You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@uima.apache.org by Mario Gazzo <ma...@gmail.com> on 2015/05/22 16:59:23 UTC

Injecting nested resources using UIMA fit

I have some trouble with initialising some nested resource with UIMA fit. I have followed the approach described in the section “Resources implementing SharedResourceObject”. I just have a resource B that uses resource A and a collection reader and a flow control that use both A and B but I get "mandatory resource A not set on resource B” illegal state exception. I use the @ExternalResource annotations to get them injected and I used ExternalResourceFactory.bindExternalResource with A and B on the collection reader and flow control descriptions when creating my aggregate. It works if B is not dependent on A but as soon I add the dependency then it breaks. I also tried to explicitly use ExternalResourceFactory.bindExternalResource on A to B but that caused null pointer exception in ExternalResourceFactory when trying to bind to the collection reader right after.

I would appreciate any ideas about what I might be doing wrong.

Cheers
Mario

Re: Injecting nested resources using UIMA fit

Posted by Mario Gazzo <ma...@gmail.com>.
Thanks Richard,

No hurry, I have a temporary workaround for it but I probably need to look into this soon. I’ll keep you posted when I dig up some new findings.

Cheers
Mario

> On 24 Jun 2015, at 09:29 , Richard Eckart de Castilho <re...@apache.org> wrote:
> 
> Hi Mario,
> 
> I'm not sure if the resource injection has a proper two-phase initialization
> (first instantiation, then injection) or if it behaves more like a constructor
> injection (injection during instantiation). I think it is the latter which
> requires that there is no circular injection - but that needs to be checked.
> I may not be able to get my hands into this in the next few days, so if have
> a need and want to dig into it more, feel free.
> 
> Cheers,
> 
> -- Richard
> 
> On 19.06.2015, at 22:24, Mario Gazzo <ma...@gmail.com> wrote:
> 
>> Hi Richard,
>> 
>> Seems something still spooky with my nested resources. This time I added an additional resource, which depends on the same shared resource as another. I now have two different resources dependent on the same external resource but during initialisation I get the error shown below. I can use both resources independently of each other but just not together. I have been able to replicate it by extending the earlier simple example (see further down).
>> 
>> You will notice in the example that I bind every resource to every description specified even though there is no declared dependency. Reason is because our actual application has a small DSL that aggregates the descriptions and then tries to bind resources on all possible descriptions just before execution. However, I just did a naive approach where I bind every resource to every possible description that was added but I didn’t do code that first inspects whether a description has actually declared the dependency before attempting to bind. Yes, its inefficient for a very large amount of resources but we don’t have that. My naive assumption was that the UIMAfit binding process would figure this out way better than I could myself and I just sticked with this since it worked fine until now and it was simple to program. I don’t know whether this actually is the direct cause of the problem or whether my use just triggered a bug. It works if I don’t do these superfluous bindings. If this use case cannot be supported then I would like to know what would alternatively be the simplest way to make these inspections on the descriptors before making a binding attempt?
>> 
>> Thanks a lot for your help.
>> 
>> Cheers
>> Mario
> 


Re: Injecting nested resources using UIMA fit

Posted by Richard Eckart de Castilho <re...@apache.org>.
Hi Mario,

I'm not sure if the resource injection has a proper two-phase initialization
(first instantiation, then injection) or if it behaves more like a constructor
injection (injection during instantiation). I think it is the latter which
requires that there is no circular injection - but that needs to be checked.
I may not be able to get my hands into this in the next few days, so if have
a need and want to dig into it more, feel free.

Cheers,

-- Richard

On 19.06.2015, at 22:24, Mario Gazzo <ma...@gmail.com> wrote:

> Hi Richard,
> 
> Seems something still spooky with my nested resources. This time I added an additional resource, which depends on the same shared resource as another. I now have two different resources dependent on the same external resource but during initialisation I get the error shown below. I can use both resources independently of each other but just not together. I have been able to replicate it by extending the earlier simple example (see further down).
> 
> You will notice in the example that I bind every resource to every description specified even though there is no declared dependency. Reason is because our actual application has a small DSL that aggregates the descriptions and then tries to bind resources on all possible descriptions just before execution. However, I just did a naive approach where I bind every resource to every possible description that was added but I didn’t do code that first inspects whether a description has actually declared the dependency before attempting to bind. Yes, its inefficient for a very large amount of resources but we don’t have that. My naive assumption was that the UIMAfit binding process would figure this out way better than I could myself and I just sticked with this since it worked fine until now and it was simple to program. I don’t know whether this actually is the direct cause of the problem or whether my use just triggered a bug. It works if I don’t do these superfluous bindings. If this use case cannot be supported then I would like to know what would alternatively be the simplest way to make these inspections on the descriptors before making a binding attempt?
> 
> Thanks a lot for your help.
> 
> Cheers
> Mario


Re: Injecting nested resources using UIMA fit

Posted by Mario Gazzo <ma...@gmail.com>.
Hi Richard,

Seems something still spooky with my nested resources. This time I added an additional resource, which depends on the same shared resource as another. I now have two different resources dependent on the same external resource but during initialisation I get the error shown below. I can use both resources independently of each other but just not together. I have been able to replicate it by extending the earlier simple example (see further down).

You will notice in the example that I bind every resource to every description specified even though there is no declared dependency. Reason is because our actual application has a small DSL that aggregates the descriptions and then tries to bind resources on all possible descriptions just before execution. However, I just did a naive approach where I bind every resource to every possible description that was added but I didn’t do code that first inspects whether a description has actually declared the dependency before attempting to bind. Yes, its inefficient for a very large amount of resources but we don’t have that. My naive assumption was that the UIMAfit binding process would figure this out way better than I could myself and I just sticked with this since it worked fine until now and it was simple to program. I don’t know whether this actually is the direct cause of the problem or whether my use just triggered a bug. It works if I don’t do these superfluous bindings. If this use case cannot be supported then I would like to know what would alternatively be the simplest way to make these inspections on the descriptors before making a binding attempt?

