4906

xsp.application.timeout and “Object has been removed or recycled”

Question:

I've been having a lot of problems with disappearing Java class level Domino objects lately. For example I place a lotus.domino.Session to a (non-static) class level variable and when I try to use it in the next code line I get:

NotesException: Object has been removed or recycled

I didn't have these problems before I started using <em>managed beans</em> but now I seem to get them all the time with request scoped beans and also in plain Java objects. I've been adding isRecycled() checks to many places and been wondering why I didn't have to do it before. I know Domino objects are not serialized but before they stayed for the duration of the request or agent.

Today I copied the code giving this exception to another db and there the exception did not occur. Then I copied the <em>xsp.properties</em> from that db to the original db and the exception did not occur there either. By removing one line at a time I found out that if I have this:

xsp.application.timeout=10

I don't get the exception and if I remove it I get the exception. Does anyone understand why? The default should be 30 minutes but my session object seems to dissappear in nanoseconds unless I set the application timeout. I'm passing the session from SSJS to Java and store it in the constructor code:

private Session session; public Domino(Session session) { this.session = session; }

As you can see this is not a managed bean. The Domino version I tested with is 9.0.1 but I need to use this code also with 8.5.2. The code is running in beforePageLoad event.

It seems that my problem is solved but I'd like understand what's happening here.

<strong>Update1</strong>

I still get the error in the main db if I wait for a while (probabaly more than 10 minutes) and then reload the XPage. In the other db I've never gotten the error.

<strong>Update2</strong>

Yesterday I added back the full <em>xsp.properties</em> from the db where it has worked all the time. Now after 8 hours it still works fine also in my original db. Looks like I need also this:

xsp.persistence.mode=basic

which means "Keeps pages in memory". It seems the XPage is serialized immediately (within a single HTTP request) without this setting.

Answer1:

Quick answer: don't ever, ever, <em>ever</em>, for <em>any reason whatsoever</em>, store a handle to a Domino object for any longer than a single HTTP request. :)

I suspect that, because a Domino session is essentially a singleton, storing it in application scope was preventing it from being recycled at the end of each request, as it normally would. Under normal circumstances, any Domino object the XPage engine is aware of at the end of any HTTP request is automatically recycled. So in order to prevent the error you're receiving, it's best practice to not store handles in any scope higher than request.

The good news is, at least for the current Session and Database, you never need to: you can ask the variable resolver for it.

SSJS has intrinsic access to the variable resolver, since all SSJS code has to be evaluated at runtime; so any reference to session, for example, has to ask the variable resolver what "session" currently evaluates to. This happens automatically when the entire expression is evaluated, but we can manually access the variable resolver from our own Java code:

FacesContext context = FacesContext.getCurrentInstance(); Application app = context.getApplication(); VariableResolver resolver = app.getVariableResolver(); Session currentSession = (Session) resolver.resolveVariable("session", context);

That's a lot of nonsense to type each time we want to get a handle on a variable, and resolving contextual variables is often useful (because this works for any variables that would also be valid within SSJS, not just for Domino objects), so I recommend wrapping this in a static utility method:

public class VariableUtils { public static Object getVariableValue(String variable) { FacesContext context = FacesContext.getCurrentInstance(); Application app = context.getApplication(); VariableResolver resolver = app.getVariableResolver(); return resolver.resolveVariable(variable, context); } }

Then you can easily resolve any variable from any of your Java code:

Session currentSession = (Session) VariableUtils.resolveVariable("session"); Database currentDatabase = (Database) VariableUtils.resolveVariable("database"); DominoDocument currentDocument = (DominoDocument) VariableUtils.resolveVariable("currentDocument");

If your app loads the Extension Library, there's already a static method available for those first two:

Session currentSession = (Session) ExtLibUtils.getCurrentSession(); Database currentDatabase = (Database) ExtLibUtils.getCurrentDatabase();

That class has a bunch of useful variable resolution methods you might want to check out. But having your own convenience method for resolving variables is useful for any contextual inspection -- for instance, retrieving the current row for a view panel, data table, or repeat; the query string parameter map (param); any data source. Just like SSJS, your Java code is typically triggered within the context of a given component (for instance, the onclick event handler of a button), so any variables that are valid for that component can be resolved this way.

