admin@glassfish.java.net

Re: HK2 / v3 Issues related to admingui pluggability infrastructure

From: Jerome Dochez <Jerome.Dochez_at_Sun.COM>
Date: Wed, 27 Feb 2008 11:39:17 -0800

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
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>
>>