The first cardinal rule when working with pooled ArcGIS Server objects in a webapp is that you must release the server context after every web server request. This is because you are sharing the server object with many other users and you need to put it back into the pool so that other users can access it. The second cardinal rule is that you cannot reference any server object after you have released the server context. If you do, it would be like executing a JDBC Statement
after closing the Connection
. You always need a live connection or a context in a client-server environment to work with objects that are remotely hosted.
So the question then is: How do I persist with the current state of a server object after releasing the context? The answer lies in the saveObject()
and loadObject()
methods of the IServerContext. You can serialize objects to their string representations with saveObject()
and you can deserialize them to their object forms with loadObject()
. So calling saveObject
s before releasing the context and calling loadObject
s on reconnect sets you up well to persist with the current client state while working with pooled objects.
As always, the ADF assists you in making such experiences easy for you. Rather than you having to scratch your heads about when to calls loads and when to calls saves, where to call them, how to keep track of them, et al the ADF provides you a simple interface in WebLifecycle where in you can do all of these tasks and that for only those objects needed for that particular task. The ADF calls relevant methods of the WebLifecycle
just prior to releasing the context as well as immediately after a reconnect.
In the CountFeatures
class that we have been working on through Parts I and II we may want to persist with the SpatialFilter
object. Generally you persist only those objects which have enough client state in them for you to justify the saves and loads. It's obvious that the SpatialFilter
doesn't have much state in it to merit justification but the idea here is to showcase how to do it easily so that you can apply it to more pertinent objects such as graphic elements and symbols.
The WebLifecycle
defines 3 methods - activate()
, passivate()
and destroy()
- which are called at different stages of a request / session lifecycle by the ADF. The passivate()
method is called after a request has been serviced giving you the opportunity to serialize server objects to strings. The activate()
method is called before servicing the request where you can deserialize the strings so that they are available as live objects when you perform the business tasks. And finally the destroy()
is called when the session is being terminated for you to perform the necessary cleanup.
Below is the code which extends the CountFeatures
class to participate in this lifecycle:
public class CountFeatures implements WebContextInitialize, WebContextObserver, WebLifecycle {
...
//serialized SpatialFilter - valid after passivate() and before activate()
String serializedSpatialFilter;
//the spatial filter object - only valid between activate() and passivate()
SpatialFilter filter;
public void init(WebContext webContext) {
...
//create SpatialFilter and set spatial relationship
filter = new SpatialFilter(agsctx.createServerObject(SpatialFilter.getClsid()));
filter.setSpatialRel(esriSpatialRelEnum.esriSpatialRelContains);
}
public void passivate() { //serialize to strings
serializedSpatialFilter = agsctx.saveObject(filter);
}
public void activate() { //deserialize to objects
filter = new SpatialFilter(agsctx.loadObject(serializedSpatialFilter));
}
public void destroy() { //cleanup
filter = null;
serializedSpatialFilter = null;
}
public String doCount() throws Exception {
...
//spatial filter is already created - only need to set geometry to the current extent
filter.setGeometryByRef(agsmap.getFocusMapExtent());
...
return null;
}
}
The complete source code can be downloaded from here.
It's important to note that the loads still create new instances of the objects on the server. So there are no performance benefits to saves and loads versus new instance creations. The benefit to gain is that you don't have to worry about persisting with the state of the object yourself. The server will do that work for you.
That does it for this trilogy (ok so that was blatant abuse of that word - but hey, who's to say... It's my world around here :)