001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins;
023:
024: import java.rmi.RemoteException;
025:
026: import java.io.ByteArrayInputStream;
027: import java.io.ByteArrayOutputStream;
028: import java.io.ObjectInputStream;
029: import java.io.ObjectOutputStream;
030: import java.io.IOException;
031:
032: import javax.ejb.SessionBean;
033: import javax.ejb.RemoveException;
034: import javax.ejb.EJBException;
035:
036: import javax.naming.Context;
037: import javax.naming.InitialContext;
038:
039: import org.jboss.ejb.Container;
040: import org.jboss.ejb.StatefulSessionContainer;
041: import org.jboss.ejb.StatefulSessionPersistenceManager;
042: import org.jboss.ejb.StatefulSessionEnterpriseContext;
043: import org.jboss.metadata.ClusterConfigMetaData;
044:
045: import org.jboss.ha.hasessionstate.interfaces.HASessionState;
046: import org.jboss.ha.hasessionstate.interfaces.PackagedSession;
047: import org.jboss.ha.framework.interfaces.HAPartition;
048:
049: import org.jboss.system.ServiceMBeanSupport;
050:
051: import org.jboss.util.id.UID;
052:
053: // import org.jboss.util.collection.CompoundKey;
054:
055: /**
056: * This persistence manager work with an underlying HASessionState to get
057: * clustered state.
058: *
059: * @see HASessionState
060: * @see org.jboss.ha.hasessionstate.server.HASessionStateImpl
061: *
062: * @author <a href="mailto:sacha.labourey@cogito-info.ch">Sacha Labourey</a>
063: * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
064: * @version $Revision: 57188 $
065: *
066: * <p><b>Revisions:</b>
067: */
068:
069: public class StatefulHASessionPersistenceManager extends
070: ServiceMBeanSupport implements
071: StatefulSessionPersistenceManager,
072: HASessionState.HASessionStateListener, HAPersistentManager {
073:
074: /** Creates new StatefulHASessionPersistenceManager */
075: public StatefulHASessionPersistenceManager() {
076: }
077:
078: // Constants -----------------------------------------------------
079:
080: // Attributes ----------------------------------------------------
081:
082: private StatefulSessionContainer con;
083:
084: private HASessionState sessionState = null;
085:
086: private String localNodeName = null;
087: private String appName = null;
088:
089: // Static --------------------------------------------------------
090:
091: private static String DEFAULT_HASESSIONSTATE_JNDI_NAME = "/HASessionState/Default";
092:
093: // Constructors --------------------------------------------------
094:
095: // Public --------------------------------------------------------
096:
097: public void setContainer(Container c) {
098: con = (StatefulSessionContainer) c;
099: }
100:
101: protected void createService() throws Exception {
102: // Initialize the dataStore
103:
104: // Find HASessionState that we will use
105: //
106: String sessionStateName = org.jboss.metadata.ClusterConfigMetaData.DEFAULT_SESSION_STATE_NAME;
107: ClusterConfigMetaData config = con.getBeanMetaData()
108: .getClusterConfigMetaData();
109: if (config != null)
110: sessionStateName = config.getHaSessionStateName();
111:
112: Context ctx = new InitialContext();
113: try {
114: this .sessionState = (HASessionState) ctx
115: .lookup(sessionStateName);
116: } finally {
117: ctx.close();
118: }
119:
120: this .localNodeName = this .sessionState.getNodeName();
121: this .appName = this .con.getBeanMetaData().getJndiName();
122:
123: this .sessionState.subscribe(this .appName, this );
124: }
125:
126: protected void stopService() {
127: this .sessionState.unsubscribe(this .appName, this );
128: }
129:
130: public Object createId(StatefulSessionEnterpriseContext ctx)
131: throws Exception {
132: //
133: // jason: could probably use org.jboss.util.collection.CompoundKey here
134: // for better uniqueness based on hashCode and such...
135: //
136: // return new CompoundKey(this.localNodeName, new UID());
137: //
138: return this .localNodeName + ":" + new UID();
139: }
140:
141: public void createdSession(StatefulSessionEnterpriseContext ctx)
142: throws Exception {
143: this .sessionState.createSession(this .appName, ctx.getId());
144: }
145:
146: public void activateSession(StatefulSessionEnterpriseContext ctx)
147: throws RemoteException {
148: try {
149: ObjectInputStream in;
150:
151: // Load state
152: PackagedSession state = this .sessionState
153: .getStateWithOwnership(this .appName, ctx.getId());
154:
155: if (state == null)
156: throw new EJBException(
157: "Could not activate; failed to recover session (session has been probably removed by session-timeout)");
158:
159: in = new SessionObjectInputStream(ctx,
160: new ByteArrayInputStream(state.getState()));
161: ;
162:
163: ctx.setInstance(in.readObject());
164:
165: in.close();
166:
167: //removePassivated (ctx.getId ());
168:
169: // Instruct the bean to perform activation logic
170: ((SessionBean) ctx.getInstance()).ejbActivate();
171: } catch (ClassNotFoundException e) {
172: throw new EJBException("Could not activate", e);
173: } catch (IOException e) {
174: throw new EJBException("Could not activate", e);
175: }
176: }
177:
178: public void passivateSession(StatefulSessionEnterpriseContext ctx)
179: throws RemoteException {
180: // do nothing
181: }
182:
183: public void synchroSession(StatefulSessionEnterpriseContext ctx)
184: throws RemoteException {
185: try {
186: // Call bean
187: ((SessionBean) ctx.getInstance()).ejbPassivate();
188:
189: // Store state
190: ByteArrayOutputStream baos = new ByteArrayOutputStream();
191: ObjectOutputStream out = new SessionObjectOutputStream(baos);
192:
193: out.writeObject(ctx.getInstance());
194:
195: out.close();
196:
197: this .sessionState.setState(this .appName, ctx.getId(), baos
198: .toByteArray());
199:
200: ((SessionBean) ctx.getInstance()).ejbActivate(); //needed?
201: } catch (IOException e) {
202: throw new EJBException("Could not passivate", e);
203: }
204: }
205:
206: public void removeSession(StatefulSessionEnterpriseContext ctx)
207: throws RemoteException, RemoveException {
208: try {
209: // Call bean
210: ((SessionBean) ctx.getInstance()).ejbRemove();
211: } finally {
212: this .sessionState.removeSession(this .appName, ctx.getId());
213: }
214: }
215:
216: public void removePassivated(Object key) {
217: this .sessionState.removeSession(this .appName, key);
218: }
219:
220: // HASessionState.HASessionStateListener methods -----------------
221: //
222: public void sessionExternallyModified(PackagedSession session) {
223: // this callback warns us that a session (i.e. a bean) has been externally modified
224: // this means that we need to tell to our InstanceCache that this bean is no more under its control
225: // and that it should not keep a cached version of it => CACHE MISS
226: //
227: log
228: .trace("Invalidating cache for session: "
229: + session.getKey());
230: this .con.getInstanceCache().remove(session.getKey());
231: }
232:
233: public void newSessionStateTopology(HAPartition haSubPartition) {
234: }
235:
236: }
|