It was a lot harder when each custom extension was an enum implementing an 
interface. There was no way to do a new on it.

Ralph

> On Jan 25, 2014, at 10:33 PM, Remko Popma <remko.po...@gmail.com> wrote:
> 
> Hm...
> Doesn't it become nearly impossible to protect against malicious intent, the 
> moment we make it extensible?
> 
>> On Sunday, January 26, 2014, Ralph Goers <ralph.go...@dslextreme.com> wrote:
>> A malicious app could do 
>> 
>> for (int i=0; i < 100000; ++i) {
>>   new Level(“Level” + i, 1000 + i){};
>> }
>> 
>> Sure idiots can do lots of bad things but I don’t think Levels should be 
>> quite that flexible.
>> 
>> Ralph
>> 
>>> On Jan 25, 2014, at 9:39 PM, Remko Popma <remko.po...@gmail.com> wrote:
>>> 
>>> I don't think client code can do new Level(){} as the constructor requires 
>>> String and int arguments.
>>> 
>>> By the way, I am unclear on what went wrong with the enum approach you 
>>> originally took.
>>> You said:
>>>     StdLevel isn’t a Level because it can’t extend it if it is an enum, so 
>>> I can’t initialize the levels using that.
>>> 
>>> I don't understand. StdLevel implements the Level interface, right? So what 
>>> do you mean by "it can't extend it"?
>>> 
>>> The reason I ask is that for the code generation, "real" java enums may be 
>>> easier to deal with than the extensible enum approach.
>>> 
>>> 
>>> On Sun, Jan 26, 2014 at 2:30 PM, Ralph Goers <ralph.go...@dslextreme.com> 
>>> wrote:
>>> Out of curiosity, what exactly is the benefit of declaring the class 
>>> abstract when it has a protected constructor?  It seems like all you are 
>>> accomplishing is making the instantiation syntax uglier. It also bothers me 
>>> that open code can just do a new Level(){} - which will do nothing but 
>>> cause problems.  I’m beginning to think that we should require an 
>>> annotation on the Level declaration of the extension class to avoid that.
>>> 
>>> Ralph 
>>> 
>>>> On Jan 25, 2014, at 9:13 PM, Remko Popma <remko.po...@gmail.com> wrote:
>>>> 
>>>> Ralph,
>>>> I copied Nick's code _as is_ and had no compile errors.
>>>> The class is abstract, but instances are defined in the static block as:
>>>> OFF = new Level("OFF", 0) {}; // note the {}: this creates an anonymous 
>>>> concrete subclass
>>>> 
>>>> I agree that read access needs to be synchronized as well, not just write 
>>>> access (the constructor).
>>>> I experimented with several options: 
>>>> * synchronizing on plain Object in both constructor and when accessing the 
>>>> static Map(s)
>>>> * a ReentrantReadWriteLock
>>>> * a lock-free implementation
>>>> 
>>>> I decided against ReentrantReadWriteLock as it has more overhead than 
>>>> plain synchronized access and the write access (in the constructors) is 
>>>> going to be extremely rare: not worth paying the overhead in the more 
>>>> common reads. It is also cumbersome to code.
>>>> 
>>>> The lock-free implementation uses an AtomicInteger for the ordinals, and 
>>>> an AtomicReference for the Map<String, Level>.
>>>> In the constructor, create a new Map<String, Level> instance based on the 
>>>> old copy, add the new instance, and try to call compareAndSet to replace 
>>>> the old instance with the new instance. Retry on failure.
>>>> 
>>>> Finally, simply synchronizing on the constructorLock object in the 
>>>> Level.toLevel() and Level.values() methods may be simplest. 
>>>> 
>>>> Which of the last two is best depends on how often the toLevel() and 
>>>> values() levels are called.
>>>> It turns out they are only called during reconfiguration, so no real need 
>>>> to optimize these methods.
>>>> I would argue that simple synchronization may be best in this case.
>>>> 
>>>> Remko
>>>>  
>>>> 
>>>> 
>>>> On Sun, Jan 26, 2014 at 1:49 PM, Ralph Goers <ralph.go...@dslextreme.com> 
>>>> wrote:
>>>> As I am working on this I just want to point out a number of issues with 
>>>> the code below:
>>>> 
>>>> 1. The class is abstract. The static block is doing a bunch of new Level() 
>>>> invocations which obviously generate compile errors on an abstract class.  
>>>> I had to make it be a non-abstract class.
>>>> 2. As I pointed out before there is no way to access the “standard” levels 
>>>> as an enum. I have addressed that.
>>>> 3. Although the constructor is synchronized access to the Map is not. 
>>>> Trying to get from the map while a Level is being added will result in a 
>>>> ConcurrentModificationException. I

Reply via email to