Hi Monosij,
Glad to hear this is working.  I'll answer your questions briefly inline
below, but I'd like to say up front that I think a slight change to the
design of your application might be a better approach.

As I understand it, QueryServlet sends a query to QueryExecutor, which
executes the query, puts the results in QueryResults, and passes a
service reference for QueryResults back to QueryServlet.  QueryServlet
then invokes the QueryResults service to get the results.

A simpler approach would be for QueryExecutor to create a POJO containing
the results and pass that POJO back to QueryServlet.  This would remove
the need to use service references, HashMaps, unique IDs, etc.  Is there
some reason why this simpler approach isn't suitable?

  Simon

Monosij Dutta-Roy wrote:
hi Simon - Great! That worked. I am now getting back results! Thank you. No null-pointers.
--------------------
So I wanted to clarify your solution for the permanent approach.

If I use a Unique ID for each request:

1. How should I generate this ID?

It's a unique ID for each client (person using the system), not for
each request.  If your application doesn't have a notion of client,
and each request isn't related to past or future activity, then using
the POJO approach that I mentioned above seems like a better solution.

2. I thought composite references were injected in as per Singleton pattern - a new object for each thread.

No, an SCA composite-scoped implementation is semantically a single
global object.  This could be implemented under the covers as different
Java objects for different threads, but these objects would need to
synchronize their state after each update, giving the appearance of
a single global object.

3. In going the UniqueID / HashMap way would I not be programming to the framework - rather than a POJO model.

Yes, but this is caused by your design choice to make QueryResults a
service instead of a POJO.  If you can make it a POJO instead, this is
a much simpler approach.

4. Is there another approach to this issue? I need to read up on the various Scopes.

See comments above.

5. Does this scale effectively for QueryResults on multiple nodes with each having a large set of some collections? of course I would be removing the entry from the HashMap so maybe its not an issue.
>
It's not ideal.  Using the approach described above is more efficient.

--------------------
Just trying to understand the right approach to the framework. And thanks again!

You're welcome!

  Simon

monosij

On Thu, Apr 21, 2011 at 2:59 PM, Simon Nash <n...@apache.org <mailto:n...@apache.org>> wrote:

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