tuscany-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Simon Nash <n...@apache.org>
Subject Re: ServiceReference returns fine - but object not set correctly.
Date Fri, 22 Apr 2011 18:45:21 GMT
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 <nash@apache.org 
> <mailto:nash@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 <nash@apache.org
>         <mailto:nash@apache.org> <mailto:nash@apache.org
>         <mailto:nash@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:///
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 


Mime
View raw message