One last note about storage of Domino objects: just store metadata instead. So, if you would otherwise be storing a database (other than the current), store instead its filepath or replica ID, and when you need to access it, use the stored metadata to ask the current session for a handle to the database. Similarly, store the name of a view, but not the View itself; store a document's NoteID or UNID, but not the actual Document. If you find you're having to obtain these handles repeatedly, and therefore wishing they were cached, revisit the way your logic is structured... the code should be refactored to establish a handle once, do whatever needs to be done with / to that object, then discard it (and, if it's not a session, database, or an object that you also have a data source bound to, manually recycle it).

Keep in mind that <em>any</em> Java object that implements Serializable and does not store pointers to any Domino objects can be stored as long as you want. So create "model" objects for your data (and populate their properties by reading the corresponding Domino handles), store <em>those</em> objects in scope, and then write back to the corresponding Domino objects whenever appropriate. If IBM hadn't tried to simplify XPages for us by creating the document and view data sources for us, this is what we'd already be doing (for instance, we'd be binding all of our editable fields to properties of bean classes like Contact, ExpenseReport, Facility, etc., not directly to note items). But because these data sources <em>do</em> exist, we're still thinking in terms of "documents" and "views", instead of thinking in terms of the people, physical objects, and business processes that the data represents. As a result, we maintain unnecessary links between our user interfaces and back end data, instead of only touching the back end data when we need to do an initial query and an eventual update (or create). Sorry to get so philosophical, but so much of what we try to do in XPages gets so much easier when we transition beyond thinking in documents. :)

Answer2:

I think this can be caused by <a href="http://www-01.ibm.com/support/docview.wss?uid=swg1LO58442" rel="nofollow">known</a> bug of 8.5.2. We have had the same problems, only workaround was to remove recycle code where not really necessary. The example in APAR is not very helpful, it covers only loop avoiding to recycle single document, but other objects (database, view) need different approach.

<strong>Edit:</strong> There can be another issue related to internal object cache. Not sure if it was fixed: when you ask for some object, you may get one from internal cache, which was already recycled (intentionally). This can be proved by printing Java object ID. It was big issue in 8.5.1 and 8.5.2, and I doubt it happens in R9. Did not test, tho.

Answer3:

It turned out that when I made a small change to the parent of my parent class and built the application it started to work. To make sure I copy pasted the original code back and it still worked.

Looks like it was some kind of build problem. This was not the only case when I've seen this problem but next time I will try some re-saving, cleaning and rebuilding.

Recommend

  • Can some data be separated in a Tcp connection?
  • How to escalate top-most supervisors in Akka?
  • GWT Toolkit: preprocessing files on client side
  • Per Machine App Registration
  • Read stdin in chunks in Bash pipe
  • Quickly or concisely determine the longest string per column in a row-based data collection
  • GitHub default README markup
  • Quick Question About Get and Set
  • Find VMID for running instance
  • Issue with routerLink directive
  • What causes the runtime difference in this trivial fortran code?
  • Wrong labels when plotting a time series pandas dataframe with matplotlib
  • Which open source license has no forking [closed]
  • How can I replace the server in Web Component Tester
  • How to autopopulate a field in SugarCRM form
  • Trying to get the char code of ENTER key
  • Clarification on min distance on LocationManager.requestLocationUpdates method, min Distance paramet
  • Using Sax parsing to edit and write XML in VB6
  • C# program and C++ DLL compiled for 32-bit system crash on 64-bit system
  • How integrated is Collada to OpenGL ES
  • What and where is mdimport
  • Debug.DrawLine not showing in the GameView
  • Alternative To body {overflow:scroll;} That Will Prevent Page Jostling/Wriggling?
  • WPF - CanExecute dosn't fire when raising Commands from a UserControl
  • Yii2: Config params vs. const/define
  • Django rest serializer Breaks when data exists
  • How to rebase a series of branches?
  • Azure Cloud Service Web Role web pages do not load
  • 'TypeError' while using NSGA2 to solve Multi-objective prob. from pyopt-sparse in OpenMDAO
  • what is the difference between the asp.net mvc application and asp.net web application
  • Jquery - Jquery Wysiwyg return html as a string
  • Arrays break string types in Julia
  • bootstrap to use multiple ng-app
  • How to get icons for entities from eclipse?
  • WPF Applying a trigger on binding failure
  • How get height of the a view with gone visibility and height defined as wrap_content in xml?
  • Java static initializers and reflection
  • Turn off referential integrity in Derby? is it possible?
  • Linking SubReports Without LinkChild/LinkMaster
  • JaxB to read class hierarchy