All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openbp.server.context.SessionRegistryImpl Maven / Gradle / Ivy

There is a newer version: 0.9.11
Show newest version
/*
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package org.openbp.server.context;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.openbp.common.logger.LogUtil;
import org.openbp.common.util.DisposalListener;
import org.openbp.common.util.ExpirationHashtable;
import org.openbp.common.util.ToStringHelper;
import org.openbp.core.model.ModelQualifier;
import org.openbp.core.model.item.ItemTypes;
import org.openbp.core.model.item.process.NodeSocket;
import org.openbp.core.model.item.process.ProcessItem;
import org.openbp.core.model.modelmgr.ModelMgr;
import org.openbp.core.model.modelmgr.ModelNotificationObserver;
import org.openbp.core.model.modelmgr.ModelNotificationService;
import org.openbp.server.engine.EngineUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * The context manager keeps a store of the session context ({@link TokenContext})
 * for each session that has been opened.
 * Each context is identified by the session id.
* When context is created, it is also passed an expiration time, after which the context * will be removed from the store. The expiration time should be identical to the expiration * time of the session that created the context. * * @author Heiko Erhardt */ @Service("sessionRegistry") public class SessionRegistryImpl implements SessionRegistry, DisposalListener, ModelNotificationObserver { @Autowired private ModelMgr modelMgr; @Autowired ModelNotificationService modelNotificationService; /** Hashtable mapping session id's (Strings) to {@link TokenContext} objects */ private ExpirationHashtable contextMap; /** * Private constructor. */ public SessionRegistryImpl() { // Initialize session context map with a timeout of 10 x one hour. contextMap = new ExpirationHashtable(0); // Add a disposal listener for the hashtable. contextMap.setDisposalListener(this); } /** * Upon initialization, the class registers itself as model notification observer. */ @PostConstruct public void initialize() { modelNotificationService.addModelNotificationObserver(this); } /** * Returns a string represenation of this object. * * @return Debug string containing the most important properties of this object */ public String toString() { return ToStringHelper.toString(this); } /** * Gets a token context according to a session id. * If a valid context is found for this session, the access timestamp of the * context is updated, so it will remain in the store. * * @param sessionId Session id of the context * @return The context or null if no context exists for this session or the * context has timed out. */ public TokenContext lookupSession(Object sessionId) { return (TokenContext) contextMap.get(sessionId); } /** * Adds a context to the store. * * @param sessionId Id of the context * @param context Context to add * @param timeout Time in seconds that the context may remain inactive. * If this time has expired, the context will be removed from the session. */ public void registerSession(Object sessionId, TokenContext context, long timeout) { LogUtil.trace(getClass(), "Registered session id $0 (timeout: {1} sec). [{2}]", sessionId, new Long(timeout), context); // Store session context. contextMap.put(sessionId, context, timeout * 1000); LogUtil.debug(getClass(), "SessionRegistryImpl.registerSession called for session $0. Now maintaining $1 session(s).", sessionId, new Integer(contextMap.size())); // TODO Feature 4 Trigger session creation event } /** * Removes a session context with the given session id from the session map. * * @param sessionId Id of the context to unregister */ public void unregisterSession(Object sessionId) { // ...this should be told the session context, too. if (sessionId != null) { onDispose(sessionId); // ...remove the context from the map. contextMap.remove(sessionId); LogUtil.debug(getClass(), "SessionRegistryImpl.unregisterSession called. Now maintaining $0 session(s).", new Integer(contextMap.size())); } } /** * Removes a session context from the session map by searching the map for the context. * This method is much slower than the {@link #unregisterSession(Object)} method. * * @param context Context to remove */ public void unregisterSession(TokenContext context) { for (Iterator it = contextMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); TokenContext c = (TokenContext) entry.getValue(); if (c == context) { Object key = entry.getKey(); // ...this should be told the session context, too. onDispose(key); // ...remove the context from the map. it.remove(); break; } } LogUtil.debug(getClass(), "SessionRegistryImpl.unregisterSession called. Now maintaining $0 session(s).", new Integer(contextMap.size())); } ////////////////////////////////////////////////// // @@ ModelNotificationObserver implementation ////////////////////////////////////////////////// /** * Notification method for model updates. * * @param qualifier Qualifier of the object that has been updated * @param mode Type of model update ({@link ModelNotificationService#ADDED}/{@link ModelNotificationService#UPDATED}/{@link ModelNotificationService#REMOVED}) */ public void modelUpdated(ModelQualifier qualifier, int mode) { boolean ret = false; if (qualifier.getItem() != null && ItemTypes.PROCESS.equals(qualifier.getItemType())) { ProcessItem process = (ProcessItem) modelMgr.getItemByQualifier(qualifier, true); if (process != null) { for (Enumeration en = contextMap.elements(); en.hasMoreElements();) { TokenContext context = (TokenContext) en.nextElement(); ret &= performProcessUpdateOnContext(context, process); } } } } /** * Resets all models. * Re-initializes the model classloader and the model properties and reinitializes the components of the model. */ public void requestModelReset() { } ////////////////////////////////////////////////// // @@ Process updates ////////////////////////////////////////////////// /** * Checks if we reference any sockets of the supplied process and refreshes * the socket reference if appropriate. * * @param context Token context * @param process * Updated process * @return true All updates have been performed successfully.\n false The * context references one or more sockets that do not exist any more * in the updated process. */ public boolean performProcessUpdateOnContext(TokenContext context, ProcessItem process) { boolean result = true; // First, give the call stack a chance to update itself. if (!context.getCallStack().performProcessUpdate(process)) result = false; // Second, try to update current position. NodeSocket currentSocket = context.getCurrentSocket(); if (currentSocket != null && currentSocket.getProcess() == process) { NodeSocket newSocket = EngineUtil.updateSocketReference(currentSocket, process); if (newSocket != null) { currentSocket = newSocket; } else { result = false; } } for (Iterator it = context.getChildContexts(); it.hasNext();) { TokenContext cc = (TokenContext) it.next(); performProcessUpdateOnContext(cc, process); } return result; } /** * Requests the termination of processes that are debugged by the specified debugger. * * @param debuggerId Debugger client id */ public void requestSessionAbort(String debuggerId) { for (Enumeration en = contextMap.keys(); en.hasMoreElements();) { // Get the key... Object key = en.nextElement(); // ...and the token context. TokenContext context = (TokenContext) contextMap.get(key); // ...and compare the debugger id with the passed one. if (debuggerId.equals(context.getDebuggerId())) { // Remove the context from the map. contextMap.remove(key); // Request termination. TokenContextUtil.requestTermination(context); } } } /** * For toString debugging only. */ protected ExpirationHashtable getContextMap() { return contextMap; } ////////////////////////////////////////////////// // @@ DisposalListener ////////////////////////////////////////////////// /** * This method is called when a session is removed from the TokenContextMgrImpl, either * explicitly or by expiration. * * @param key The session id */ public void onDispose(Object key) { // Get the corresponding session. if (key != null) { // TokenContext context = (TokenContext) contextMap.get(key); // TODO Feature 4 Trigger session destroy event } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy