admin@glassfish.java.net

Re: HK2 / v3 Issues related to admingui pluggability infrastructure

From: Ken Paulsen <Ken.Paulsen_at_Sun.COM>
Date: Wed, 27 Feb 2008 12:31:27 -0800

Ok, no problem.

Thanks!

Ken

Jerome Dochez wrote:
> yes so I think I need to provide a good way for you to import a few
> HK2 modules from the core web application which is not a module
> itself.... in the meantime, the reflection based approach is your only
> way out.
>
> jerome
>
> On Feb 26, 2008, at 11:59 PM, Ken Paulsen wrote:
>
>>
>> I have:
>>
>> @Contract ConsoleProvider <-- Each module providing GUI
>> "IntegrationPoints" must implement this as a @Service; defines the
>> URL getConfiguration() method which points to an XML file for
>> building the IntegrationPoint objects.
>>
>> @Service ConsolePluginService <-- I don't have a @Contract for this,
>> but I wanted to be able to locate this via the Habitat and have
>> ConsoleProvider[] @Injected into it... this class does the work of
>> iterating over the ConsoleProvider impls and getting all the
>> "IntegrationPoint" objects by type.
>>
>> @Configured IntegrationPoint <-- configured from XML descriptors;
>> describe where in the GUI an extension will occur; may refer to other
>> objects that need to be loaded by the same ClassLoader
>>
>> @Configured ConsoleConfig <-- Just contains IntegrationPoints.
>>
>> In the GUI code, I use the Habitat to obtain the
>> ConsolePluginService. Getting a hold of that injects the
>> ConsoleProviders from all modules. I iterate over this, using the HK2
>> parser w/ the URL from each to instantiate IntegrationPoint Objects
>> and store them by "type".
>>
>> In the GUI code, if I cast the object returned from:
>>
>> habitat.getByType(ConsolePluginService.class);
>>
>> To (ConsolePluginService), I get a ClassCastException. I believe this
>> is b/c a ConsolePluginService is created by a different classloader.
>>
>> To get around this, I'm currently return Object instead of
>> ConsolePluginService from my "getPluginService()" method. Then using
>> reflection to invoke the getIntegrationPoints(String) method on it,
>> as I was unable to cast it to its proper type.
>>
>> This is my first attempt at using HK2 concepts (@Contract/_at_Service,
>> Habitat, etc.), so please let me know if you have any suggestions on
>> how I can do things better.
>>
>> For reference, here are the files involved:
>>
>> v3/common/glassfish-api/src/main/java/org/glassfish/api/admingui/ConsoleProvider.java
>>
>> v3/admingui/plugin/src/main/java/org/glassfish/admingui/plugin/ConsolePluginService.java
>>
>> v3/admingui/plugin/src/main/java/org/glassfish/admingui/plugin/IntegrationPoint.java
>>
>> v3/admingui/plugin/src/main/java/org/glassfish/admingui/plugin/ConsoleConfig.java
>>
>>
>> And I'm accessing this from:
>>
>> v3/admingui/core/src/main/java/org/glassfish/admingui/handlers/PluginHandlers.java
>>
>>
>> Thanks!
>>
>> Ken
>>
>> Jerome Dochez wrote:
>>>
>>> On Feb 26, 2008, at 7:56 PM, Ken Paulsen wrote:
>>>
>>>>
>>>> Hi Jerome / Shing Wai,
>>>>
>>>> Thanks for providing the Habitat via the ServletContext. This is
>>>> now working for us and we're able to get the ConsolePluginService
>>>> which gives us the IntegrationPoint's that are specified in various
>>>> modules w/o doing anything funny at server startup.
>>>>
>>>> However.... since I am using multiple classloaders, I cannot cast
>>>> ConsolePluginService to ConsolePluginService within our web app
>>>> code. I am currently using reflection to invoke the method I need
>>>> on the ConsolePluginService provider to avoid the
>>>> ClassCastException. What is the preferred way to handle this? Can I
>>>> set the context classloader on the thread before I access each
>>>> object from a different classloader?
>>> so I am not sure I understand what you are trying to do... u have a
>>> ConsolePluginService interface (and implementations) which are
>>> loaded by different class loaders ? and then you need to invoke a
>>> method of that interface on different implementations ?
>>>
>>> jerome
>>>
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Ken
>>>>
>>>> Jerome Dochez wrote:
>>>>> ok for now, it's stored in your servlet context and the attribute
>>>>> name is com.sun.appserv.jsf.habitat
>>>>>
>>>>> that should get you going...
>>>>>
>>>>> jerome
>>>>>
>>>>> Ken Paulsen wrote:
>>>>>>
>>>>>> Hi Jerome,
>>>>>>
>>>>>> Hmm... I realized I can't init on startup b/c a module's
>>>>>> classloader is different than my web app's. So I get a different
>>>>>> instance. So I think I'm stuck until I have a way to Inject the
>>>>>> Habitat, or my @Service directly in my web app. Let me know if
>>>>>> you have any other ideas.
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> Ken
>>>>>>
>>>>>> Ken Paulsen wrote:
>>>>>>>
>>>>>>> Jerome Dochez wrote:
>>>>>>>>
>>>>>>>> so far, admin gui is a plain war file, right ?
>>>>>>> Yes.
>>>>>>>> looks like I need to extend @Startup service to have an
>>>>>>>> Application scope. Applications could optionally implement it
>>>>>>>> and that would be called when applications are started... that
>>>>>>>> would be enough right ?
>>>>>>> Yes, that sounds like it would work well. Any idea on how much
>>>>>>> effort that will take / when it will be available? In the mean
>>>>>>> time, I think I'll initialize on server startup so I can keep
>>>>>>> working.
>>>>>>>
>>>>>>> Thanks!
>>>>>>>
>>>>>>> Ken
>>>>>>>> jerome
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> On Feb 25, 2008, at 11:39 AM, Ken Paulsen wrote:
>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Jerome Dochez wrote:
>>>>>>>>>>
>>>>>>>>>> On Feb 25, 2008, at 10:43 AM, Ken Paulsen wrote:
>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Hi Jerome,
>>>>>>>>>>>
>>>>>>>>>>> Thanks for the quick reply.
>>>>>>>>>>>
>>>>>>>>>>> With plain apt, my annotations work. In the meantime, I was
>>>>>>>>>>> able to add extra checks in my annotation processors to keep
>>>>>>>>>>> them from processing annotation they aren't meant to
>>>>>>>>>>> process. In looking into this issue, it seems that HK2's use
>>>>>>>>>>> of CompositeAnnotationProcessors may be the
>>>>>>>>>>
>>>>>>>>>>> cause. In any case, I'm no longer blocked.
>>>>>>>>>> ok, I will look into that when I have some time...
>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> As for the configuration info... I would like to have
>>>>>>>>>>> @Configured objects populated from XML files which describe
>>>>>>>>>>> gui integration points. Here's a small example of one of the
>>>>>>>>>>> XML files:
>>>>>>>>>>>
>>>>>>>>>>> <?xml version="1.0" encoding="UTF-8"?>
>>>>>>>>>>>
>>>>>>>>>>> <console-config id="myIntegration">
>>>>>>>>>>> <integration-point id="myTab" type="webApplicationTab"
>>>>>>>>>>> priority="22" parentId="webApplicationTab" uri="/myTab.jsf" />
>>>>>>>>>>> <integration-point id="jbiRootNode" type="tree"
>>>>>>>>>>> priority="840" parentId="rootNode" uri="/myTreeNode.jsf"
>>>>>>>>>>> content="test2"/>
>>>>>>>>>>> </console-config>
>>>>>>>>>>>
>>>>>>>>>>> I have this working... as long as the XML file is in the
>>>>>>>>>>> same module as my Service which parses them (using HK2's
>>>>>>>>>>> ConfigParser). I need a way to search all modules for these
>>>>>>>>>>> files. I will also need a way to read resources (images,
>>>>>>>>>>> other files text files, classes, etc.) from the same modules
>>>>>>>>>>> which contain these files.
>>>>>>>>>>
>>>>>>>>>> looks like you need to define a Contract for that, something
>>>>>>>>>> like
>>>>>>>>>> @Contract
>>>>>>>>>> public interface GuiProvider {
>>>>>>>>>> /**
>>>>>>>>>> * @Return a URL for its configuration (xml file).
>>>>>>>>>> URL getConfiguration();
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> then each module implements this GuiProvider with their own
>>>>>>>>>> XML configuration.
>>>>>>>>>>
>>>>>>>>>> when you need them you can just look up for all GuiProvider
>>>>>>>>>> implementations : @Inject
>>>>>>>>>> GuiProvider[] providers
>>>>>>>>>>
>>>>>>>>>> .... later in the code ...
>>>>>>>>>>
>>>>>>>>>> for (GuidProvider provider : providers) {
>>>>>>>>>> ConfigParser.parse(... provider.getConfiguration() ...);
>>>>>>>>>>
>>>>>>>>>> for accessing resources, you should use the implementation
>>>>>>>>>> class loader so for instance...
>>>>>>>>>>
>>>>>>>>>> for (GuiProvider provider : providers) {
>>>>>>>>>>
>>>>>>>>>> provider.getClass().getClassLoader().loadResource("META-INF/default-icon.gif);
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> }
>>>>>>>>>>
>>>>>>>>>> does that answer your question ?
>>>>>>>>> Yes. I was hoping to avoid needing to require people to create
>>>>>>>>> a Java class, but it's an easy step to do and will make things
>>>>>>>>> "just work" better. I'll do this.
>>>>>>>> this is the easiest for now, we might want to revisit this once
>>>>>>>> we have switched to OSGi
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> New question: How can I get the default Habitat? I tried
>>>>>>>>>>> "Globals.getGlobals().getDefaultHabitat()", but getGlobals()
>>>>>>>>>>> returned (null). To back up, I am simply trying to get a
>>>>>>>>>>> @Service implementation via Java code. I was trying via
>>>>>>>>>>> habitat.getByType(...), but can't seem to get a valid Habitat.
>>>>>>>>>> so you need to do this lookup in code that never had access
>>>>>>>>>> to injection ? can't you get the habitat injected when you
>>>>>>>>>> initialize and save it in your runtime for this kind of use
>>>>>>>>>> later on your code paths ?
>>>>>>>>> Ok, I can do that... if you can tell me how I should be
>>>>>>>>> initializing. I can make a @Service which implements Populator
>>>>>>>>> and store it... but I don't think I should be doing this on
>>>>>>>>> Server Startup.
>>>>>>>> no that would be wrong...
>>>>>>>>> Is there another interface or technique I can use to only
>>>>>>>>> initialize this when the Admin GUI is accessed for the first
>>>>>>>>> time?
>>>>>>>> so far, admin gui is a plain war file, right ?
>>>>>>>>
>>>>>>>> looks like I need to extend @Startup service to have an
>>>>>>>> Application scope. Applications could optionally implement it
>>>>>>>> and that would be called when applications are started... that
>>>>>>>> would be enough right ?
>>>>>>>>
>>>>>>>> jerome
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Thanks!!
>>>>>>>>>
>>>>>>>>> Ken
>>>>>>>>>>
>>>>>>>>>> Jerome
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Thanks!
>>>>>>>>>>>
>>>>>>>>>>> Ken
>>>>>>>>>>>
>>>>>>>>>>> Jerome Dochez wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On Feb 24, 2008, at 8:13 PM, Ken Paulsen wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Hi Kohsuke / Jerome,
>>>>>>>>>>>>>
>>>>>>>>>>>>> I have attempted to implement the admin gui pluggability
>>>>>>>>>>>>> code and have run into some issues and questions. Here
>>>>>>>>>>>>> they are:
>>>>>>>>>>>>>
>>>>>>>>>>>>> * When creating a @Configured element with an
>>>>>>>>>>>>> @Attribute(required=true), the "required=true" does not
>>>>>>>>>>>>> seem to do anything. I noticed the generated
>>>>>>>>>>>>> ObjectNameInjector.java file did not have any check in it
>>>>>>>>>>>>> for (null). (not critical, but doesn't validate the data)
>>>>>>>>>>>>>
>>>>>>>>>>>> ok I will let Kohsuke fix that later...
>>>>>>>>>>>>>
>>>>>>>>>>>>> *
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> * In the admin-gui module when compiling w/ JSFTemplating's
>>>>>>>>>>>>> @annotations, it does a couple strange things (*this is
>>>>>>>>>>>>> blocking me*):
>>>>>>>>>>>>>
>>>>>>>>>>>>> 1) It generates the FormatDefinition.map &
>>>>>>>>>>>>> UIComponentFactory.map files when these do not exist when
>>>>>>>>>>>>> compiling as we did in v2 (ant).
>>>>>>>>>>>>> 2) It throws a NPE when an HK2 annotation is present w/
>>>>>>>>>>>>> JSFTemplating anntations in the same build:
>>>>>>>>>>>>>
>>>>>>>>>>>>> java.lang.NullPointerException
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.jsftemplating.annotation.HandlerAP.process(HandlerAP.java:121)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.mirror.apt.AnnotationProcessors$CompositeAnnotationProcessor.process(AnnotationProcessors.java:60)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.mirror.apt.AnnotationProcessors$CompositeAnnotationProcessor.process(AnnotationProcessors.java:60)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.mirror.apt.AnnotationProcessors$CompositeAnnotationProcessor.process(AnnotationProcessors.java:60)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at com.sun.tools.apt.comp.Apt.main(Apt.java:454)
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.tools.apt.main.JavaCompiler.compile(JavaCompiler.java:258)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at com.sun.tools.apt.main.Main.compile(Main.java:1102)
>>>>>>>>>>>>> at com.sun.tools.apt.main.Main.compile(Main.java:964)
>>>>>>>>>>>>> at com.sun.tools.apt.Main.processing(Main.java:95)
>>>>>>>>>>>>> at com.sun.tools.apt.Main.process(Main.java:85)
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.enterprise.module.maven.HK2CompileMojo$1.compileInProcess(HK2CompileMojo.java:87)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.enterprise.module.maven.AptCompiler.compile(AptCompiler.java:67)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.plugin.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:485)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.enterprise.module.maven.CompilerMojo.execute(CompilerMojo.java:113)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> com.sun.enterprise.module.maven.HK2CompileMojo.execute(HK2CompileMojo.java:101)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:443)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:539)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLifecycle(DefaultLifecycleExecutor.java:480)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:459)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:311)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:278)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:143)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:334)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.DefaultMaven.execute(DefaultMaven.java:125)
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.apache.maven.cli.MavenCli.main(MavenCli.java:280)
>>>>>>>>>>>>> at
>>>>>>>>>>>>> sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>>>>>>>>>>>> at
>>>>>>>>>>>>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at java.lang.reflect.Method.invoke(Method.java:597)
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)
>>>>>>>>>>>>>
>>>>>>>>>>>>> at
>>>>>>>>>>>>> org.codehaus.classworlds.Launcher.main(Launcher.java:375)
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> I have 3 different Annotation processor factories. In each
>>>>>>>>>>>>> of them I return the supported types, which I believe
>>>>>>>>>>>>> should limit the annotations which are processed by the
>>>>>>>>>>>>> AnnotationProcessor created by the factory. However, based
>>>>>>>>>>>>> on the above errors, and tests that I've done, I think they
>>>>>>>>>>>>> are getting called for more than that. For example, my
>>>>>>>>>>>>> FormatDefinitionAPFactory is getting called for my @Handler
>>>>>>>>>>>>> annotations... this shouldn't happen. Perhaps the
>>>>>>>>>>>>> HK2Compiler is doing things differently than the normal apt
>>>>>>>>>>>>> compiler?
>>>>>>>>>>>>>
>>>>>>>>>>>> have you tried to just use the plain APT invocation from
>>>>>>>>>>>> the command line ? does your processors also get called
>>>>>>>>>>>> with HK2 annotations ? I don't remember doing anything
>>>>>>>>>>>> special in the APT invocation from maven...
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> * I need to find out how I should be finding configuration
>>>>>>>>>>>>> information for the admin console plugin data. There is
>>>>>>>>>>>>> no Java file (currently) which I can annotate to provide
>>>>>>>>>>>>> this. I am currently using @Configured Pojo's for
>>>>>>>>>>>>> storing this information... so I need a way to find these
>>>>>>>>>>>>> XML files, or an alternative approach.
>>>>>>>>>>>>>
>>>>>>>>>>>> which configuration data are u trying to access ?
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>
>>>>>>>>>>>>> Ken
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>
>>>
>