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