Menu

Custom ResourceReference implementation

2011-12-14
2012-09-09
  • Vasanth Kamatgi

    Vasanth Kamatgi - 2011-12-14

    I have implemented a custom ResourceReference Implementation
    (DBResourceReference) and am looking for a painless way of configuring it.

    I have added

        <resource-facade>
            <resource-reference scheme="dbContent" class="DBContentResourceReference"/>
        </resource-facade>
    

    However, packaging this class in jar file and placing it in runtime/lib isn't
    working. Unless I create a new war that packages this jar file also in its
    WEB-INF/lib, this ResourceReference isnt getting loaded. So, eachtime there is
    a change in the implementation of DBResourceReference, I need to first package
    it in jar and then in war, which is a little painful. Moreover, in my opinion
    it beats the purpose of ability to deploy one time and continuously just
    develop - meaning there is a clear separation of moqui framework and custom
    application libraries.

    This behaviour is because of

                Class rrClass = this.getClass().getClassLoader().loadClass(rrNode."@class")
    

    in ResourceFacadeImpl.groovy. This allows only war file class loader to be
    used for loading resource reference implementations, which I think is quite
    limiting. Instead if we can use a classloader which is a child of the war
    classloader and has the list of jars and classes of each component, then this
    limitation is eliminated.

     
  • Vasanth Kamatgi

    Vasanth Kamatgi - 2011-12-22

    I guess this choice could be a well-thought out decision. I am trying to
    understand the rationale behind it, but was not able to find more reasons than
    probably security concerns. If the thought process behind this choice is
    shared, it would be very helpful.

    Thanks

     
  • David E. Jones

    David E. Jones - 2011-12-22

    Thanks for commenting on this Vasanth. This was an oversight and related to
    another bug recently fixed related to classpath resources accessed through the
    ResourceFacade.

    This is fixed in the trunk in commit 909a67d.

     
  • Vasanth Kamatgi

    Vasanth Kamatgi - 2011-12-25

    I downloaded the latest version and verified it to be 909a67d. I ran my test
    app against the war built with this version and am still seeing the same
    problem cropping up. On investigating a little bit, I noticed that, in
    ExecutionContextImpl, initClassLoader() is being called after
    ResourceFacadeImpl is created. I am guessing, this is the reason why
    ResourceFacadeImpl throws a ClassNotFoundException. To confirm my inference, I
    refactored initClassLoader and extracted a method that adds lib and classes to
    the classloader. I invoked this method in ExecutionContextImpl just before
    instantiating any *FacadeImpl. With this change, my custom
    ResourceReferenceImpl is getting loaded without requiring to package in a jar
    and then in the war.

    As I do not understand fully, the consequences of this change, but suspect it
    to be an unintended bug, I am posting my finding.

    Thanks

     
  • David E. Jones

    David E. Jones - 2011-12-25

    Thanks for testing this Vasanth. I looked into it a little more and I don't
    see any reason to delay the ClassLoader init. I originally put it after the
    init of the ResourceFacade, but they can (and as you point out should) by
    initialized earlier.

    Currently they need to be initialized after components are loaded, though for
    a few reasons components cannot currently be on the classpath anyway.

    This should be fixed as of commit a834fec.

     
  • Vasanth Kamatgi

    Vasanth Kamatgi - 2011-12-26

    Now I get a NullPointerException.

    init of ClassLoader uses ResourceFacade (Line No.281)

    ResourceReference classesRr = this.resourceFacade.getLocationReference(componentEntry.value + "/classes")
    

    Due to this, startup fails. I think, this part of Classloader init should be
    called only after ResourceFacadeImpl is init_ed_.

    Thanks

     
  • David E. Jones

    David E. Jones - 2011-12-26

    What is the test case you are using... this isn't happening for me locally.

    I see from that code that what you're saying is correct, but I'm wondering
    what sort of component configuration you're using and such that causes this to
    happen.

     
  • David E. Jones

    David E. Jones - 2011-12-26

    Nevermind... it does happen with no changes or add-ons...

     
  • David E. Jones

    David E. Jones - 2011-12-26

    I spent a few more minutes testing and working on this, and basically the
    ClassLoader setup and ResourceFacade init had to be split up.

    As of commit 1d41e91 the code should be much more flexible, and OOTB
    everything loads and runs fine again.

    The one constraint is that I couldn't figure out a way around is to allow a
    component's location to depend on a ResourceReference implementation that is
    in another component. Otherwise, ResourceReference, ScriptRunner and
    TemplateRenderer implementations can be in components.

     
  • Vasanth Kamatgi

    Vasanth Kamatgi - 2011-12-26

    It works now.

    Also, I think the constraint that

    a component's location should not depend on a Resource Reference
    implementation in another component

    is an acceptable constraint. In my opinion, documenting this limitation and
    moving on, should be good enough for now vis-a-vis making class loading more
    complex.

     

Log in to post a comment.