Monosij Dutta-Roy wrote:
hi Simon -

Made the changes as suggested and <reference> is now only in QueryExecutor. All others pure Java. Thanks for the help and suggestions. I tried just getting the size of the ArrayList in QueryExecutor and I lose it right after I set it in the ServiceReference object on QueryExecutor.
--------------------
So in QueryExecutor I try as below where QueryResults declared as a ServiceReference:

@Reference
protected ServiceReference<QueryResults> queryResults;

1. System.out.println("Patients Count (Before ServiceReference): " + alPatients.size());
2. queryResults.getService().setResults(alPatients);
3. System.out.println("Patients Count (In ServiceReference): " + queryResults.getService().getResults().size());

1 Returns the correct size of ArrayList of Patients in getting from database. 2. Sets the ArrayList in the QueryResults object declared as a ServiceReference injection for QueryExecutor. 3. Try to get the size of the ArrayList in the ServiceReference object QueryResults and get the null-pointer error.

Did not have to try it from QueryServlet. It does not seem to set it in the ServiceReference object. Running JDK 1.6.0.20.
--------------------
Thanks again for all your help.

Thanks for trying this.  This narrows down the problem and I think
I know what is happening.

I think the problem is the scope of the QueryResults service implementation.
If it has the default scope (STATELESS), a new instance of the implementation
class will be created for every service invocation.  So when you invoke
getResults() you are getting a different instance than when you invoked
setResults().  This would happen whether or not you use a ServiceReference
to invoke setResults() and getResults().

A quick fix to solve this problem is to set @Scope("COMPOSITE") on the
QueryResults implementation class.  This will create a single instance
object for the QueryResults service and use it for all calls to this service.
If you only have one client, this will work fine.  However, if you have more
than one client, this won't work because of the following scenario:
 client 1 -> setResults(results)
 client 2 -> setResults(results)
 client 1 -> getResults()
 client 2 -> getResults()
This will cause client 1 to get the results set by client 2, which isn't
correct.

The solution to this problem is to use @Scope("COMPOSITE") for the
QueryResults implementation class and give each client a unique ID which
is passed by the client to the QueryResults service.  The sequence of
calls above would change to the following:
 client 1 -> setResults(client1ID, results)
 client 2 -> setResults(client2ID, results)
 client 1 -> getResults(client1ID)
 client 2 -> getResults(client2ID)

The QueryResults implementation needs to keep a HashMap (or similar) that
holds multiple result sets and maps the unique client ID to the results
for that client.

  Simon

monosij

