Skip to content

Commit

Permalink
Add ERPersistentSessionStorage framework to Wonder
Browse files Browse the repository at this point in the history
  • Loading branch information
nullterminated committed Apr 29, 2012
1 parent 56dda08 commit 60b70d4
Show file tree
Hide file tree
Showing 24 changed files with 894 additions and 1 deletion.
11 changes: 10 additions & 1 deletion Build/build/build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1161,12 +1161,21 @@
</antcall>
</target>

<target name="ERPersistentSessionStorage.all">
<antcall target="global.framework.${build.action}" >
<param name="project.principal.class" value="er.persistentsessionstorage.ERPersistentSessionStorage" />
<param name="project.name" value="ERPersistentSessionStorage" />
<param name="project.dir" value="Frameworks/Misc/ERPersistentSessionStorage" />
<param name="wo.external.root.bundles" value="${frameworks.wonder.core}" />
</antcall>
</target>

<!--
The targets here correspond to a top-level directory, split into frameworks, apps and examples
to add your own, add a target definition above and choose the correct group below
-->

<target name="common.frameworks.all" depends="ERJars.all, JavaWOExtensions.all, ERExtensions.all, Ajax.all, ERDirectToWeb.all, ERNeutralLook.all, ERSelenium.all, WOOgnl.all, ERPrototypes.all, ERPlot.all, ERIndexing.all, ERChronic.all, ERCaching.all, ERCaptcha.all, ERProfiling.all, EROpenID.all, ERPDFGeneration.all, ERJGroupsSynchronizer.all, ERRest.all, ERAttachment.all, ERTaggable.all, ERJavaMail.all, ERCoreBusinessLogic.all, ERChangeNotificationJMS.all, ERCalendar.all, ERExcelLook.all, ERWorkerChannel.all, BTBusinessLogic.all, JavaMemoryAdaptor.all, JavaRESTAdaptor.all, JavaFSAdaptor.all, JavaERJDBCAdaptor.all, WOLips.all, WOJRebel.all, ERMoviesLogic.all, SnapshotExplorer.all, ERDivaliteLook.all, ERJasperReports.all, ERAttributeExtension.all, ERWOAdaptor.all, ERCayenne.all, ERCayenne.all, ERDistribution.all, MooTools.all, ERJQueryMobile.all" />
<target name="common.frameworks.all" depends="ERJars.all, JavaWOExtensions.all, ERExtensions.all, Ajax.all, ERDirectToWeb.all, ERNeutralLook.all, ERSelenium.all, WOOgnl.all, ERPrototypes.all, ERPlot.all, ERIndexing.all, ERChronic.all, ERCaching.all, ERCaptcha.all, ERProfiling.all, EROpenID.all, ERPDFGeneration.all, ERJGroupsSynchronizer.all, ERRest.all, ERAttachment.all, ERTaggable.all, ERJavaMail.all, ERCoreBusinessLogic.all, ERChangeNotificationJMS.all, ERCalendar.all, ERExcelLook.all, ERWorkerChannel.all, BTBusinessLogic.all, JavaMemoryAdaptor.all, JavaRESTAdaptor.all, JavaFSAdaptor.all, JavaERJDBCAdaptor.all, WOLips.all, WOJRebel.all, ERMoviesLogic.all, SnapshotExplorer.all, ERDivaliteLook.all, ERJasperReports.all, ERAttributeExtension.all, ERWOAdaptor.all, ERCayenne.all, ERCayenne.all, ERDistribution.all, MooTools.all, ERJQueryMobile.all, ERPersistentSessionStorage.all" />

<target name="common.applications.all" depends="BugTracker.all, ERMailer.all, Uber.all, SecretPal.all, ERXTest.all, PluginTest.all" />

