Adam,

You I must have a different definition of robust. Two of the MANY examples that illustrate my point is as follows:

1. There is no error checking on disableConfiguratorServices method and, the implementation as it stand now, could force us to break our contract with the configurators. Furthermore, it's not always obvious that something wrong was done. For instance, the following code will not generate an error:

FacesContectFactory.getFacesContext(context, request, response, lifecycle);
...
Configurator.disableConfiguratorServices();

This will not generate an error yet cleanup (endRequest) will not occur even though beginRequest WAS called (when the FacesContextFactory was created OR when the filter is run). getExternalContext MAY or MAY NOT be wrapped depending on whether or not an external context was retrieved before the disable. The basically leaves the status of externalContext in an unknown state and will not execute the end Request. You eliminated the "reflection" in my latest patch by getting rid of this check. In a public "rhobust" API, this really needs to be enforced. It USED to call an IllegalStateException so it didn't necessarily have to be caught because it should be fairly obvious at the time someone writes their code.

2. You got rid of reflection in the public Configurator class by using Trinidad's Service Loader. This class not ONLY uses reflection, but it also reads a bunch of files and returns an "array" of initialized services. Do we really need to open some file objects and initialize an extra array for no reason? Now it's an interesting idea to be able to replace the global configurator, but first off that wasn't a requirement that I was coding for and second off, we cannot guarantee the "order" that the services files are loaded in. Again this leaves us in an unknown state if we are trying to override the default functionality and is simply using a sledge hammer to drive a nail if we aren't.

You were able to eliminate a lot of the casting by not exposing the is initialized method on the global configurator by moving the initialization code inside of "getInstance" method. I kept this separate so that I could adjust to JSR-301 as I need to. Butt the API is now locked in to perform initialization at that stage. This is something that very well could become a problem. And I haven't even taken a look at how you handled the isInRequest functionality that I need to maintain the proper flexibility in the portal case.

Still, I really don't have time to argue these points. I'll just have to generate Jira tickets as problems come up and we'll have to change the API's if we need to change them. All I really have to say about the subject is allowing the GlobalConfigurator implementation handles all these issues for free. And using my latest checkins handles most of them, just not as cleanly. Certainly. though, a lot more cleanly then using the "Service Loader".

You said that you didn't know if these changes worked in a portal environment, and I'm not real sure I can confirm that within the next week or so. But checking in changes to a "portal compatibility" branch without being able to check them in a Proof of Concept (POC) is really damaging to the project being that Portal compatibility is what this project is all about. I was able to test my stuff as a POC using the Oracle Portal and Bridge, and I'm also aware of the changes that need to be made in the MyFaces Bridge to support these cases. Many of these issues ARE going to be addressed in JSR-301 but my hope it to have the myfaces bridge up to par before that time.

My final, and I mean final, comment on this is that it is important to me to have error checking on disableConfiguratorServices. That's from a robust API perspective. From a Portal standpoint, it is far more important for me to have control over the initialization logic and to error out of getInstance when an instance is not available (or return null, I don't care which) then it is for me to have an exposed "getInstance()" in the API and for the thing to return a dummy configurator. Exposing the getInstance made sense when we had the ability to tack additional non-static API's onto the GlobalConfigurator. Since we don't, I can't see ANY reason why someone would need this API outside of Trinidad. The object is simply "not useful" outside of this codebase anymore. Plus it keeps us flexible to add an API later if we need one whereas this current implementation LOCKS us in to providing a plain run-of-the-mill configurator. Lastly, for GOD sake, don't use the service loading system to load this class. The Service loading system is great for making extensions to Trinidad, but it has limitations which stem from the fact that order within these services is not guaranteed. For now I say we simply have the GlobalConfiguratorImpl (in the Impl package) be referenced directly if we need to, and if we have the need to add additional globalConfigurators in the future, we can come up with an API that makes sense. This one makes no sense at all. Essentially I outlined for you the things in my last checkin. You're latest checkin' will lock us into unwanted implementations, implementations that make NO sense what so ever, and implementations that are not robust. As I stated before, though, I don't really have time to argue with you anymore. I have some other projects that I need to work on at the moment. So if you're happy with the API, call a vote and let's get this moved in so I can move forward and we can hopefully have trinidad working inside of a MyFaces Portal environment sometime this century.

Scott O'Bryan

Adam Winer wrote:
On 12/21/06, Scott O'Bryan <[EMAIL PROTECTED]> wrote:

Adam,

Well, you basically implemented one of the solutions I said I didn't
like earlier, but oh well.  And there are a number of places you need to
cast.  So the concerns are still valid.


Well, I don't get that claim, as I didn't add a single cast in my
patch at all, and removed references to the impl class, so I can't imagine
how I've made things worse.  And I didn't really see any casts that were
already there.

The one question I do have is why does getInstance take in an
ExternalContext?  I'm assuming it's because your executing the init
inside of the getInstance object and I'm not sure this is the correct
place for this.  My hope in all of this was to be able to explicitly
handle initialization of this object.  Plus, nine times out of ten, the
ExternalContext object is ignored in the call to this method.


A create + initialize construct is more robust than a create-and-hope-
it-gets-initialized-by-someone-else construct.

-- Adam



Either way, don't see as I really have the time to argue.  So is it
acceptable to everyone?

Also, there is no


Adam Winer wrote:
> Scott,
>
> OK, well, I just went ahead and implemented what I was trying
> to say, to see if I'd run into the problems you're describing.  I
> didn't...
> (It's possible I've broken something in portlet land - I only tested
> the changes in a servlet environment.)
>
> On 12/21/06, Scott O'Bryan <[EMAIL PROTECTED]> wrote:
>> Adding getInstance() to the configurator will either force us to cast
in
>> a bunch of different places
>
> No, it doesn't.  No casts were required at all, much
> less in a bunch of places, and most of the code now
> doesn't even have references to the impl class at all.
>
>> or to expose the GlobalConfiguratorImpl's
>> api to the rest of the world (which I don't want to do because they are
>> applicable ONLY to global configurator.  And it won't lock us into an
>> API we may have to expand later.
>>
>> As for simply putting the Boolean on the request map, either I'll have
>> to make a protected constant on the Configurator interface (which has
no
>> bearing on any of the configurators except the global configurator so
it
>> shouldn't go into the ancestor) or I add a porotected (isDisabled)
>> method (which, again, is only applicable to the GlobalConfiguratorImpl
>> and therfore shouldn't do into it's Ancestor).
>
> See the code checked in, which does not suffer these probems.
>
>> I've never been one to include a feature into an interface or a class
>> that is applicable in only one instance of that class because it
>> violated basics OO design principals. The only other option I see here >> is to define the constant used to store the boolean in BOTH classes and >> hope they remain in sync, but I've never been a big fan of that either.
>
> Again, see the code checked in.
>
> -- Adam
>




Reply via email to