001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.core;
019:
020: import java.lang.ref.WeakReference;
021: import java.util.HashMap;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027: import java.util.Vector;
028:
029: import javax.servlet.http.HttpSessionBindingEvent;
030: import javax.servlet.http.HttpSessionBindingListener;
031:
032: import de.finix.contelligent.CallData;
033: import de.finix.contelligent.ComponentManager;
034: import de.finix.contelligent.ComponentPath;
035: import de.finix.contelligent.Contelligent;
036: import de.finix.contelligent.Session;
037: import de.finix.contelligent.clientsupport.ClientNotificator;
038: import de.finix.contelligent.core.security.ContelligentSecurityManager;
039: import de.finix.contelligent.core.security.ContelligentUser;
040: import de.finix.contelligent.core.security.RuntimePermissionTargets;
041: import de.finix.contelligent.core.security.SystemUser;
042: import de.finix.contelligent.core.security.User;
043: import de.finix.contelligent.event.EventQueueListener;
044: import de.finix.contelligent.exception.ContelligentRuntimeException;
045: import de.finix.contelligent.exception.ContelligentSecurityException;
046: import de.finix.contelligent.logging.LoggingService;
047: import de.finix.contelligent.util.ThreadedMem;
048:
049: public class ContelligentSession implements Session,
050: HttpSessionBindingListener {
051: final static org.apache.log4j.Logger log = LoggingService
052: .getLogger(ContelligentSession.class);
053:
054: private User user;
055:
056: private Map categoryMap;
057:
058: private Map sessionStore;
059:
060: private ComponentManager componentManager;
061:
062: private Map pageHistory;
063:
064: // most of all session will have no observer-session at all so we initialize
065: // the set
066: // of observers the first time it is used. (but we need a non-null object to
067: // sync on)
068: final private Object observerSessionMapLock = new Object();
069:
070: private HashMap observerSessionMap = null; // maps session-id to session
071:
072: // wrapped in WeakReference
073:
074: final private Object observedSessionKeysLock = new Object();
075:
076: /** contains the ids of the sessions observed by this session */
077: private HashSet observedSessionKeys = null;
078:
079: private int previewMode = PREVIEW;
080:
081: private ClientNotificator notificator;
082:
083: private boolean clientSession;
084:
085: private long workflowId = -1L;
086:
087: final private String id;
088:
089: final private Contelligent system;
090:
091: private boolean markedForLogout = false;
092:
093: public ContelligentSession(String sessionId,
094: ComponentManager manager, Contelligent system) {
095: categoryMap = new HashMap();
096: sessionStore = new HashMap();
097: pageHistory = new HashMap();
098: id = sessionId;
099: this .componentManager = manager;
100: this .system = system;
101: resetWorkflowId();
102: }
103:
104: public User getUser() {
105: return user;
106: }
107:
108: void setUser(User user) {
109: if (log.isDebugEnabled()) {
110: log.debug("setUser() - changing user in session from old='"
111: + this .user + "' --> new='" + user + "'");
112: }
113: if (!(user instanceof ContelligentUser || user instanceof SystemUser)) {
114: throw new ContelligentSecurityException(
115: "Unable to switch to insecure user class.");
116: }
117: if (!user.isAuthenticated()) {
118: throw new ContelligentSecurityException(
119: "Unable to switch to unauthenticated user.");
120: }
121: this .user = user;
122: }
123:
124: /*
125: * Filters out the system user if DO_AS_SYSTEM is not set.
126: */
127: public void setNamedUser(User user) {
128: User sysUser = ContelligentSecurityManager.getSystemUser();
129: if (sysUser.equals(user)) {
130: SecurityManager sm = System.getSecurityManager();
131: if (sm != null) {
132: sm.checkPermission(new RuntimePermission(
133: RuntimePermissionTargets.DO_AS_SYSTEM));
134: }
135: }
136: setUser(user);
137: }
138:
139: /**
140: * Reset the user to the guest user.
141: */
142: public void resetToGuest() {
143: setUser(ContelligentSecurityManager.getInstance().getGuest());
144: }
145:
146: /**
147: * Sets the path of actual page which will be returned by
148: * {@link #getCurrentPage}. Note that only the system should invoke this
149: * method.
150: *
151: * @param currentPage
152: * a <code>String</code> value
153: */
154: public synchronized void addCurrentPage(
155: final ComponentPath currentPage, String environment) {
156: int maxEnvironments = ContelligentImpl.getInstance()
157: .getMaxEnvironments();
158: int historyLimit = ContelligentImpl.getInstance()
159: .getHistoryLimit();
160: List localHistory;
161: if (pageHistory.containsKey(environment)) {
162: localHistory = (List) pageHistory.get(environment);
163: } else {
164: if (pageHistory.size() >= maxEnvironments) {
165: throw new ContelligentRuntimeException(
166: "Maximum number of history environments exceeded.");
167: }
168: localHistory = new Vector();
169: pageHistory.put(environment, localHistory);
170: }
171: localHistory.add(0, currentPage);
172: while (localHistory.size() > historyLimit) {
173: localHistory.remove(localHistory.size() - 1);
174: }
175: }
176:
177: public synchronized ComponentPath getHistoryPage(
178: String environment, int index) {
179: List localHistory = (List) pageHistory.get(environment);
180: if (localHistory == null) {
181: return null;
182: }
183: if (index >= localHistory.size()) {
184: index = localHistory.size() - 1;
185: }
186: ComponentPath currentPage = (ComponentPath) localHistory
187: .get(index);
188: return currentPage;
189: }
190:
191: /**
192: * Legacy method. Uses the new multidimensional page history to show the old
193: * (pre 9.1) current page information.
194: */
195: public synchronized ComponentPath getCurrentPage() {
196: CallData callData = ThreadedMem.getCallData();
197: String environment = callData.getEnvironment();
198: ComponentPath currentPage = getHistoryPage(environment, 0);
199: return currentPage;
200: }
201:
202: public void setCategoryMap(Map map) {
203: this .categoryMap = map;
204: }
205:
206: public Map getCategoryMap() {
207: return categoryMap;
208: }
209:
210: public Map getSessionStore() {
211: return sessionStore;
212: }
213:
214: public String toString() {
215: return ("ContelligentSession[" + user + "]");
216: }
217:
218: public void setComponentManager(ComponentManager mgr) {
219: this .componentManager = mgr;
220: }
221:
222: public ComponentManager getComponentManager() {
223: if (componentManager == null)
224: return ContelligentImpl.getInstance()
225: .getRootComponentManager();
226: return componentManager;
227: }
228:
229: public String getId() {
230: return id;
231: }
232:
233: public void setClientNotificator(ClientNotificator notificator) {
234: this .notificator = notificator;
235: }
236:
237: public ClientNotificator getClientNotificator() {
238: return notificator;
239: }
240:
241: public void addObserverSession(ContelligentSession session) {
242: synchronized (observerSessionMapLock) {
243: HashMap observersClone = ((observerSessionMap != null) ? (HashMap) observerSessionMap
244: .clone()
245: : new HashMap());
246: observersClone.put(session.getId(), new WeakReference(
247: session));
248: observerSessionMap = observersClone;
249: session.addObservedSessionKey(this .getId());
250: }
251: }
252:
253: public void removeObserverSession(ContelligentSession session) {
254: synchronized (observerSessionMapLock) {
255: if (observerSessionMap != null
256: && observerSessionMap.containsKey(session.getId())) {
257: HashMap observersClone = (HashMap) observerSessionMap
258: .clone();
259: observersClone.remove(session.getId());
260: observerSessionMap = observersClone;
261: session.removeObservedSessionKey(this .getId());
262: }
263: }
264: }
265:
266: /**
267: * Returns a <code>Set</code> of <code>String</code> instances, the ids
268: * of the sessions observed by this session of null if this session is not
269: * registered as an observer of any session.
270: *
271: * @return a <code>Set</code> value of <code>String</code> instances
272: */
273: Set getObservedSessionKeys() {
274: return observedSessionKeys;
275: }
276:
277: private void addObservedSessionKey(String observedSessionId) {
278: synchronized (observedSessionKeysLock) {
279: HashSet clone = ((observedSessionKeys != null) ? (HashSet) observedSessionKeys
280: .clone()
281: : new HashSet());
282: clone.add(observedSessionId);
283: observedSessionKeys = clone;
284: }
285: }
286:
287: private void removeObservedSessionKey(String observedSessionId) {
288: synchronized (observedSessionKeysLock) {
289: if (observedSessionKeys != null
290: && observedSessionKeys.contains(observedSessionId)) {
291: HashSet clone = (HashSet) observedSessionKeys.clone();
292: clone.remove(observedSessionId);
293: observedSessionKeys = clone;
294: }
295: }
296: }
297:
298: public boolean hasObserverSession() {
299: Map obs = observerSessionMap; // to avoid synchronization we copy the
300: // reference (reset() sets it to null)
301: return (obs != null && !obs.isEmpty());
302: }
303:
304: public boolean isClientSession() {
305: return clientSession;
306: }
307:
308: public void setClientSession(boolean flag) {
309: clientSession = flag;
310: }
311:
312: public void notifyObserverSessions(List eventList) {
313: Map obs = observerSessionMap; // to avoid synchronization we copy the
314: // reference (reset() sets it to null)
315: if (obs != null) {
316: Iterator iterator = obs.values().iterator();
317: while (iterator.hasNext()) {
318: Object session = ((WeakReference) iterator.next())
319: .get();
320: if (session != null) {
321: EventQueueListener listener = ((Session) session)
322: .getClientNotificator();
323: if (listener != null) {
324: listener.onEvents(eventList);
325: }
326: }
327: }
328: }
329: }
330:
331: public void setPreviewMode(int previewMode) {
332: this .previewMode = previewMode;
333: }
334:
335: public int getPreviewMode() {
336: return previewMode;
337: }
338:
339: /**
340: * Answer the current workflow context of this session.
341: *
342: * @return id of the current workflow
343: */
344: public long getWorkflowId() {
345: return workflowId;
346: }
347:
348: /**
349: * Set the current workflow context of this session.
350: *
351: * @param wfId
352: * id of the current workflow
353: */
354: public void setWorkflowId(long wfId) {
355: workflowId = wfId;
356: }
357:
358: public void valueBound(HttpSessionBindingEvent event) {
359: }
360:
361: public void valueUnbound(HttpSessionBindingEvent event) {
362: system.invalidateSession(this );
363: }
364:
365: public void resetWorkflowId() {
366: setWorkflowId(-1L);
367: }
368:
369: public void reset() {
370: setClientSession(false);
371: setClientNotificator(null);
372: resetToGuest();
373: resetWorkflowId();
374: observerSessionMap = null;
375: observedSessionKeys = null;
376: markedForLogout = false;
377: }
378:
379: void markForLogout() {
380: markedForLogout = true;
381: }
382:
383: public boolean isMarkedForLogout() {
384: return markedForLogout;
385: }
386:
387: }
|