On Thu, Apr 21, 2011 at 4:36 AM, Simon Nash <n...@apache.org <mailto:n...@apache.org>> wrote:

    Hi Monosij,
    See comments below.

     Simon


    Monosij Dutta-Roy wrote:

        Simon -
        Thanks for your help with the ServiceReference - it is almost
        there but am getting a null-pointer error on trying to access
        the QueryResults.
        I have attached the error file generated.
        ---------------------
        Starting with QueryExecutor where I create the ServiceReference
        object as:     @Reference
           protected ServiceReference<QueryResults> queryResults;

    That looks right.


        I pass it back through QueryOrchestrator > QueryService >
        QueryServlet and I declare the reference in *_each_* object the
        same as above.

     >
    You should only use the @Reference annotation in QueryExecutor.  In the
    other classes you should declare it as a normal Java variable with the
    type ServiceReference<QueryResults>.


        And refer to it in the composite file as:

               <reference name="queryResults"
        target="QueryResultsComponent/QueryResults">
                   <interface.java interface="org.rd.qm.QueryResults"/>
               </reference>

    You should only be doing this in QueryExecutor.


        It seems to work as now I do not get the PassByValue error
        anymore. ---------------------
        But now I get a null-pointer error when trying to access the
        QueryResults object in the ServiceReference object.
        I set the ServiceReference<QueryResults> queryResults in
        QueryExecutor as:

        first this way:
        queryResults.getService().setResults(alPatients);

    That looks right.


        second in this way:
        QueryResults quRes = new QueryResultsImpl();
        quRes.setResults(alPatients);
        queryResults.getBusinessInterface().cast(quRes);

    That doesn't look right.


        Essentially I am trying to set the ArrayList of results in
        QueryResults and in QueryServlet trying to display the ArrayList.

        So in QueryServlet I try to access the ArrayList as:
        ArrayList alPatients = queryResults.getService().getResults();

    That looks right.


        This seems to be fine as I get an ArrayList
        But I get a null-pointer when I try to iterate the ArrayList.

     >
    I'm not sure why this is happening.  You should get the same contents
    from doing this in QueryServlet as you would get if you did it in
    QueryExecutor after the setResults() call.  Can you try interating the
    ArrayList in QueryExecutor after calling setResults() to see if that
    works OK?


        ---------------------
        Questions:

        1. Seems the way I set I have set up the ServiceReference is
        working. Is that the best way to set up the ServiceReference? If
        so it seems like it would be a good idea to have
        ServiceReferences as a separate contribution that is 'passed
        around'. And then take it a step further by setting
        ServiceReferences as JAXB datatypes.

    Contributions aren't passed around at runtime.  The way you are doing it
    (with the changes/corrections that I suggested above) is fine.  I think
    it's best to defer the JAXB issues until you have got the non-JAXB code
    working.


        2. I had to set up the ServiceReference in each obect, even in
        QueryServlet. QueryServlet which calls QueryService (in same
        composite) still needs to pass back QueryResults as a
        ServiceReference since QueryService is defined as Remotable. I
        was planning on using QueryService for housekeeping while still
        making it Remotable - and pass back to QueryServlet only what is
        needed (so servlet framework can be swapped out). But now it
        seems I have to make the QueryServlet (ie the Servlet framework)
        depend on QueryResult or such. Is there a way to avoid this? Am
        I thinking about this the right way? I am thinking QueryServlet
        should only know and depend on QueryService in the same
        composite. I guess then QueryService has to be Local?

    If you make QueryService local, this means the code for QueryService
    will always run in the same webapp as QueryServlet.  Is that what
    you want?  Originally I thought you wanted to keep the back-end logic
    separate from the UI framework.  Is QueryService part of the back-end
    logic or is it part of the UI framework?


        3. This is a question for later once I get this working but I am
        currently importing QueryOrchestrator in QueryService (webapp).
        Would there be a way to go around this and not have
        QueryOrchestrator connected at all. I am assuming I can go the
        ws.binding route and just call the webservice that
        QueryOrchestrator will service - but I lose the non-ws.binding
        connectivity. Would there be a way to just depend on
        QueryResults - that is shared by everyone and is a
        ServiceReference - to make it happen. I am just shooting in dark
        here a little. But my thought is I should only want to depend on
        QueryResults and not worry about how I get QueryResults. I guess
        I will need to try some approaches.

    I'm not sure what the purpose of QueryOrchestrator is.  As you say,
    getting
    it working is the first priority.  When you have it working, you can
    look
    at the end-to-end design and make changes incrementally to change the
    component structure as needed.  With SCA, this should be easy to do.


        4. This maybe related, not a big deal but strange. I am using
        Eclipse Helios on Ubuntu and since I started using
        ServiceReference - the objects from the third composite:
        domainBCA - which are Person and PhysicalLocation have an error
        marker on them as 'import not found'. I tried deleting them and
        recreating the imports, it still remains. Removing
        ServiceReference makes those go away. However it does not create
        a problem as such as Maven compiles fine - but it is happening
        in both the composites: controller and servlet.
        ---------------------
        Thanks for all your help and patience.

    My guess is that your Eclipse workspace is missing a dependency on the
    Tuscany library that provides the definition of the ServiceReference
    interface.

     Simon

        monosij


        ------------------------------------------------------------------------


           HTTP ERROR 500

        Problem accessing /qmAppSCA01/QueryServlet. Reason:

           INTERNAL_SERVER_ERROR


             Caused by:

        java.lang.NullPointerException
               at
        org.rd.qm.servlet.QueryServlet.getPatients(QueryServlet.java:74)
               at
        org.rd.qm.servlet.QueryServlet.service(QueryServlet.java:91)
               at
        javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
               at
        org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
               at
        org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:401)
               at
        
org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
               at
        org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
               at
        org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
               at
        org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
               at
        
org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:230)
               at
        
org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
               at
        org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
               at org.mortbay.jetty.Server.handle(Server.java:326)
               at
        org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
               at
        
org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:945)
               at
        org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
               at
        org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
               at
        org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
               at
        
org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
               at
        
org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

        ------------------------------------------------------------------------
        /Powered by Jetty:///






















Reply via email to