Expand Down
15 changes: 15 additions & 0 deletions Frameworks/Misc/ERPersistentSessionStorage/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="Sources"/>
<classpathentry kind="con" path="WOFramework/ERExtensions"/>
<classpathentry kind="con" path="WOFramework/ERJars"/>
<classpathentry kind="con" path="WOFramework/ERPrototypes"/>
<classpathentry kind="con" path="WOFramework/JavaWOExtensions"/>
<classpathentry kind="con" path="WOFramework/JavaEOAccess"/>
<classpathentry kind="con" path="WOFramework/JavaEOControl"/>
<classpathentry kind="con" path="WOFramework/JavaFoundation"/>
<classpathentry kind="con" path="WOFramework/JavaJDBCAdaptor"/>
<classpathentry kind="con" path="WOFramework/JavaWebObjects"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>
23 changes: 23 additions & 0 deletions Frameworks/Misc/ERPersistentSessionStorage/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ERPersistentSessionStorage</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.objectstyle.wolips.incrementalbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.objectstyle.wolips.incrementalframeworknature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding//Components=UTF-8
1 change: 1 addition & 0 deletions Frameworks/Misc/ERPersistentSessionStorage/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This framework should be all one needs to store sessions persistently in a database. Every page and every component in the backtrack cache must serialize properly for it to work however. Findbugs is useful in tracking down your serialization errors :-)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-destination /Users/rams/Repositories/ponder/ERPersistentSessionStorage/Sources -extension java -java -javaTemplate _WonderEntity.java -model Resources/ERPersistentSessionStorage.eomodeld -packagedirs -subclassDestination /Users/rams/Repositories/ponder/ERPersistentSessionStorage/Sources -subclassJavaTemplate WonderEntity.java -templatedir Templates -verbose -loadModelGroup -superclassPackage eogen
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
attributes = (
{
columnName = expirationDate;
name = expirationDate;
prototypeName = dateTime;
userInfo = {"_EntityModeler" = {documentation = "The date when the session expires."; }; };
},
{allowsNull = N; name = id; prototypeName = id; },
{
columnName = intLock;
name = intLock;
prototypeName = intNumber;
userInfo = {
"_EntityModeler" = {
documentation = "Since we can't lock on the sessionData blob, this column is locked and updated on each save. This is done to prevent cases where a session might be checked out twice before it is checked in.";
};
};
},
{
columnName = sessionData;
name = sessionData;
prototypeName = blob;
userInfo = {"_EntityModeler" = {documentation = "Holds the session data blob."; }; };
},
{
columnName = sessionID;
name = sessionID;
prototypeName = varchar50;
userInfo = {"_EntityModeler" = {documentation = "The WOSession id."; }; };
}
);
attributesUsedForLocking = (id, intLock, sessionID);
className = "er.persistentsessionstorage.model.ERSessionInfo";
classProperties = (expirationDate, intLock, sessionData, sessionID);
entityIndexes = (
{
attributes = (sessionID);
constraint = distinct;
indexType = clustered;
name = "sessionID_idx";
order = asc;
userInfo = {
"_EntityModeler" = {documentation = "Unique index to prevent duplicate session ids."; };
};
}
);
externalName = ERSessionInfo;
fetchSpecificationDictionary = {};
name = ERSessionInfo;
primaryKeyAttributes = (id);
userInfo = {
"_EntityModeler" = {
documentation = "This EO maintains state information for a WO application. The session data blob is the serialized WOSession. If you're making relationships to this EO in your model, you're probably doing something very wrong :)";
};
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
EOModelVersion = "2.1";
adaptorName = JDBC;
entities = (
{
className = "er.persistentsessionstorage.model.ERSessionInfo";
name = ERSessionInfo;
}
);
}
20 changes: 20 additions & 0 deletions Frameworks/Misc/ERPersistentSessionStorage/Resources/Properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#The number of seconds for which a session may be idle before it times out.
#The default is 3600 seconds (one hour). A value of 0 means sessions never
#time out.
#WOSessionTimeOut=0

#The WOSessionStore removes session automatically at a specific interval.
#The problem is it does not check to see if the session is distributed.
#In order to prevent one instance from removing a session which another
#instance might be using, we turn it off by making the interval the max
#integer value possible. This should be sufficient to prevent premature
#session deletion unless you plan on having an app uptimes > 24 days.
_WOSessionReclaimingInterval=2147483

#ERXResponseRewriter uses weak references to pages in order to store
#the information about the resources sent to a page. That does not work
#for persistent sessions, because the weak references are garbage collected
#after the session is serialized. This property should make no difference
#when using in-memory sessions, but is necessary for persistent sessions,
#especially if you plan on using Ajax.
er.extensions.appserver.ajax.ERXAjaxSession.storesPageInfo=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package er.persistentsessionstorage;

import org.apache.log4j.Logger;

import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOSession;
import com.webobjects.appserver.WOSessionStore;
import com.webobjects.foundation.NSNotification;
import com.webobjects.foundation.NSNotificationCenter;
import com.webobjects.foundation.NSSelector;

import er.extensions.ERXFrameworkPrincipal;

