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