Thanks a lot for your help.

Cheers
Mario

///////////////////////// EXAMPLE OUTPUT ///////////////////////////////////

Resource A loaded
Resource B loaded
Resource C loaded
Resource C initialized. Now calling resource A
Hello resource A
Exception in thread "main" org.apache.uima.resource.ResourceInitializationException
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:128)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.initialize(ExternalResourceInitializer.java:72)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.initializeNestedResources(ExternalResourceInitializer.java:199)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:98)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:94)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.initialize(ExternalResourceInitializer.java:72)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.initializeNestedResources(ExternalResourceInitializer.java:199)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:98)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:94)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:94)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:94)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:94)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.configure(ExternalResourceInitializer.java:94)
	at org.apache.uima.fit.component.initialize.ExternalResourceInitializer.initialize(ExternalResourceInitializer.java:72)
	at org.apache.uima.fit.component.JCasCollectionReader_ImplBase.initialize(JCasCollectionReader_ImplBase.java:55)
	at org.apache.uima.collection.CollectionReader_ImplBase.initialize(CollectionReader_ImplBase.java:70)
	at org.apache.uima.impl.CollectionReaderFactory_impl.produceResource(CollectionReaderFactory_impl.java:103)
	at org.apache.uima.impl.CompositeResourceFactory_impl.produceResource(CompositeResourceFactory_impl.java:62)
	at org.apache.uima.UIMAFramework.produceResource(UIMAFramework.java:279)
	at org.apache.uima.UIMAFramework.produceResource(UIMAFramework.java:331)
	at org.apache.uima.UIMAFramework.produceCollectionReader(UIMAFramework.java:812)
	at org.apache.uima.fit.pipeline.SimplePipeline.runPipeline(SimplePipeline.java:134)
	at NestedResourceExample.main(NestedResourceExample.java:291)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.lang.IllegalStateException: Mandatory resource [NestedResourceExample$ResourceB-1##Resource-A] is not set on [class NestedResourceExample$ResourceB]
	... 28 more


///////////////////////// EXAMPLE CODE ///////////////////////////////////

import org.apache.uima.UIMAException;
import org.apache.uima.analysis_engine.AnalysisEngineDescription;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.analysis_engine.metadata.FixedFlow;
import org.apache.uima.analysis_engine.metadata.FlowConstraints;
import org.apache.uima.cas.AbstractCas;
import org.apache.uima.cas.CAS;
import org.apache.uima.collection.CollectionException;
import org.apache.uima.collection.CollectionReaderDescription;
import org.apache.uima.fit.component.*;
import org.apache.uima.fit.component.JCasFlowController_ImplBase;
import org.apache.uima.fit.component.initialize.ConfigurationParameterInitializer;
import org.apache.uima.fit.descriptor.ConfigurationParameter;
import org.apache.uima.fit.descriptor.ExternalResource;
import org.apache.uima.fit.factory.*;
import org.apache.uima.fit.pipeline.SimplePipeline;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.flow.*;
import org.apache.uima.jcas.JCas;
import org.apache.uima.resource.DataResource;
import org.apache.uima.resource.ExternalResourceDescription;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.SharedResourceObject;
import org.apache.uima.util.Progress;
import org.apache.uima.util.ProgressImpl;

import java.io.IOException;
import java.util.ArrayList;

import static org.apache.uima.fit.factory.ExternalResourceFactory.bindExternalResource;

/**
 * Micro example illustrating a problem when initializing nested resources
 */

public class NestedResourceExample {

    public static class ResourceA implements SharedResourceObject, ExternalResourceAware {

        public static final String RESOURCE_A_KEY = "Resource-A";

        @ConfigurationParameter(name= ExternalResourceFactory.PARAM_RESOURCE_NAME)
        private String resourceName;

        @Override
        public String getResourceName() {
            return resourceName;
        }

        @Override
        public void afterResourcesInitialized() throws ResourceInitializationException {
            System.out.println("Resource A initialized");
        }

        @Override
        public void load(DataResource aData) throws ResourceInitializationException {
            ConfigurationParameterInitializer.initialize(this, aData);
            System.out.println("Resource A loaded");
        }

        public void helloA() {
            System.out.println("Hello resource A");
        }
    }

    public static class ResourceB implements SharedResourceObject, ExternalResourceAware {

        public static final String RESOURCE_B_KEY = "Resource-B";

        @ExternalResource(key = ResourceA.RESOURCE_A_KEY)
        private ResourceA resourceA;

        @ConfigurationParameter(name= ExternalResourceFactory.PARAM_RESOURCE_NAME)
        private String resourceName;

        @Override
        public String getResourceName() {
            return resourceName;
        }

        @Override
        public void afterResourcesInitialized() throws ResourceInitializationException {
            System.out.println("Resource B initialized. Now calling resource A");
            resourceA.helloA();
        }

        @Override
        public void load(DataResource aData) throws ResourceInitializationException {
            ConfigurationParameterInitializer.initialize(this, aData);
            System.out.println("Resource B loaded");
        }

        public void helloB() {
            System.out.println("Hello resource B");
        }
    }

    public static class ResourceC implements SharedResourceObject, ExternalResourceAware {

        public static final String RESOURCE_C_KEY = "Resource-C";

        @ExternalResource(key = ResourceA.RESOURCE_A_KEY)
        private ResourceA resourceA;

        @ConfigurationParameter(name= ExternalResourceFactory.PARAM_RESOURCE_NAME)
        private String resourceName;

        @Override
        public String getResourceName() {
            return resourceName;
        }

        @Override
        public void afterResourcesInitialized() throws ResourceInitializationException {
            System.out.println("Resource C initialized. Now calling resource A");
            resourceA.helloA();
        }

        @Override
        public void load(DataResource aData) throws ResourceInitializationException {
            ConfigurationParameterInitializer.initialize(this, aData);
            System.out.println("Resource C loaded");
        }

        public void helloC() {
            System.out.println("Hello resource C");
        }
    }

    public static class FlowController extends JCasFlowController_ImplBase {

        @ExternalResource(key = ResourceA.RESOURCE_A_KEY)
        private ResourceA resourceA;

        @ExternalResource(key = ResourceB.RESOURCE_B_KEY)
        private ResourceB resourceB;

        private ArrayList<Step> pipeline = new ArrayList<>();

        @Override
        public void initialize(FlowControllerContext context) throws ResourceInitializationException {
            super.initialize(context);

            FlowConstraints flowConstraints = context.getAggregateMetadata().getFlowConstraints();
            String[] sequence = ((FixedFlow) flowConstraints).getFixedFlow();
            for( String key : sequence ) {
                pipeline.add(new SimpleStep(key));
            }

        }

        @Override
        public Flow computeFlow(JCas aJCas) throws AnalysisEngineProcessException {
            return new SimpleFlow(aJCas);
        }

        public class SimpleFlow implements Flow {

            private final JCas jCas;

            private int step = 0;

            public SimpleFlow(JCas jCas) {
                this.jCas = jCas;
            }

            @Override
            public Step next() throws AnalysisEngineProcessException {
                if(step < pipeline.size()) {
                    return pipeline.get(step++);
                } else {
                    resourceA.helloA();
                    resourceB.helloB();
                    return new FinalStep();
                }
            }

            @Override
            public Flow newCasProduced(AbstractCas newCas, String producedBy) throws AnalysisEngineProcessException {
                return null;
            }

            @Override
            public boolean continueOnFailure(String failedAeKey, Exception failure) {
                return false;
            }

            @Override
            public void aborted() {
                System.out.println("Simple flow aborted");
            }
        }
    }

    public static class SimpleCollectionReader extends JCasCollectionReader_ImplBase {

        @ExternalResource(key = ResourceA.RESOURCE_A_KEY)
        private ResourceA resourceA;

        @ExternalResource(key = ResourceB.RESOURCE_B_KEY)
        private ResourceB resourceB;

        private int completed = 0;

        @Override
        public void getNext(JCas jCas) throws IOException, CollectionException {
            try {
                JCas view = ViewCreatorAnnotator.createViewSafely(jCas, CAS.NAME_DEFAULT_SOFA);
                view.setDocumentText("This is some text "+completed++);
                resourceA.helloA();
                resourceB.helloB();
            } catch (AnalysisEngineProcessException e) {
                throw new CollectionException(e);
            }
        }

        @Override
        public boolean hasNext() throws IOException, CollectionException {
            return completed < 1;
        }

        @Override
        public Progress[] getProgress() {
            return new Progress[] { new ProgressImpl(0, 1, Progress.ENTITIES) };
        }
    }

    public static class SimpleAnalyser extends JCasAnnotator_ImplBase {

        @ExternalResource(key = ResourceB.RESOURCE_B_KEY)
        private ResourceB resourceB;

        @Override
        public void process(JCas jCas) throws AnalysisEngineProcessException {
            JCas view = JCasUtil.getView(jCas, CAS.NAME_DEFAULT_SOFA, true);
            System.out.println(view.getDocumentText());
            resourceB.helloB();
        }
    }

    public static class AnotherSimpleAnalyser extends JCasAnnotator_ImplBase {

        @ExternalResource(key = ResourceC.RESOURCE_C_KEY)
        private ResourceC resourceC;

        @Override
        public void process(JCas jCas) throws AnalysisEngineProcessException {
            System.out.println("One more analysis");
            resourceC.helloC();
        }
    }

    public static void main(String[] args) throws UIMAException, IOException {

        AggregateBuilder builder = new AggregateBuilder();

        ExternalResourceDescription resourceA = ExternalResourceFactory.createExternalResourceDescription(ResourceA.class,"http://resource.org/a");
        ExternalResourceDescription resourceB = ExternalResourceFactory.createExternalResourceDescription(ResourceB.class,"http://resource.org/b");
        ExternalResourceDescription resourceC = ExternalResourceFactory.createExternalResourceDescription(ResourceC.class,"http://resource.org/c");

        CollectionReaderDescription reader = CollectionReaderFactory.createReaderDescription(SimpleCollectionReader.class);
        FlowControllerDescription flow = FlowControllerFactory.createFlowControllerDescription(FlowController.class);
        AnalysisEngineDescription ae1 = AnalysisEngineFactory.createEngineDescription(SimpleAnalyser.class);
        AnalysisEngineDescription ae2 = AnalysisEngineFactory.createEngineDescription(AnotherSimpleAnalyser.class);

        bindExternalResource(resourceA, ResourceB.RESOURCE_B_KEY, resourceB);
        bindExternalResource(resourceC, ResourceC.RESOURCE_C_KEY, resourceC);
        bindExternalResource(resourceB, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(resourceB, ResourceC.RESOURCE_C_KEY, resourceC);
        bindExternalResource(resourceC, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(resourceC, ResourceB.RESOURCE_B_KEY, resourceB);
        bindExternalResource(flow, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(flow, ResourceB.RESOURCE_B_KEY, resourceB);
        bindExternalResource(flow, ResourceC.RESOURCE_C_KEY, resourceC);
        bindExternalResource(reader, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(reader, ResourceB.RESOURCE_B_KEY, resourceB);
        bindExternalResource(reader, ResourceC.RESOURCE_C_KEY, resourceC);
        bindExternalResource(ae1, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(ae1, ResourceB.RESOURCE_B_KEY, resourceB);
        bindExternalResource(ae1, ResourceC.RESOURCE_C_KEY, resourceC);
        bindExternalResource(ae2, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(ae2, ResourceB.RESOURCE_B_KEY, resourceB);
        bindExternalResource(ae2, ResourceC.RESOURCE_C_KEY, resourceC);

        builder.add(ae1);
        builder.add(ae2);
        builder.setFlowControllerDescription(flow);

        SimplePipeline.runPipeline(reader, builder.createAggregateDescription());
    }
}

> On 24 May 2015, at 13:19 , Mario Gazzo <ma...@gmail.com> wrote:
> 
> Works nicely now, Richard. Thanks a lot :)
> 
> I will run with the 2.2.0 branch from the Git repository in the coming period and I will report back if I stumble upon any issues.
> 
> Is there some time horizon for the final release?
> 
> Cheers
> Mario
> 
>> On 24 May 2015, at 02:26 , Richard Eckart de Castilho <re...@apache.org> wrote:
>> 
>> Ok, so for what it's worth - bindExternalResource() should also have worked
>> in the way that you used it and it was a bug that it didn't.
>> 
>> So both of these issues are sorted out now:
>> 
>> - https://issues.apache.org/jira/browse/UIMA-4425
>> - https://issues.apache.org/jira/browse/UIMA-4426
>> 
>> I can now run your code with "bindResourcesFirst" set to true.
>> In fact, resourceA must be bound to resourceB before resourceB
>> is bound to further things.
>> 
>> We're not supposed to expose users to unreleased artifacts... 
>> but if you know how to get the latest uimaFIT from SVN and hook it
>> up to your code, it wouldn't hurt if you could give the fixes
>> a spin in your environment.
>> 
>> -- Richard
>> 
>> 
>> On 23.05.2015, at 22:52, Richard Eckart de Castilho <re...@apache.org> wrote:
>> 
>>> On 23.05.2015, at 22:45, Mario Gazzo <ma...@gmail.com> wrote:
>>> 
>>>> Thank you, Richard. The reason I use bindExternalResource is because I have a light DSL layer on top where everything get’s wired together from different aggregate modules. This way the modules don’t need to be that tightly coupled up front but I just do the binding generically right before the execution. The example doesn’t show this.
>>> 
>>> ... ok, I'll double check again whether bindExternalResource really cannot be used as you did here ... after fixing the other problem.
>>> 
>>> My main local uimaFIT checkout is currently a bit of a mess.
>>> 
>>> /me fetching duster and dusting off...
>>> 
>>> -- Richard
>> 
> 


Re: Injecting nested resources using UIMA fit

Posted by Richard Eckart de Castilho <re...@apache.org>.
I'd say it depends on demand/pressure. Basically, we have no blockers
for a release as the uimaFIT development process is very incremental
at this time. I have gone through the issues yesterday and weeded out
what would be nice to still get in. But if somebody "urgently" needs
a release, it could probably be complete within 2-4 weeks after starting
it (wrapping up voting may take that much time).

-- Richard

On 24.05.2015, at 13:19, Mario Gazzo <ma...@gmail.com> wrote:

> Works nicely now, Richard. Thanks a lot :)
> 
> I will run with the 2.2.0 branch from the Git repository in the coming period and I will report back if I stumble upon any issues.
> 
> Is there some time horizon for the final release?
> 
> Cheers
> Mario


Re: Injecting nested resources using UIMA fit

Posted by Mario Gazzo <ma...@gmail.com>.
Works nicely now, Richard. Thanks a lot :)

I will run with the 2.2.0 branch from the Git repository in the coming period and I will report back if I stumble upon any issues.

Is there some time horizon for the final release?

Cheers
Mario

> On 24 May 2015, at 02:26 , Richard Eckart de Castilho <re...@apache.org> wrote:
> 
> Ok, so for what it's worth - bindExternalResource() should also have worked
> in the way that you used it and it was a bug that it didn't.
> 
> So both of these issues are sorted out now:
> 
> - https://issues.apache.org/jira/browse/UIMA-4425
> - https://issues.apache.org/jira/browse/UIMA-4426
> 
> I can now run your code with "bindResourcesFirst" set to true.
> In fact, resourceA must be bound to resourceB before resourceB
> is bound to further things.
> 
> We're not supposed to expose users to unreleased artifacts... 
> but if you know how to get the latest uimaFIT from SVN and hook it
> up to your code, it wouldn't hurt if you could give the fixes
> a spin in your environment.
> 
> -- Richard
> 
> 
> On 23.05.2015, at 22:52, Richard Eckart de Castilho <re...@apache.org> wrote:
> 
>> On 23.05.2015, at 22:45, Mario Gazzo <ma...@gmail.com> wrote:
>> 
>>> Thank you, Richard. The reason I use bindExternalResource is because I have a light DSL layer on top where everything get’s wired together from different aggregate modules. This way the modules don’t need to be that tightly coupled up front but I just do the binding generically right before the execution. The example doesn’t show this.
>> 
>> ... ok, I'll double check again whether bindExternalResource really cannot be used as you did here ... after fixing the other problem.
>> 
>> My main local uimaFIT checkout is currently a bit of a mess.
>> 
>> /me fetching duster and dusting off...
>> 
>> -- Richard
> 


Re: Injecting nested resources using UIMA fit

Posted by Richard Eckart de Castilho <re...@apache.org>.
Ok, so for what it's worth - bindExternalResource() should also have worked
in the way that you used it and it was a bug that it didn't.

So both of these issues are sorted out now:

- https://issues.apache.org/jira/browse/UIMA-4425
- https://issues.apache.org/jira/browse/UIMA-4426

I can now run your code with "bindResourcesFirst" set to true.
In fact, resourceA must be bound to resourceB before resourceB
is bound to further things.

We're not supposed to expose users to unreleased artifacts... 
but if you know how to get the latest uimaFIT from SVN and hook it
up to your code, it wouldn't hurt if you could give the fixes
a spin in your environment.

-- Richard


On 23.05.2015, at 22:52, Richard Eckart de Castilho <re...@apache.org> wrote:

> On 23.05.2015, at 22:45, Mario Gazzo <ma...@gmail.com> wrote:
> 
>> Thank you, Richard. The reason I use bindExternalResource is because I have a light DSL layer on top where everything get’s wired together from different aggregate modules. This way the modules don’t need to be that tightly coupled up front but I just do the binding generically right before the execution. The example doesn’t show this.
> 
> ... ok, I'll double check again whether bindExternalResource really cannot be used as you did here ... after fixing the other problem.
> 
> My main local uimaFIT checkout is currently a bit of a mess.
> 
> /me fetching duster and dusting off...
> 
> -- Richard


Re: Injecting nested resources using UIMA fit

Posted by Richard Eckart de Castilho <re...@apache.org>.
On 23.05.2015, at 22:45, Mario Gazzo <ma...@gmail.com> wrote:

> Thank you, Richard. The reason I use bindExternalResource is because I have a light DSL layer on top where everything get’s wired together from different aggregate modules. This way the modules don’t need to be that tightly coupled up front but I just do the binding generically right before the execution. The example doesn’t show this.

... ok, I'll double check again whether bindExternalResource really cannot be used as you did here ... after fixing the other problem.

My main local uimaFIT checkout is currently a bit of a mess.

/me fetching duster and dusting off...

-- Richard

Re: Injecting nested resources using UIMA fit

Posted by Mario Gazzo <ma...@gmail.com>.
Thank you, Richard. The reason I use bindExternalResource is because I have a light DSL layer on top where everything get’s wired together from different aggregate modules. This way the modules don’t need to be that tightly coupled up front but I just do the binding generically right before the execution. The example doesn’t show this.

The reason we are still using UIMA 2.6 is just because we haven’t had the time to test 2.7 yet. I upgraded my own branch now so I intend to start testing it and we will likely move to 2.7 because we could among other things benefit from the new compact binary format.

Cheers
Mario

> On 23 May 2015, at 22:21 , Richard Eckart de Castilho <re...@apache.org> wrote:
> 
> Ok, so here is the analysis. There are two independent reasons why the code does
> not work.
> 
> 
> == Unexpected used of "bindExternalResource" ==
> 
> I did not foresee using "bindExternalResource" for binding
> a nested resource to a resource. So instead of
> 
> resourceA = createExternalResourceDescription(ResourceA.class,"http://resource.org/a");
> resourceB = createExternalResourceDescription(ResourceB.class,"http://resource.org/b");
> bindExternalResource(resourceB, ResourceA.RESOURCE_A_KEY, resourceA);
> 
> You need to write:
> 
> resourceA = createExternalResourceDescription(ResourceA.class,"http://resource.org/a");
> resourceB = createExternalResourceDescription(ResourceB.class,"http://resource.org/b",
>  ResourceA.RESOURCE_A_KEY, resourceA);
> 
> The reason here is that part of the magic that makes nesting work happens in 
> createExternalResourceDescription and is missed if bindExternalResource is used.
> 
> Still, bindExternalResource shouldn't fail with an NPE here - it should give a reasonable
> message. And it should behave consistently, so produce the same error no matter when it
> is called in the code - or it should just work as expected...
> 
> 
> == createExternalResourceDescription for SharedResourceObjects missing code ==
> 
> The proper code for handling nested resources is missing from the createExternalResourceDescription
> variant used to with SharedResourceObjects. This is an oversight and will be fixed. I've done a
> local fix and will commit that soon.
> 
> 
> Btw. any reason you are still on UIMA 2.6.0? I am considering to do the next uimaFIT release
> based on 2.7.0 (and Java 1.6).
> 
> -- Richard


Re: Injecting nested resources using UIMA fit

Posted by Richard Eckart de Castilho <re...@apache.org>.
Ok, so here is the analysis. There are two independent reasons why the code does
not work.


== Unexpected used of "bindExternalResource" ==

I did not foresee using "bindExternalResource" for binding
a nested resource to a resource. So instead of

resourceA = createExternalResourceDescription(ResourceA.class,"http://resource.org/a");
resourceB = createExternalResourceDescription(ResourceB.class,"http://resource.org/b");
bindExternalResource(resourceB, ResourceA.RESOURCE_A_KEY, resourceA);

You need to write:

resourceA = createExternalResourceDescription(ResourceA.class,"http://resource.org/a");
resourceB = createExternalResourceDescription(ResourceB.class,"http://resource.org/b",
  ResourceA.RESOURCE_A_KEY, resourceA);

The reason here is that part of the magic that makes nesting work happens in 
createExternalResourceDescription and is missed if bindExternalResource is used.

Still, bindExternalResource shouldn't fail with an NPE here - it should give a reasonable
message. And it should behave consistently, so produce the same error no matter when it
is called in the code - or it should just work as expected...


== createExternalResourceDescription for SharedResourceObjects missing code ==

The proper code for handling nested resources is missing from the createExternalResourceDescription
variant used to with SharedResourceObjects. This is an oversight and will be fixed. I've done a
local fix and will commit that soon.


Btw. any reason you are still on UIMA 2.6.0? I am considering to do the next uimaFIT release
based on 2.7.0 (and Java 1.6).

-- Richard

Re: Injecting nested resources using UIMA fit

Posted by Mario Gazzo <ma...@gmail.com>.
Here it is once again:

import org.apache.uima.UIMAException;
import org.apache.uima.analysis_engine.AnalysisEngineDescription;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.analysis_engine.metadata.FixedFlow;
import org.apache.uima.analysis_engine.metadata.FlowConstraints;
import org.apache.uima.cas.AbstractCas;
import org.apache.uima.cas.CAS;
import org.apache.uima.collection.CollectionException;
import org.apache.uima.collection.CollectionReaderDescription;
import org.apache.uima.fit.component.*;
import org.apache.uima.fit.component.JCasFlowController_ImplBase;
import org.apache.uima.fit.component.initialize.ConfigurationParameterInitializer;
import org.apache.uima.fit.descriptor.ConfigurationParameter;
import org.apache.uima.fit.descriptor.ExternalResource;
import org.apache.uima.fit.factory.*;
import org.apache.uima.fit.pipeline.SimplePipeline;
import org.apache.uima.fit.util.JCasUtil;
import org.apache.uima.flow.*;
import org.apache.uima.jcas.JCas;
import org.apache.uima.resource.DataResource;
import org.apache.uima.resource.ExternalResourceDescription;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.SharedResourceObject;
import org.apache.uima.util.Progress;
import org.apache.uima.util.ProgressImpl;

import java.io.IOException;
import java.util.ArrayList;

import static org.apache.uima.fit.factory.ExternalResourceFactory.bindExternalResource;

/**
 * Micro example illustrating a problem when initializing nested resources
 */

public class NestedResourceExample {

    public static class ResourceA implements SharedResourceObject, ExternalResourceAware {

        public static final String RESOURCE_A_KEY = "Resource-A";

        @ConfigurationParameter(name= ExternalResourceFactory.PARAM_RESOURCE_NAME)
        private String resourceName;

        @Override
        public String getResourceName() {
            return resourceName;
        }

        @Override
        public void afterResourcesInitialized() throws ResourceInitializationException {
            System.out.println("Resource A initialized");
        }

        @Override
        public void load(DataResource aData) throws ResourceInitializationException {
            ConfigurationParameterInitializer.initialize(this, aData);
            System.out.println("Resource A loaded");
        }

        public void helloA() {
            System.out.println("Hello resource A");
        }
    }

    public static class ResourceB implements SharedResourceObject, ExternalResourceAware {

        public static final String RESOURCE_B_KEY = "Resource-B";

        @ExternalResource(key = ResourceA.RESOURCE_A_KEY)
        private ResourceA resourceA;

        @ConfigurationParameter(name= ExternalResourceFactory.PARAM_RESOURCE_NAME)
        private String resourceName;

        @Override
        public String getResourceName() {
            return resourceName;
        }

        @Override
        public void afterResourcesInitialized() throws ResourceInitializationException {
            System.out.println("Resource B initialized. Now calling resource A");
            resourceA.helloA();
        }

        @Override
        public void load(DataResource aData) throws ResourceInitializationException {
            ConfigurationParameterInitializer.initialize(this, aData);
            System.out.println("Resource B loaded");
        }

        public void helloB() {
            System.out.println("Hello resource B");
        }
    }

    public static class FlowController extends JCasFlowController_ImplBase {

        @ExternalResource(key = ResourceA.RESOURCE_A_KEY)
        private ResourceA resourceA;

        @ExternalResource(key = ResourceB.RESOURCE_B_KEY)
        private ResourceB resourceB;

        private ArrayList<Step> pipeline = new ArrayList<>();

        @Override
        public void initialize(FlowControllerContext context) throws ResourceInitializationException {
            super.initialize(context);

            FlowConstraints flowConstraints = context.getAggregateMetadata().getFlowConstraints();
            String[] sequence = ((FixedFlow) flowConstraints).getFixedFlow();
            for( String key : sequence ) {
                pipeline.add(new SimpleStep(key));
            }

        }

        @Override
        public Flow computeFlow(JCas aJCas) throws AnalysisEngineProcessException {
            return new SimpleFlow(aJCas);
        }

        public class SimpleFlow implements Flow {

            private final JCas jCas;

            private int step = 0;

            public SimpleFlow(JCas jCas) {
                this.jCas = jCas;
            }

            @Override
            public Step next() throws AnalysisEngineProcessException {
                if(step < pipeline.size()) {
                    return pipeline.get(step++);
                } else {
                    resourceA.helloA();
                    resourceB.helloB();
                    return new FinalStep();
                }
            }

            @Override
            public Flow newCasProduced(AbstractCas newCas, String producedBy) throws AnalysisEngineProcessException {
                return null;
            }

            @Override
            public boolean continueOnFailure(String failedAeKey, Exception failure) {
                return false;
            }

            @Override
            public void aborted() {
                System.out.println("Simple flow aborted");
            }
        }
    }

    public static class SimpleCollectionReader extends JCasCollectionReader_ImplBase {

        @ExternalResource(key = ResourceA.RESOURCE_A_KEY)
        private ResourceA resourceA;

        @ExternalResource(key = ResourceB.RESOURCE_B_KEY)
        private ResourceB resourceB;

        private int completed = 0;

        @Override
        public void getNext(JCas jCas) throws IOException, CollectionException {
            try {
                JCas view = ViewCreatorAnnotator.createViewSafely(jCas, CAS.NAME_DEFAULT_SOFA);
                view.setDocumentText("This is some text "+completed++);
                resourceA.helloA();
                resourceB.helloB();
            } catch (AnalysisEngineProcessException e) {
                throw new CollectionException(e);
            }
        }

        @Override
        public boolean hasNext() throws IOException, CollectionException {
            return completed < 1;
        }

        @Override
        public Progress[] getProgress() {
            return new Progress[] { new ProgressImpl(0, 1, Progress.ENTITIES) };
        }
    }

    public static class SimpleAnalyser extends JCasAnnotator_ImplBase {

        @Override
        public void process(JCas jCas) throws AnalysisEngineProcessException {
            JCas view = JCasUtil.getView(jCas, CAS.NAME_DEFAULT_SOFA, true);
            System.out.println(view.getDocumentText());
        }
    }

    public static void main(String[] args) throws UIMAException, IOException {

        boolean bindResourcesFirst = args.length > 0 ? "-brf".equals(args[0]) : false;

        AggregateBuilder builder = new AggregateBuilder();

        ExternalResourceDescription resourceA = ExternalResourceFactory.createExternalResourceDescription(ResourceA.class,"http://resource.org/a");
        ExternalResourceDescription resourceB = ExternalResourceFactory.createExternalResourceDescription(ResourceB.class,"http://resource.org/b");
        CollectionReaderDescription reader = CollectionReaderFactory.createReaderDescription(SimpleCollectionReader.class);
        FlowControllerDescription flow = FlowControllerFactory.createFlowControllerDescription(FlowController.class);
        AnalysisEngineDescription ae = AnalysisEngineFactory.createEngineDescription(SimpleAnalyser.class);

        if(bindResourcesFirst) // Variation to illustrate the different error outcome
            bindExternalResource(resourceB, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(flow, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(flow, ResourceB.RESOURCE_B_KEY, resourceB);
        bindExternalResource(reader, ResourceA.RESOURCE_A_KEY, resourceA);
        bindExternalResource(reader, ResourceB.RESOURCE_B_KEY, resourceB);
        if(!bindResourcesFirst)
            bindExternalResource(resourceB, ResourceA.RESOURCE_A_KEY, resourceA);

        builder.add(ae);
        builder.setFlowControllerDescription(flow);

        SimplePipeline.runPipeline(reader, builder.createAggregateDescription());
    }
}

> On 23 May 2015, at 15:19 , Richard Eckart de Castilho <re...@apache.org> wrote:
> 
> Mario, it appears as if the attachment didn't make it through. No idea
> if the list filters it. I expect the code snippet is not too long,
> so maybe you can paste it directly to the mail?
> 
> -- Richard
> 
> On 23.05.2015, at 11:53, Mario Gazzo <ma...@gmail.com> wrote:
> 
>> I attached a small Java example program that reproduces the problem using the simple pipeline but the error is the same with CPE. We are still using UIMA 2.6 with uimaFIT 2.1.0 but I could reproduce it with UIMA 2.7.
>> 
>> You can vary the binding sequence to see how the error differs depending on whether resource B is bound to resource A first or last. Also try to comment out the dependencies of B on A and see that everything then works as expected.
>> 
>> Let me know if its just me doing something wrong ;)
>> 
>> Cheers
>> Mario
>> 
>> 
>> 
>>> On 22 May 2015, at 17:32 , Mario Gazzo <ma...@gmail.com> wrote:
>>> 
>>> Yes, I am using the uimaFIT base classes but I will try to reproduce it in a micro sample application as soon as possible and post it here.
>>> 
>>>> On 22 May 2015, at 17:04 , Richard Eckart de Castilho <re...@apache.org> wrote:
>>>> 
>>>> I am not sure that I have ever tested nested resources on readers;
>>>> certainly, I have never tested them on flow controllers - only on AEs.
>>>> 
>>>> Anyway - are you using the uimaFIT base-classes for readers and flow
>>>> controllers - those that call ExternalResourceInitializer.initialize(...)
>>>> in their initialize(...) methods?
>>>> 
>>>> Can you provide some example code?
>>>> 
>>>> Cheers,
>>>> 
>>>> -- Richard
>>>> 
>>>> On 22.05.2015, at 16:59, Mario Gazzo <ma...@gmail.com> wrote:
>>>> 
>>>>> I have some trouble with initialising some nested resource with UIMA fit. I have followed the approach described in the section “Resources implementing SharedResourceObject”. I just have a resource B that uses resource A and a collection reader and a flow control that use both A and B but I get "mandatory resource A not set on resource B” illegal state exception. I use the @ExternalResource annotations to get them injected and I used ExternalResourceFactory.bindExternalResource with A and B on the collection reader and flow control descriptions when creating my aggregate. It works if B is not dependent on A but as soon I add the dependency then it breaks. I also tried to explicitly use ExternalResourceFactory.bindExternalResource on A to B but that caused null pointer exception in ExternalResourceFactory when trying to bind to the collection reader right after.
>>>>> 
>>>>> I would appreciate any ideas about what I might be doing wrong.
>>>>> 
>>>>> Cheers
>>>>> Mario
>>>> 
>>> 
>> 
> 


Re: Injecting nested resources using UIMA fit

Posted by Richard Eckart de Castilho <re...@apache.org>.
Mario, it appears as if the attachment didn't make it through. No idea
if the list filters it. I expect the code snippet is not too long,
so maybe you can paste it directly to the mail?

-- Richard

On 23.05.2015, at 11:53, Mario Gazzo <ma...@gmail.com> wrote:

> I attached a small Java example program that reproduces the problem using the simple pipeline but the error is the same with CPE. We are still using UIMA 2.6 with uimaFIT 2.1.0 but I could reproduce it with UIMA 2.7.
> 
> You can vary the binding sequence to see how the error differs depending on whether resource B is bound to resource A first or last. Also try to comment out the dependencies of B on A and see that everything then works as expected.
> 
> Let me know if its just me doing something wrong ;)
> 
> Cheers
> Mario
> 
> 
> 
>> On 22 May 2015, at 17:32 , Mario Gazzo <ma...@gmail.com> wrote:
>> 
>> Yes, I am using the uimaFIT base classes but I will try to reproduce it in a micro sample application as soon as possible and post it here.
>> 
>>> On 22 May 2015, at 17:04 , Richard Eckart de Castilho <re...@apache.org> wrote:
>>> 
>>> I am not sure that I have ever tested nested resources on readers;
>>> certainly, I have never tested them on flow controllers - only on AEs.
>>> 
>>> Anyway - are you using the uimaFIT base-classes for readers and flow
>>> controllers - those that call ExternalResourceInitializer.initialize(...)
>>> in their initialize(...) methods?
>>> 
>>> Can you provide some example code?
>>> 
>>> Cheers,
>>> 
>>> -- Richard
>>> 
>>> On 22.05.2015, at 16:59, Mario Gazzo <ma...@gmail.com> wrote:
>>> 
>>>> I have some trouble with initialising some nested resource with UIMA fit. I have followed the approach described in the section “Resources implementing SharedResourceObject”. I just have a resource B that uses resource A and a collection reader and a flow control that use both A and B but I get "mandatory resource A not set on resource B” illegal state exception. I use the @ExternalResource annotations to get them injected and I used ExternalResourceFactory.bindExternalResource with A and B on the collection reader and flow control descriptions when creating my aggregate. It works if B is not dependent on A but as soon I add the dependency then it breaks. I also tried to explicitly use ExternalResourceFactory.bindExternalResource on A to B but that caused null pointer exception in ExternalResourceFactory when trying to bind to the collection reader right after.
>>>> 
>>>> I would appreciate any ideas about what I might be doing wrong.
>>>> 
>>>> Cheers
>>>> Mario
>>> 
>> 
> 


Re: Injecting nested resources using UIMA fit

Posted by Mario Gazzo <ma...@gmail.com>.
I attached a small Java example program that reproduces the problem using the simple pipeline but the error is the same with CPE. We are still using UIMA 2.6 with uimaFIT 2.1.0 but I could reproduce it with UIMA 2.7.

You can vary the binding sequence to see how the error differs depending on whether resource B is bound to resource A first or last. Also try to comment out the dependencies of B on A and see that everything then works as expected.

Let me know if its just me doing something wrong ;)

Cheers
Mario


Re: Injecting nested resources using UIMA fit

Posted by Mario Gazzo <ma...@gmail.com>.
Yes, I am using the uimaFIT base classes but I will try to reproduce it in a micro sample application as soon as possible and post it here.

> On 22 May 2015, at 17:04 , Richard Eckart de Castilho <re...@apache.org> wrote:
> 
> I am not sure that I have ever tested nested resources on readers;
> certainly, I have never tested them on flow controllers - only on AEs.
> 
> Anyway - are you using the uimaFIT base-classes for readers and flow
> controllers - those that call ExternalResourceInitializer.initialize(...)
> in their initialize(...) methods?
> 
> Can you provide some example code?
> 
> Cheers,
> 
> -- Richard
> 
> On 22.05.2015, at 16:59, Mario Gazzo <ma...@gmail.com> wrote:
> 
>> I have some trouble with initialising some nested resource with UIMA fit. I have followed the approach described in the section “Resources implementing SharedResourceObject”. I just have a resource B that uses resource A and a collection reader and a flow control that use both A and B but I get "mandatory resource A not set on resource B” illegal state exception. I use the @ExternalResource annotations to get them injected and I used ExternalResourceFactory.bindExternalResource with A and B on the collection reader and flow control descriptions when creating my aggregate. It works if B is not dependent on A but as soon I add the dependency then it breaks. I also tried to explicitly use ExternalResourceFactory.bindExternalResource on A to B but that caused null pointer exception in ExternalResourceFactory when trying to bind to the collection reader right after.
>> 
>> I would appreciate any ideas about what I might be doing wrong.
>> 
>> Cheers
>> Mario
> 


Re: Injecting nested resources using UIMA fit

Posted by Richard Eckart de Castilho <re...@apache.org>.
I am not sure that I have ever tested nested resources on readers;
certainly, I have never tested them on flow controllers - only on AEs.

Anyway - are you using the uimaFIT base-classes for readers and flow
controllers - those that call ExternalResourceInitializer.initialize(...)
in their initialize(...) methods?

Can you provide some example code?

Cheers,

-- Richard

On 22.05.2015, at 16:59, Mario Gazzo <ma...@gmail.com> wrote:

> I have some trouble with initialising some nested resource with UIMA fit. I have followed the approach described in the section “Resources implementing SharedResourceObject”. I just have a resource B that uses resource A and a collection reader and a flow control that use both A and B but I get "mandatory resource A not set on resource B” illegal state exception. I use the @ExternalResource annotations to get them injected and I used ExternalResourceFactory.bindExternalResource with A and B on the collection reader and flow control descriptions when creating my aggregate. It works if B is not dependent on A but as soon I add the dependency then it breaks. I also tried to explicitly use ExternalResourceFactory.bindExternalResource on A to B but that caused null pointer exception in ExternalResourceFactory when trying to bind to the collection reader right after.
> 
> I would appreciate any ideas about what I might be doing wrong.
> 
> Cheers
> Mario