package com.dbxml.db.enterprise.labrador;
/*
* dbXML - Native XML Database
* Copyright (c) 1999-2006 The dbXML Group, L.L.C.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* $Id: PersistentSession.java,v 1.3 2006/02/02 19:04:15 bradford Exp $
*/
import com.dbxml.db.client.CollectionClient;
import com.dbxml.db.client.dbXMLClient;
import com.dbxml.db.client.xmlrpc.dbXMLClientImpl;
import com.dbxml.labrador.ID;
import com.dbxml.labrador.configuration.Configuration;
import com.dbxml.labrador.configuration.ConfigurationCallback;
import com.dbxml.labrador.configuration.ConfigurationException;
import com.dbxml.labrador.sessions.Session;
import com.dbxml.labrador.sessions.SessionException;
import com.dbxml.labrador.types.TypeConversions;
import com.dbxml.labrador.types.Types;
import com.dbxml.labrador.types.Variant;
import com.dbxml.labrador.util.Base64;
import com.dbxml.util.dbXMLException;
import com.dbxml.xml.dom.DOMHelper;
import java.util.Iterator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
/**
* PersistentSession is a configurable Session class for Labrador
* that can be used to intercept Session lifecycle events in order
* to persist certain Session resources.
*/
public class PersistentSession extends Session {
private static final String DEFAULT_DRIVER = dbXMLClientImpl.class.getName();
private static final String DRIVER = "driver";
private static final String COLLECTION = "collection";
private static final String PROPERTY = "property";
private static final String NAME = "name";
private static final String VALUE = "value";
private static final String SESSION = "session";
private static final String ID = "id";
private static final String TIMESTAMP = "timestamp";
private static final String RESOURCE = "resource";
private static final String KEY = "key";
private static final String TYPE = "type";
private ID sessionID;
private dbXMLClient client;
private String colName;
private CollectionClient col;
private boolean dirty;
public PersistentSession() {
}
public void setConfig(Configuration config) throws ConfigurationException {
super.setConfig(config);
colName = config.getAttribute(COLLECTION);
String driver = config.getAttribute(DRIVER, DEFAULT_DRIVER);
try {
client = (dbXMLClient)Class.forName(driver).newInstance();
config.processChildren(PROPERTY, new ConfigurationCallback() {
public void process(Configuration cfg) {
String name = cfg.getAttribute(NAME);
String value = cfg.getAttribute(VALUE);
client.setProperty(name, value);
}
});
}
catch ( ClassNotFoundException e ) {
throw new ConfigurationException(e.getMessage());
}
catch ( InstantiationException e ) {
throw new ConfigurationException(e.getMessage());
}
catch ( IllegalAccessException e ) {
throw new ConfigurationException(e.getMessage());
}
}
private CollectionClient getCollection() throws dbXMLException {
if ( col == null ) {
client.connect();
col = client.getCollection(colName);
}
return col;
}
protected void _clear() {
dirty = true;
super._clear();
}
protected void _put(Object key, Object value) {
dirty = true;
super._put(key, value);
}
protected Object _remove(Object key) {
dirty = true;
return super._remove(key);
}
protected void sessionCreated(ID sessionID) throws SessionException {
this.sessionID = sessionID;
readSession();
}
protected void sessionDestroyed() throws SessionException {
if ( !dirty )
return;
writeSession();
}
public void readSession() throws SessionException {
try {
Document doc;
try {
doc = getCollection().getDocument(sessionID.toString());
if ( doc == null )
return;
}
catch ( dbXMLException e ) {
return;
}
Element rootElem = doc.getDocumentElement();
if ( !rootElem.getTagName().equals(SESSION) )
return;
String id = rootElem.getAttribute(ID);
if ( !sessionID.equals(id) )
return;
super._clear();
NodeList nl = rootElem.getChildNodes();
for ( int i = 0; i < nl.getLength(); i++ ) {
Node n = nl.item(i);
if ( n.getNodeType() != Node.ELEMENT_NODE )
continue;
Element e = (Element)n;
if ( !e.getTagName().equals(RESOURCE) )
continue;
String key = e.getAttribute(KEY);
int typeNum = Types.typeNum(e.getAttribute(TYPE));
if ( typeNum != Types.UNKNOWN ) {
StringBuffer sb = new StringBuffer();
NodeList nl2 = e.getChildNodes();
for ( int j = 0; j < nl2.getLength(); j++ ) {
Node n2 = nl2.item(j);
if ( n2.getNodeType() == Node.TEXT_NODE )
sb.append(((Text)n2).getData());
}
String str = Base64.decode(sb.toString().trim());
Variant v = new Variant(str);
Object value = TypeConversions.toTypedValue(typeNum, v);
super._put(key, value);
}
}
dirty = false;
}
catch ( Exception e ) {
throw new SessionException(e.getMessage());
}
}
public void writeSession() throws SessionException {
try {
String docKey = sessionID.toString();
Document doc = DOMHelper.newDocument();
Element rootElem = doc.createElement(SESSION);
doc.appendChild(rootElem);
rootElem.setAttribute(ID, docKey);
rootElem.setAttribute(TIMESTAMP, Long.toString(System.currentTimeMillis()));
Iterator iter = _keyIterator();
while ( iter.hasNext() ) {
Object key = iter.next();
Object value = _get(key);
int typeNum = Types.typeOf(value);
if ( typeNum == Types.UNKNOWN )
continue;
String type = Types.typeName(typeNum);
Variant v = new Variant(value);
String str = v.getString();
if ( str == null )
continue;
Element resource = doc.createElement(RESOURCE);
rootElem.appendChild(resource);
resource.setAttribute(KEY, key.toString());
resource.setAttribute(TYPE, type);
Text text = doc.createTextNode(Base64.encode(str).trim());
resource.appendChild(text);
}
getCollection().setDocument(docKey, doc);
dirty = false;
}
catch ( Exception e ) {
throw new SessionException(e.getMessage());
}
}
public void removeSession() throws SessionException {
try {
String docKey = sessionID.toString();
getCollection().remove(docKey);
super._clear();
dirty = false;
}
catch ( Exception e ) {
throw new SessionException(e.getMessage());
}
}
}