public class ERPersistentSessionStorage extends ERXFrameworkPrincipal {

public static final Class<?>[] REQUIRES = new Class[] {};

protected static volatile ERPersistentSessionStorage sharedInstance;

private static final Logger log = Logger.getLogger(ERPersistentSessionStorage.class);

// Registers the class as the framework principal
static {
log.debug("Static Initializer for ERR2d2w");
setUpFrameworkPrincipalClass(ERPersistentSessionStorage.class);
}

public static ERPersistentSessionStorage sharedInstance() {
if (sharedInstance == null) {
synchronized (ERPersistentSessionStorage.class) {
if (sharedInstance == null) {
sharedInstance = sharedInstance(ERPersistentSessionStorage.class);
}
}
}
return sharedInstance;
}

@Override
public void finishInitialization() {
log.info("Initializing persistent session store.");
WOSessionStore store = new ERPersistentSessionStore();

//Create the persistent session store
WOApplication.application().setSessionStore(store);

//Set up notifications for newly created sessions
NSNotificationCenter nc = NSNotificationCenter.defaultCenter();
NSSelector<Void> sel = new NSSelector<Void>("enableSessionDistribution", new Class[] {NSNotification.class});
nc.addObserver(this, sel, WOSession.SessionDidCreateNotification, null);
}

/**
* Sets distribution enabled on new sessions
* @param n a session created notification
*/
public void enableSessionDistribution(NSNotification n) {
WOSession session = (WOSession) n.object();
session.setDistributionEnabled(true);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package er.persistentsessionstorage;

import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOSession;
import com.webobjects.appserver.WOSessionStore;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.foundation.NSTimestamp;

import er.extensions.eof.ERXEC;
import er.persistentsessionstorage.model.ERSessionInfo;

public class ERPersistentSessionStore extends WOSessionStore {

@Override
public WOSession removeSessionWithID(String s) {
EOEditingContext ec = ERXEC.newEditingContext();
ERSessionInfo info = ERSessionInfo.clazz.objectMatchingKeyAndValue(ec, ERSessionInfo.SESSION_ID_KEY, s);
if(info != null) {
WOSession session = info.session();
info.delete();
ec.saveChanges();
return session;
}
return null;
}

@Override
public WOSession restoreSessionWithID(String s, WORequest request) {
EOEditingContext ec = ERXEC.newEditingContext();
ERSessionInfo info = ERSessionInfo.clazz.objectMatchingKeyAndValue(ec, ERSessionInfo.SESSION_ID_KEY, s);
return info == null || info.expirationDate().getTime() < System.currentTimeMillis()?null:info.session();
}

@Override
public void saveSessionForContext(WOContext context) {
WOSession session = context.session();
EOEditingContext ec = ERXEC.newEditingContext();
ERSessionInfo info = ERSessionInfo.clazz.objectMatchingKeyAndValue(ec, ERSessionInfo.SESSION_ID_KEY, session.sessionID());
if(info == null) {
info = ERSessionInfo.clazz.createAndInsertObject(ec);
info.setSessionID(session.sessionID());
}
NSTimestamp expires = new NSTimestamp(System.currentTimeMillis() + session.timeOutMillis());
info.setExpirationDate(expires);
info.archiveDataFromSession(session);
ec.saveChanges();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package er.persistentsessionstorage.migrations;

import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.foundation.NSArray;

import er.extensions.migration.ERXMigrationDatabase;
import er.extensions.migration.ERXMigrationTable;
import er.extensions.migration.ERXModelVersion;

public class ERPersistentSessionStorage0 extends ERXMigrationDatabase.Migration {
@Override
public NSArray<ERXModelVersion> modelDependencies() {
return null;
}

@Override
public void downgrade(EOEditingContext editingContext, ERXMigrationDatabase database) throws Throwable {
// DO NOTHING
}

@Override
public void upgrade(EOEditingContext editingContext, ERXMigrationDatabase database) throws Throwable {
ERXMigrationTable erSessionInfoTable = database.newTableNamed("ERSessionInfo");
erSessionInfoTable.newTimestampColumn("expirationDate", false);
erSessionInfoTable.newIntegerColumn("id", false);
erSessionInfoTable.newIntegerColumn("intLock", false);
erSessionInfoTable.newBlobColumn("sessionData", false);
erSessionInfoTable.newStringColumn("sessionID", 50, false);

erSessionInfoTable.addUniqueIndex("sessionID_idx", erSessionInfoTable.existingColumnNamed("sessionID"));

erSessionInfoTable.create();
erSessionInfoTable.setPrimaryKey("id");
}
}
Loading

0 comments on commit 60b70d4

Please sign in to comment.