Presentation is loading. Please wait.

Presentation is loading. Please wait.

Problems of Object-Oriented Design and Implementation

Similar presentations


Presentation on theme: "Problems of Object-Oriented Design and Implementation"— Presentation transcript:

1 Problems of Object-Oriented Design and Implementation
Ideas, Pretty Pictures, and Examples from OOPSLA 93 Presentation on “Subject-Oriented Programming (A Critique of Pure Objects)” by Harrison & Ossher AOSD 03 Presentation on “Aspect-Oriented Programming” by Gregor Kiczales and many more …

2 One Object: Several Views
Class: Tree Attributes Height Weight Cell-count Leaf-mass Operations Growth Photosynthesis Class: Tree Attributes SalePrice TimeToCut Operations ComputeProfit Class: Tree Attributes FoodValue Operations ComputeFlight Class: Tree Attributes AssessedValue Operations EstimateValue ComputeTax From OOPSLA 93 Presentation on “Subject-Oriented Programming (A Critique of Pure Objects)” by Harrison & Ossher

3 Solution? Attempt to Solution?
Treat all extrinsic information as intrinsic One big nice giant class “Tree” Looks and smells like a “blob” Live without encapsulation & polymorphism Consider different views

4 Weakness in OO development
Non-invasive system extension and evolution Without modifying original source Large-scale reuse and integration Without significant preplanning System decomposition By-feature; by-requirement as well as by-object Multi-team/decentralized development Without agreeing a single domain model

5 Two subjects (bird and woodsman)
nectar plant Insect nestable predator object maple cherry pine dandelion bird woodsman hardwood softwood tree nontree (Two class hierarchies over the same instantiable objects) From OOPSLA 93 Presentation on “Subject-Oriented Programming (A Critique of Pure Objects)” by Harrison & Ossher

6 Non-Modular OO Implementations
/* * * ==================================================================== * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * reserved. * Copyright (c) 1999 The Apache Software Foundation. All rights * The Apache Software License, Version 1.1 * 1. Redistributions of source code must retain the above copyright * are met: * the documentation and/or other materials provided with the * distribution. * notice, this list of conditions and the following disclaimer in * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer. itself, * if and wherever such third-party acknowlegements normally appear. * Apache Software Foundation ( * Alternately, this acknowlegement may appear in the software * "This product includes software developed by the * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * Foundation" must not be used to endorse or promote products * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * 5. Products derived from this software may not be called "Apache" * permission, please contact derived * from this software without prior written permission. For written * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * This software consists of voluntary contributions made by many * SUCH DAMAGE. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * information on the Apache Software Foundation, please see * individuals on behalf of the Apache Software Foundation. For more * [Additional notices, if required by prior licensing conditions] */ * < package org.apache.tomcat.session; import java.net.*; import java.util.*; import java.io.*; import org.apache.tomcat.util.StringManager; import org.apache.tomcat.core.*; * Core implementation of an application level session James Duncan Davidson /** import javax.servlet.http.*; import javax.servlet.*; James Todd Jason Hunter private String id; private Hashtable values = new Hashtable(); private StringManager sm = public class ApplicationSession implements HttpSession { StringManager.getManager("org.apache.tomcat.session"); private ServerSession serverSession; private boolean valid = true; private int inactiveInterval = -1; private long lastAccessed = creationTime; private Context context; private long creationTime = System.currentTimeMillis();; private long thisAccessTime = creationTime; this.inactiveInterval = context.getSessionTimeOut(); this.context = context; this.id = id; Context context) { ApplicationSession(String id, ServerSession serverSession, this.serverSession = serverSession; } this.inactiveInterval *= 60; if (this.inactiveInterval != -1) { return serverSession; ServerSession getServerSession() { * inactivities can be dealt with accordingly. * Called by context when request comes in so that accesses and void accessed() { thisAccessTime = System.currentTimeMillis(); lastAccessed = thisAccessTime; // set last accessed to thisAccessTime as it will be left over // from the previous access int thisInterval = if (inactiveInterval != -1) { void validate() { validate(); invalidate(); if (thisInterval > inactiveInterval) { (int)(System.currentTimeMillis() - lastAccessed) / 1000; // if we have an inactive interval, check to see if we've exceeded it if (valid) { // HTTP SESSION IMPLEMENTATION METHODS String msg = sm.getString("applicationSession.session.ise"); public String getId() { throw new IllegalStateException(msg); } else { return id; return creationTime; public long getCreationTime() { public long getLastAccessedTime() { return new SessionContextImpl(); public HttpSessionContext getSessionContext() { return lastAccessed; public void invalidate() { // remove everything in the session serverSession.removeApplicationSession(context); removeValue(name); String name = (String)enum.nextElement(); Enumeration enum = values.keys(); while (enum.hasMoreElements()) { public boolean isNew() { valid = false; if (! valid) { return true; return false; if (thisAccessTime == creationTime) { public void setAttribute(String name, Object value) { setAttribute(name, value); public void putValue(String name, Object value) { removeValue(name); // remove any existing binding throw new IllegalArgumentException(msg); String msg = sm.getString("applicationSession.value.iae"); if (name == null) { new HttpSessionBindingEvent(this, name); ((HttpSessionBindingListener)value).valueBound(e); HttpSessionBindingEvent e = if (value != null && value instanceof HttpSessionBindingListener) { values.put(name, value); public Object getAttribute(String name) { return getAttribute(name); public Object getValue(String name) { return values.get(name); public String[] getValueNames() { names.addElement(e.nextElement()); while (e.hasMoreElements()) { Vector names = new Vector(); Enumeration e = getAttributeNames(); names.copyInto(valueNames); String[] valueNames = new String[names.size()]; public Enumeration getAttributeNames() { return valueNames; return (Enumeration)valuesClone.keys(); Hashtable valuesClone = (Hashtable)values.clone(); public void removeAttribute(String name) { removeAttribute(name); public void removeValue(String name) { Object o = values.get(name); ((HttpSessionBindingListener)o).valueUnbound(e); new HttpSessionBindingEvent(this,name); if (o instanceof HttpSessionBindingListener) { public void setMaxInactiveInterval(int interval) { values.remove(name); public int getMaxInactiveInterval() { inactiveInterval = interval; return inactiveInterval; // ; * Standard implementation of the <b>Session</b> interface. This object is /** * <b>IMPLEMENTATION NOTE</b>: An instance of this class represents both the * <p> * to a different JVM for distributable session support. * serializable, so that it can be stored in persistent storage or transferred * internal (Session) and application level (HttpSession) view of the session. Craig R. McClanahan * * HttpSession view of this instance back to a Session view. * However, because the class itself is not declared public, Java logic outside * of the <code>org.apache.tomcat.session</code> package cannot cast an $Revision: 1.2 $ $Date: 2000/05/15 17:54:10 $ // Constructors implements HttpSession, Session { */ final class StandardSession manager The manager with which this Session is associated * Construct a new Session associated with the specified Manager. this.manager = manager; } super(); public StandardSession(Manager manager) { private long lastAccessedTime = creationTime; * The last accessed time for this Session. * The maximum time interval, in seconds, between client requests before private Manager manager = null; * The Manager with which this Session is associated. private int maxInactiveInterval = -1; * indicates that the session should never time out. * the servlet container may invalidate this session. A negative time private boolean isNew = true; * Flag indicating whether this session is new or not. * Flag indicating whether this session is valid or not. private boolean isValid = false; private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); * The string manager for this package. private static HttpSessionContext sessionContext = null; * The HTTP session context associated with this session. private long thisAccessedTime = creationTime; * The current accessed time for this session. // Session Properties * Set the creation time for this session. This method is called by the time The new creation time * Manager when an existing Session instance is reused. this.thisAccessedTime = time; this.lastAccessedTime = time; public void setCreationTime(long time) { this.creationTime = time; public String getId() { * Return the session identifier for this session. return (this.id); id The new session identifier * Set the session identifier for this session. public void setId(String id) { if ((this.id != null) && (manager != null) && if ((manager != null) && (manager instanceof ManagerBase)) this.id = id; (manager instanceof ManagerBase)) ((ManagerBase) manager).remove(this); ((ManagerBase) manager).add(this); * Return descriptive information about this Session implementation and public String getInfo() { * <code><description>/<version></code>. * the corresponding version number, in the format return (this.info); * Return the last time the client sent a request associated with this * a value associated with the session, do not affect the access time. * GMT. Actions that your application takes, such as getting or setting * session, as the number of milliseconds since midnight, January 1, 1970 return (this.lastAccessedTime); public long getLastAccessedTime() { * Return the Manager within which this Session is valid. return (this.manager); public Manager getManager() { public void setManager(Manager manager) { manager The new Manager * Set the Manager within which this Session is valid. * time indicates that the session should never time out. * before the servlet container will invalidate the session. A negative * Return the maximum time interval, in seconds, between client requests public int getMaxInactiveInterval() { * an invalidated session IllegalStateException if this method is called on return (this.maxInactiveInterval); * Update the accessed time information for this session. This method * should be called by the context when a request comes in for a particular this.thisAccessedTime = System.currentTimeMillis(); this.lastAccessedTime = this.thisAccessedTime; public void access() { * session, even if the application does not reference it. this.isNew=false; public void expire() { * without triggering an exception if the session has already expired. * Perform the internal processing required to invalidate this session, // Remove this session from our manager's active sessions String attr = (String) attrs.nextElement(); while (attrs.hasMoreElements()) { Enumeration attrs = getAttributeNames(); // Unbind any objects associated with this session Vector results = new Vector(); while (names.hasMoreElements()) { removeAttribute(name); String name = (String) names.nextElement(); Enumeration names = results.elements(); results.addElement(attr); setValid(false); // Mark this session as invalid isNew The new value for the <code>isNew</code> flag * Set the <code>isNew</code> flag for this session. void setNew(boolean isNew) { this.isNew = isNew; void setValid(boolean isValid) { isValid The new value for the <code>isValid</code> flag * Set the <code>isValid</code> flag for this session. // HttpSession Properties this.isValid = isValid; IllegalStateException if this method is called on an * midnight, January 1, 1970 GMT. * Return the time when this session was created, in milliseconds since return (this.creationTime); public long getCreationTime() { * invalidated session * replacement. It will be removed in a future version of the As of Version 2.1, this method is deprecated and has no * Return the session context with which this session is associated. * Java Servlet API. sessionContext = new StandardSessionContext(); return (sessionContext); if (sessionContext == null) public HttpSessionContext getSessionContext() { // HttpSession Public Methods * Return the object bound with the specified name in this session, or name Name of the attribute to be returned * <code>null</code> if no object is bound with that name. return (attributes.get(name)); public Object getAttribute(String name) { * containing the names of the objects bound to this session. * Return an <code>Enumeration</code> of <code>String</code> objects return (attributes.keys()); public Enumeration getAttributeNames() { name Name of the value to be returned As of Version 2.2, this method is replaced by return (getAttribute(name)); public Object getValue(String name) { * <code>getAttribute()</code> * are no such objects, a zero-length array is returned. * Return the set of names of objects bound to this session. If there public String[] getValueNames() { * <code>getAttributeNames()</code> return (names); names[i] = (String) results.elementAt(i); for (int i = 0; i < names.length; i++) String names[] = new String[results.size()]; * Invalidates this session and unbinds any objects bound to it. expire(); // Cause this session to expire public void invalidate() { * example, if the server used only cookie-based sessions, and the client * session, or if the client chooses not to join the session. For * Return <code>true</code> if the client does not yet know about the * request. * has disabled the use of cookies, then a session would be new on each return (this.isNew); public boolean isNew() { * Remove the object bound with the specified name from this session. If * After this method executes, and if the object implements * does nothing. * the session does not have an object bound with this name, this method * <code>valueUnbound()</code> on the object. name Name of the object to remove from this session. * <code>HttpSessionBindingListener</code>, the container calls synchronized (attributes) { Object object = attributes.get(name); public void removeAttribute(String name) { ((HttpSessionBindingListener) object).valueUnbound (new HttpSessionBindingEvent((HttpSession) this, name)); if (object instanceof HttpSessionBindingListener) { // System.out.println( "Removing attribute " + name ); if (object == null) return; attributes.remove(name); * replaced. * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is value Object to be bound, cannot be null * <code>valueBound()</code> on the object. name Name to which the object is bound, cannot be null * non-serializable object in an environment marked distributable. IllegalArgumentException if an attempt is made to add a throw new IllegalArgumentException public void setAttribute(String name, Object value) { attributes.put(name, value); (sm.getString("standardSession.setAttribute.iae")); if ((manager != null) && manager.getDistributable() && !(value instanceof Serializable)) ((HttpSessionBindingListener) value).valueBound if (value instanceof HttpSessionBindingListener) // HttpSession Private Methods stream The input stream to read from * is not restored by this method, and must be set explicitly. * <b>IMPLEMENTATION NOTE</b>: The reference to the owning Manager * object input stream. * Read a serialized version of this session object from the specified IOException if an input/output error occurs ClassNotFoundException if an unknown class is specified id = (String) stream.readObject(); lastAccessedTime = ((Long) stream.readObject()).longValue(); creationTime = ((Long) stream.readObject()).longValue(); // Deserialize the scalar instance variables (except Manager) private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { isNew = ((Boolean) stream.readObject()).booleanValue(); maxInactiveInterval = ((Integer) stream.readObject()).intValue(); String name = (String) stream.readObject(); Object value = (Object) stream.readObject(); for (int i = 0; i < n; i++) { int n = ((Integer) stream.readObject()).intValue(); // Deserialize the attribute count and attribute values isValid = ((Boolean) stream.readObject()).booleanValue(); * object output stream. * Write a serialized version of this session object to the specified * explicitly. * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable * <code>readObject()</code>, you must set the associated Manager * in the serialized representation of this Session. After calling * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored * Manager is set to <code>true</code>. stream The output stream to write to * be sure the <code>distributable</code> property of our associated * will be silently ignored. If you do not want any such attributes, stream.writeObject(new Long(creationTime)); stream.writeObject(id); // Write the scalar instance variables (except Manager) private void writeObject(ObjectOutputStream stream) throws IOException { stream.writeObject(new Boolean(isNew)); // Accumulate the names of serializable attributes stream.writeObject(new Boolean(isValid)); stream.writeObject(new Integer(maxInactiveInterval)); stream.writeObject(new Long(lastAccessedTime)); if (value instanceof Serializable) Object value = attributes.get(attr); stream.writeObject(new Integer(results.size())); // Serialize the attribute count and the attribute values stream.writeObject(attributes.get(name)); stream.writeObject(name); Enumeration getAttributeNames() | String[] getValueNames() | Object getAttribute(String) | long getCreationTime() | crosscut invalidate(StandardSession s): s & (int getMaxInactiveInterval() | static advice(StandardSession s): invalidate(s) { before { void setAttribute(String, Object)); void removeAttribute(String) | void invalidate() | boolean isNew() | + ".ise")); (s.sm.getString("standardSession." + thisJoinPoint.methodName throw new IllegalStateException if (!s.isValid()) // Private Class * when <code>HttpSession.getSessionContext()</code> is called. * This class is a dummy implementation of the <code>HttpSessionContext</code> * interface, to conform to the requirement that such an object be returned As of Java Servlet API 2.1 with no replacement. The private Vector dummy = new Vector(); final class StandardSessionContext implements HttpSessionContext { * interface will be removed in a future version of this API. * This method must return an empty <code>Enumeration</code> As of Java Servlet API 2.1 with no replacement. * within this context. * Return the session identifiers of all sessions defined * and will be removed in a future version of the API. return (dummy.elements()); public Enumeration getIds() { * This method must return null and will be removed in a id Session identifier for which to look up a session * specified session identifier. * Return the <code>HttpSession</code> associated with the public HttpSession getSession(String id) { * future version of the API. return (null); A high-level view of a software System Also called the SeeSoft View of the Software System Blue Lines represent the code implementing a single feature/concern/requirement package org.apache.tomcat.session; import org.apache.tomcat.core.*; import javax.servlet.http.*; import javax.servlet.*; import java.util.*; import org.apache.tomcat.util.StringManager; import java.io.*; import java.net.*; James Duncan Davidson public class ServerSession { */ James Todd * /** * Core implementation of a server session private String id; private long thisAccessTime = creationTime; private long creationTime = System.currentTimeMillis();; private Hashtable appSessions = new Hashtable(); private Hashtable values = new Hashtable(); private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); ServerSession(String id) { private long lastAccessed = creationTime; private int inactiveInterval = -1; return id; public String getId() { } this.id = id; public long getLastAccessedTime() { return creationTime; public long getCreationTime() { (ApplicationSession)appSessions.get(context); ApplicationSession appSession = public ApplicationSession getApplicationSession(Context context, return lastAccessed; boolean create) { // XXX if (appSession == null && create) { appSession = new ApplicationSession(id, this, context); appSessions.put(context, appSession); // sync to ensure valid? return appSession; // a new appSession // make sure that we haven't gone over the end of our // inactive interval -- if so, invalidate and create appSessions.remove(context); void removeApplicationSession(Context context) { * inactivities can be dealt with accordingly. * Called by context when request comes in so that accesses and thisAccessTime = System.currentTimeMillis(); lastAccessed = thisAccessTime; // from the previous access void accessed() { // set last accessed to thisAccessTime as it will be left over void validate() void validate() { (int)(System.currentTimeMillis() - lastAccessed) / 1000; int thisInterval = if (inactiveInterval != -1) { // if we have an inactive interval, check to see if // we've exceeded it if (thisInterval > inactiveInterval) { ssm.removeSession(this); ServerSessionManager.getManager(); invalidate(); ServerSessionManager ssm = (ApplicationSession)appSessions.get(key); Object key = enum.nextElement(); while (enum.hasMoreElements()) { Enumeration enum = appSessions.keys(); synchronized void invalidate() { appSession.invalidate(); String msg = sm.getString("serverSession.value.iae"); throw new IllegalArgumentException(msg); if (name == null) { public void putValue(String name, Object value) { removeValue(name); // remove any existing binding public Object getValue(String name) { values.put(name, value); return values.keys(); public Enumeration getValueNames() { return values.get(name); public void setMaxInactiveInterval(int interval) { values.remove(name); public void removeValue(String name) { public int getMaxInactiveInterval() { inactiveInterval = interval; // solution for this, but we'll determine something else later. // from this while we are reaping. This isn't the most optimal // sync'd for safty -- no other thread should be getting something return inactiveInterval; synchronized void reap() { appSession.validate(); Based on Gregor Kiczales’s AOSD 2003.

7 Examples Execution tracing policy Cross-module optimization
Use of common thread pool Security policy enforcement Component integration

8 Consequences Faulty software due to inconsistencies
Costly time-consuming development [Brooks] Costly and undependable software evolution /* * * ==================================================================== * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * reserved. * Copyright (c) 1999 The Apache Software Foundation. All rights * The Apache Software License, Version 1.1 * 1. Redistributions of source code must retain the above copyright * are met: * the documentation and/or other materials provided with the * distribution. * notice, this list of conditions and the following disclaimer in * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer. itself, * if and wherever such third-party acknowlegements normally appear. * Apache Software Foundation ( * Alternately, this acknowlegement may appear in the software * "This product includes software developed by the * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * Foundation" must not be used to endorse or promote products * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * 5. Products derived from this software may not be called "Apache" * permission, please contact derived * from this software without prior written permission. For written * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * This software consists of voluntary contributions made by many * SUCH DAMAGE. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * information on the Apache Software Foundation, please see * individuals on behalf of the Apache Software Foundation. For more * [Additional notices, if required by prior licensing conditions] */ * < package org.apache.tomcat.session; import java.net.*; import java.util.*; import java.io.*; import org.apache.tomcat.util.StringManager; import org.apache.tomcat.core.*; * Core implementation of an application level session James Duncan Davidson /** import javax.servlet.http.*; import javax.servlet.*; James Todd Jason Hunter private String id; private Hashtable values = new Hashtable(); private StringManager sm = public class ApplicationSession implements HttpSession { StringManager.getManager("org.apache.tomcat.session"); private ServerSession serverSession; private boolean valid = true; private int inactiveInterval = -1; private long lastAccessed = creationTime; private Context context; private long creationTime = System.currentTimeMillis();; private long thisAccessTime = creationTime; this.inactiveInterval = context.getSessionTimeOut(); this.context = context; this.id = id; Context context) { ApplicationSession(String id, ServerSession serverSession, this.serverSession = serverSession; } this.inactiveInterval *= 60; if (this.inactiveInterval != -1) { return serverSession; ServerSession getServerSession() { * inactivities can be dealt with accordingly. * Called by context when request comes in so that accesses and void accessed() { thisAccessTime = System.currentTimeMillis(); lastAccessed = thisAccessTime; // set last accessed to thisAccessTime as it will be left over // from the previous access int thisInterval = if (inactiveInterval != -1) { void validate() { validate(); invalidate(); if (thisInterval > inactiveInterval) { (int)(System.currentTimeMillis() - lastAccessed) / 1000; // if we have an inactive interval, check to see if we've exceeded it if (valid) { // HTTP SESSION IMPLEMENTATION METHODS String msg = sm.getString("applicationSession.session.ise"); public String getId() { throw new IllegalStateException(msg); } else { return id; return creationTime; public long getCreationTime() { public long getLastAccessedTime() { return new SessionContextImpl(); public HttpSessionContext getSessionContext() { return lastAccessed; public void invalidate() { // remove everything in the session serverSession.removeApplicationSession(context); removeValue(name); String name = (String)enum.nextElement(); Enumeration enum = values.keys(); while (enum.hasMoreElements()) { public boolean isNew() { valid = false; if (! valid) { return true; return false; if (thisAccessTime == creationTime) { public void setAttribute(String name, Object value) { setAttribute(name, value); public void putValue(String name, Object value) { removeValue(name); // remove any existing binding throw new IllegalArgumentException(msg); String msg = sm.getString("applicationSession.value.iae"); if (name == null) { new HttpSessionBindingEvent(this, name); ((HttpSessionBindingListener)value).valueBound(e); HttpSessionBindingEvent e = if (value != null && value instanceof HttpSessionBindingListener) { values.put(name, value); public Object getAttribute(String name) { return getAttribute(name); public Object getValue(String name) { return values.get(name); public String[] getValueNames() { names.addElement(e.nextElement()); while (e.hasMoreElements()) { Vector names = new Vector(); Enumeration e = getAttributeNames(); names.copyInto(valueNames); String[] valueNames = new String[names.size()]; public Enumeration getAttributeNames() { return valueNames; return (Enumeration)valuesClone.keys(); Hashtable valuesClone = (Hashtable)values.clone(); public void removeAttribute(String name) { removeAttribute(name); public void removeValue(String name) { Object o = values.get(name); ((HttpSessionBindingListener)o).valueUnbound(e); new HttpSessionBindingEvent(this,name); if (o instanceof HttpSessionBindingListener) { public void setMaxInactiveInterval(int interval) { values.remove(name); public int getMaxInactiveInterval() { inactiveInterval = interval; return inactiveInterval; // ; * Standard implementation of the <b>Session</b> interface. This object is /** * <b>IMPLEMENTATION NOTE</b>: An instance of this class represents both the * <p> * to a different JVM for distributable session support. * serializable, so that it can be stored in persistent storage or transferred * internal (Session) and application level (HttpSession) view of the session. Craig R. McClanahan * * HttpSession view of this instance back to a Session view. * However, because the class itself is not declared public, Java logic outside * of the <code>org.apache.tomcat.session</code> package cannot cast an $Revision: 1.2 $ $Date: 2000/05/15 17:54:10 $ // Constructors implements HttpSession, Session { */ final class StandardSession manager The manager with which this Session is associated * Construct a new Session associated with the specified Manager. this.manager = manager; } super(); public StandardSession(Manager manager) { private long lastAccessedTime = creationTime; * The last accessed time for this Session. * The maximum time interval, in seconds, between client requests before private Manager manager = null; * The Manager with which this Session is associated. private int maxInactiveInterval = -1; * indicates that the session should never time out. * the servlet container may invalidate this session. A negative time private boolean isNew = true; * Flag indicating whether this session is new or not. * Flag indicating whether this session is valid or not. private boolean isValid = false; private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); * The string manager for this package. private static HttpSessionContext sessionContext = null; * The HTTP session context associated with this session. private long thisAccessedTime = creationTime; * The current accessed time for this session. // Session Properties * Set the creation time for this session. This method is called by the time The new creation time * Manager when an existing Session instance is reused. this.thisAccessedTime = time; this.lastAccessedTime = time; public void setCreationTime(long time) { this.creationTime = time; public String getId() { * Return the session identifier for this session. return (this.id); id The new session identifier * Set the session identifier for this session. public void setId(String id) { if ((this.id != null) && (manager != null) && if ((manager != null) && (manager instanceof ManagerBase)) this.id = id; (manager instanceof ManagerBase)) ((ManagerBase) manager).remove(this); ((ManagerBase) manager).add(this); * Return descriptive information about this Session implementation and public String getInfo() { * <code><description>/<version></code>. * the corresponding version number, in the format return (this.info); * Return the last time the client sent a request associated with this * a value associated with the session, do not affect the access time. * GMT. Actions that your application takes, such as getting or setting * session, as the number of milliseconds since midnight, January 1, 1970 return (this.lastAccessedTime); public long getLastAccessedTime() { * Return the Manager within which this Session is valid. return (this.manager); public Manager getManager() { public void setManager(Manager manager) { manager The new Manager * Set the Manager within which this Session is valid. * time indicates that the session should never time out. * before the servlet container will invalidate the session. A negative * Return the maximum time interval, in seconds, between client requests public int getMaxInactiveInterval() { * an invalidated session IllegalStateException if this method is called on return (this.maxInactiveInterval); * Update the accessed time information for this session. This method * should be called by the context when a request comes in for a particular this.thisAccessedTime = System.currentTimeMillis(); this.lastAccessedTime = this.thisAccessedTime; public void access() { * session, even if the application does not reference it. this.isNew=false; public void expire() { * without triggering an exception if the session has already expired. * Perform the internal processing required to invalidate this session, // Remove this session from our manager's active sessions String attr = (String) attrs.nextElement(); while (attrs.hasMoreElements()) { Enumeration attrs = getAttributeNames(); // Unbind any objects associated with this session Vector results = new Vector(); while (names.hasMoreElements()) { removeAttribute(name); String name = (String) names.nextElement(); Enumeration names = results.elements(); results.addElement(attr); setValid(false); // Mark this session as invalid isNew The new value for the <code>isNew</code> flag * Set the <code>isNew</code> flag for this session. void setNew(boolean isNew) { this.isNew = isNew; void setValid(boolean isValid) { isValid The new value for the <code>isValid</code> flag * Set the <code>isValid</code> flag for this session. // HttpSession Properties this.isValid = isValid; IllegalStateException if this method is called on an * midnight, January 1, 1970 GMT. * Return the time when this session was created, in milliseconds since return (this.creationTime); public long getCreationTime() { * invalidated session * replacement. It will be removed in a future version of the As of Version 2.1, this method is deprecated and has no * Return the session context with which this session is associated. * Java Servlet API. sessionContext = new StandardSessionContext(); return (sessionContext); if (sessionContext == null) public HttpSessionContext getSessionContext() { // HttpSession Public Methods * Return the object bound with the specified name in this session, or name Name of the attribute to be returned * <code>null</code> if no object is bound with that name. return (attributes.get(name)); public Object getAttribute(String name) { * containing the names of the objects bound to this session. * Return an <code>Enumeration</code> of <code>String</code> objects return (attributes.keys()); public Enumeration getAttributeNames() { name Name of the value to be returned As of Version 2.2, this method is replaced by return (getAttribute(name)); public Object getValue(String name) { * <code>getAttribute()</code> * are no such objects, a zero-length array is returned. * Return the set of names of objects bound to this session. If there public String[] getValueNames() { * <code>getAttributeNames()</code> return (names); names[i] = (String) results.elementAt(i); for (int i = 0; i < names.length; i++) String names[] = new String[results.size()]; * Invalidates this session and unbinds any objects bound to it. expire(); // Cause this session to expire public void invalidate() { * example, if the server used only cookie-based sessions, and the client * session, or if the client chooses not to join the session. For * Return <code>true</code> if the client does not yet know about the * request. * has disabled the use of cookies, then a session would be new on each return (this.isNew); public boolean isNew() { * Remove the object bound with the specified name from this session. If * After this method executes, and if the object implements * does nothing. * the session does not have an object bound with this name, this method * <code>valueUnbound()</code> on the object. name Name of the object to remove from this session. * <code>HttpSessionBindingListener</code>, the container calls synchronized (attributes) { Object object = attributes.get(name); public void removeAttribute(String name) { ((HttpSessionBindingListener) object).valueUnbound (new HttpSessionBindingEvent((HttpSession) this, name)); if (object instanceof HttpSessionBindingListener) { // System.out.println( "Removing attribute " + name ); if (object == null) return; attributes.remove(name); * replaced. * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is value Object to be bound, cannot be null * <code>valueBound()</code> on the object. name Name to which the object is bound, cannot be null * non-serializable object in an environment marked distributable. IllegalArgumentException if an attempt is made to add a throw new IllegalArgumentException public void setAttribute(String name, Object value) { attributes.put(name, value); (sm.getString("standardSession.setAttribute.iae")); if ((manager != null) && manager.getDistributable() && !(value instanceof Serializable)) ((HttpSessionBindingListener) value).valueBound if (value instanceof HttpSessionBindingListener) // HttpSession Private Methods stream The input stream to read from * is not restored by this method, and must be set explicitly. * <b>IMPLEMENTATION NOTE</b>: The reference to the owning Manager * object input stream. * Read a serialized version of this session object from the specified IOException if an input/output error occurs ClassNotFoundException if an unknown class is specified id = (String) stream.readObject(); lastAccessedTime = ((Long) stream.readObject()).longValue(); creationTime = ((Long) stream.readObject()).longValue(); // Deserialize the scalar instance variables (except Manager) private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { isNew = ((Boolean) stream.readObject()).booleanValue(); maxInactiveInterval = ((Integer) stream.readObject()).intValue(); String name = (String) stream.readObject(); Object value = (Object) stream.readObject(); for (int i = 0; i < n; i++) { int n = ((Integer) stream.readObject()).intValue(); // Deserialize the attribute count and attribute values isValid = ((Boolean) stream.readObject()).booleanValue(); * object output stream. * Write a serialized version of this session object to the specified * explicitly. * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable * <code>readObject()</code>, you must set the associated Manager * in the serialized representation of this Session. After calling * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored * Manager is set to <code>true</code>. stream The output stream to write to * be sure the <code>distributable</code> property of our associated * will be silently ignored. If you do not want any such attributes, stream.writeObject(new Long(creationTime)); stream.writeObject(id); // Write the scalar instance variables (except Manager) private void writeObject(ObjectOutputStream stream) throws IOException { stream.writeObject(new Boolean(isNew)); // Accumulate the names of serializable attributes stream.writeObject(new Boolean(isValid)); stream.writeObject(new Integer(maxInactiveInterval)); stream.writeObject(new Long(lastAccessedTime)); if (value instanceof Serializable) Object value = attributes.get(attr); stream.writeObject(new Integer(results.size())); // Serialize the attribute count and the attribute values stream.writeObject(attributes.get(name)); stream.writeObject(name); Enumeration getAttributeNames() | String[] getValueNames() | Object getAttribute(String) | long getCreationTime() | crosscut invalidate(StandardSession s): s & (int getMaxInactiveInterval() | static advice(StandardSession s): invalidate(s) { before { void setAttribute(String, Object)); void removeAttribute(String) | void invalidate() | boolean isNew() | + ".ise")); (s.sm.getString("standardSession." + thisJoinPoint.methodName throw new IllegalStateException if (!s.isValid()) // Private Class * when <code>HttpSession.getSessionContext()</code> is called. * This class is a dummy implementation of the <code>HttpSessionContext</code> * interface, to conform to the requirement that such an object be returned As of Java Servlet API 2.1 with no replacement. The private Vector dummy = new Vector(); final class StandardSessionContext implements HttpSessionContext { * interface will be removed in a future version of this API. * This method must return an empty <code>Enumeration</code> As of Java Servlet API 2.1 with no replacement. * within this context. * Return the session identifiers of all sessions defined * and will be removed in a future version of the API. return (dummy.elements()); public Enumeration getIds() { * This method must return null and will be removed in a id Session identifier for which to look up a session * specified session identifier. * Return the <code>HttpSession</code> associated with the public HttpSession getSession(String id) { * future version of the API. return (null); package org.apache.tomcat.session; import org.apache.tomcat.core.*; import javax.servlet.http.*; import javax.servlet.*; import java.util.*; import org.apache.tomcat.util.StringManager; import java.io.*; import java.net.*; James Duncan Davidson public class ServerSession { */ James Todd * /** * Core implementation of a server session private String id; private long thisAccessTime = creationTime; private long creationTime = System.currentTimeMillis();; private Hashtable appSessions = new Hashtable(); private Hashtable values = new Hashtable(); private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); ServerSession(String id) { private long lastAccessed = creationTime; private int inactiveInterval = -1; return id; public String getId() { } this.id = id; public long getLastAccessedTime() { return creationTime; public long getCreationTime() { (ApplicationSession)appSessions.get(context); ApplicationSession appSession = public ApplicationSession getApplicationSession(Context context, return lastAccessed; boolean create) { // XXX if (appSession == null && create) { appSession = new ApplicationSession(id, this, context); appSessions.put(context, appSession); // sync to ensure valid? return appSession; // a new appSession // make sure that we haven't gone over the end of our // inactive interval -- if so, invalidate and create appSessions.remove(context); void removeApplicationSession(Context context) { * inactivities can be dealt with accordingly. * Called by context when request comes in so that accesses and thisAccessTime = System.currentTimeMillis(); lastAccessed = thisAccessTime; // from the previous access void accessed() { // set last accessed to thisAccessTime as it will be left over void validate() void validate() { (int)(System.currentTimeMillis() - lastAccessed) / 1000; int thisInterval = if (inactiveInterval != -1) { // if we have an inactive interval, check to see if // we've exceeded it if (thisInterval > inactiveInterval) { ssm.removeSession(this); ServerSessionManager.getManager(); invalidate(); ServerSessionManager ssm = (ApplicationSession)appSessions.get(key); Object key = enum.nextElement(); while (enum.hasMoreElements()) { Enumeration enum = appSessions.keys(); synchronized void invalidate() { appSession.invalidate(); String msg = sm.getString("serverSession.value.iae"); throw new IllegalArgumentException(msg); if (name == null) { public void putValue(String name, Object value) { removeValue(name); // remove any existing binding public Object getValue(String name) { values.put(name, value); return values.keys(); public Enumeration getValueNames() { return values.get(name); public void setMaxInactiveInterval(int interval) { values.remove(name); public void removeValue(String name) { public int getMaxInactiveInterval() { inactiveInterval = interval; // solution for this, but we'll determine something else later. // from this while we are reaping. This isn't the most optimal // sync'd for safty -- no other thread should be getting something return inactiveInterval; synchronized void reap() { appSession.validate();

9 AOP: Enabling Better Modularity
private long lastAccessed = creationTime; private int inactiveInterval = -1; validate(); thisAccessTime = System.currentTimeMillis(); lastAccessed = thisAccessTime; void accessed() { // set last accessed to thisAccessTime as it will be left over // from the previous access int thisInterval = (int)(System.currentTimeMillis() - lastAccessed) / 1000; if (inactiveInterval != -1) { // if we have an inactive interval, check to see if we've exceeded it void validate() { } invalidate(); if (thisInterval > inactiveInterval) { } else { return lastAccessed; public long getLastAccessedTime() { throw new IllegalStateException(msg); String msg = sm.getString("applicationSession.session.ise"); if (valid) { ServerSessionManager ssm = ssm.removeSession(this); ServerSessionManager.getManager(); private long lastAccessedTime = creationTime; * session, as the number of milliseconds since midnight, January 1, 1970 * Return the last time the client sent a request associated with this /** */ * a value associated with the session, do not affect the access time. * GMT. Actions that your application takes, such as getting or setting return (this.lastAccessedTime); this.lastAccessedTime = time; /* * ==================================================================== * reserved. * Redistribution and use in source and binary forms, with or without * Copyright (c) 1999 The Apache Software Foundation. All rights * The Apache Software License, Version 1.1 * * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * 1. Redistributions of source code must retain the above copyright * are met: * modification, are permitted provided that the following conditions * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * distribution. * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * "This product includes software developed by the * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products * if and wherever such third-party acknowlegements normally appear. itself, * Apache Software Foundation ( * Alternately, this acknowlegement may appear in the software * nor may "Apache" appear in their names without prior written * 5. Products derived from this software may not be called "Apache" * permission, please contact * from this software without prior written permission. For written derived * permission of the Apache Group. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * SUCH DAMAGE. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * < * [Additional notices, if required by prior licensing conditions] * information on the Apache Software Foundation, please see * individuals on behalf of the Apache Software Foundation. For more * This software consists of voluntary contributions made by many import java.io.*; import org.apache.tomcat.util.StringManager; import org.apache.tomcat.core.*; package org.apache.tomcat.session; * Core implementation of an application level session import javax.servlet.*; import javax.servlet.http.*; import java.net.*; import java.util.*; Jason Hunter James Duncan Davidson StringManager.getManager("org.apache.tomcat.session"); private StringManager sm = public class ApplicationSession implements HttpSession { James Todd private long thisAccessTime = creationTime; private boolean valid = true; private Context context; private long creationTime = System.currentTimeMillis();; private ServerSession serverSession; private Hashtable values = new Hashtable(); private String id; this.id = id; this.inactiveInterval = context.getSessionTimeOut(); this.context = context; this.serverSession = serverSession; ApplicationSession(String id, ServerSession serverSession, Context context) { this.inactiveInterval *= 60; if (this.inactiveInterval != -1) { return serverSession; ServerSession getServerSession() { * Called by context when request comes in so that accesses and * inactivities can be dealt with accordingly. // HTTP SESSION IMPLEMENTATION METHODS return id; public String getId() { return creationTime; public long getCreationTime() { return new SessionContextImpl(); public HttpSessionContext getSessionContext() { public void invalidate() { // remove everything in the session serverSession.removeApplicationSession(context); removeValue(name); String name = (String)enum.nextElement(); Enumeration enum = values.keys(); while (enum.hasMoreElements()) { public boolean isNew() { valid = false; if (! valid) { return true; return false; if (thisAccessTime == creationTime) { public void setAttribute(String name, Object value) { setAttribute(name, value); public void putValue(String name, Object value) { removeValue(name); // remove any existing binding throw new IllegalArgumentException(msg); String msg = sm.getString("applicationSession.value.iae"); if (name == null) { new HttpSessionBindingEvent(this, name); ((HttpSessionBindingListener)value).valueBound(e); HttpSessionBindingEvent e = if (value != null && value instanceof HttpSessionBindingListener) { values.put(name, value); public Object getAttribute(String name) { return getAttribute(name); public Object getValue(String name) { return values.get(name); public String[] getValueNames() { names.addElement(e.nextElement()); while (e.hasMoreElements()) { Vector names = new Vector(); Enumeration e = getAttributeNames(); names.copyInto(valueNames); String[] valueNames = new String[names.size()]; public Enumeration getAttributeNames() { return valueNames; return (Enumeration)valuesClone.keys(); Hashtable valuesClone = (Hashtable)values.clone(); public void removeAttribute(String name) { removeAttribute(name); public void removeValue(String name) { Object o = values.get(name); ((HttpSessionBindingListener)o).valueUnbound(e); new HttpSessionBindingEvent(this,name); if (o instanceof HttpSessionBindingListener) { public void setMaxInactiveInterval(int interval) { values.remove(name); public int getMaxInactiveInterval() { inactiveInterval = interval; return inactiveInterval; // * Core implementation of a server session public class ServerSession { private Hashtable appSessions = new Hashtable(); ServerSession(String id) { (ApplicationSession)appSessions.get(context); ApplicationSession appSession = public ApplicationSession getApplicationSession(Context context, boolean create) { // sync to ensure valid? appSession = new ApplicationSession(id, this, context); // XXX if (appSession == null && create) { appSessions.put(context, appSession); return appSession; // a new appSession // inactive interval -- if so, invalidate and create // make sure that we haven't gone over the end of our appSessions.remove(context); void removeApplicationSession(Context context) { void validate() ynchronized void invalidate() { Enumeration enum = appSessions.keys(); appSession.invalidate(); (ApplicationSession)appSessions.get(key); Object key = enum.nextElement(); String msg = sm.getString("serverSession.value.iae"); return values.keys(); public Enumeration getValueNames() { synchronized void reap() { // sync'd for safty -- no other thread should be getting something // solution for this, but we'll determine something else later. // from this while we are reaping. This isn't the most optimal appSession.validate(); ; * Standard implementation of the <b>Session</b> interface. This object is * <b>IMPLEMENTATION NOTE</b>: An instance of this class represents both the * <p> * to a different JVM for distributable session support. * serializable, so that it can be stored in persistent storage or transferred * internal (Session) and application level (HttpSession) view of the session. * HttpSession view of this instance back to a Session view. * of the <code>org.apache.tomcat.session</code> package cannot cast an * However, because the class itself is not declared public, Java logic outside $Revision: 1.2 $ $Date: 2000/05/15 17:54:10 $ Craig R. McClanahan // Constructors implements HttpSession, Session { final class StandardSession * Construct a new Session associated with the specified Manager. this.manager = manager; super(); public StandardSession(Manager manager) { manager The manager with which this Session is associated * The last accessed time for this Session. private Manager manager = null; * The Manager with which this Session is associated. * the servlet container may invalidate this session. A negative time * The maximum time interval, in seconds, between client requests before private int maxInactiveInterval = -1; * indicates that the session should never time out. private boolean isNew = true; * Flag indicating whether this session is new or not. * The string manager for this package. private boolean isValid = false; * Flag indicating whether this session is valid or not. private static HttpSessionContext sessionContext = null; * The HTTP session context associated with this session. private long thisAccessedTime = creationTime; * The current accessed time for this session. // Session Properties * Set the creation time for this session. This method is called by the public void setCreationTime(long time) { time The new creation time * Manager when an existing Session instance is reused. this.thisAccessedTime = time; this.creationTime = time; * Return the session identifier for this session. return (this.id); * Set the session identifier for this session. (manager instanceof ManagerBase)) ((ManagerBase) manager).remove(this); public void setId(String id) { id The new session identifier if ((this.id != null) && (manager != null) && ((ManagerBase) manager).add(this); if ((manager != null) && (manager instanceof ManagerBase)) * Return descriptive information about this Session implementation and public String getInfo() { * <code><description>/<version></code>. * the corresponding version number, in the format return (this.info); * Return the Manager within which this Session is valid. return (this.manager); public Manager getManager() { public void setManager(Manager manager) { manager The new Manager * Set the Manager within which this Session is valid. * before the servlet container will invalidate the session. A negative * Return the maximum time interval, in seconds, between client requests * an invalidated session IllegalStateException if this method is called on * time indicates that the session should never time out. return (this.maxInactiveInterval); * Perform the internal processing required to invalidate this session, // Remove this session from our manager's active sessions public void expire() { * without triggering an exception if the session has already expired. results.addElement(attr); String attr = (String) attrs.nextElement(); while (attrs.hasMoreElements()) { // Unbind any objects associated with this session Vector results = new Vector(); Enumeration attrs = getAttributeNames(); String name = (String) names.nextElement(); while (names.hasMoreElements()) { Enumeration names = results.elements(); setValid(false); // Mark this session as invalid isNew The new value for the <code>isNew</code> flag * Set the <code>isNew</code> flag for this session. void setNew(boolean isNew) { this.isNew = isNew; isValid The new value for the <code>isValid</code> flag * Set the <code>isValid</code> flag for this session. void setValid(boolean isValid) { // HttpSession Properties this.isValid = isValid; * Return the time when this session was created, in milliseconds since * invalidated session IllegalStateException if this method is called on an * midnight, January 1, 1970 GMT. return (this.creationTime); * Return the session context with which this session is associated. * Java Servlet API. * replacement. It will be removed in a future version of the As of Version 2.1, this method is deprecated and has no return (sessionContext); sessionContext = new StandardSessionContext(); if (sessionContext == null) // HttpSession Public Methods name Name of the attribute to be returned * <code>null</code> if no object is bound with that name. * Return the object bound with the specified name in this session, or return (attributes.get(name)); * containing the names of the objects bound to this session. * Return an <code>Enumeration</code> of <code>String</code> objects return (attributes.keys()); name Name of the value to be returned As of Version 2.2, this method is replaced by return (getAttribute(name)); * <code>getAttribute()</code> * are no such objects, a zero-length array is returned. * Return the set of names of objects bound to this session. If there * <code>getAttributeNames()</code> return (names); names[i] = (String) results.elementAt(i); for (int i = 0; i < names.length; i++) String names[] = new String[results.size()]; * Invalidates this session and unbinds any objects bound to it. // Cause this session to expire expire(); * example, if the server used only cookie-based sessions, and the client * session, or if the client chooses not to join the session. For * Return <code>true</code> if the client does not yet know about the * request. * has disabled the use of cookies, then a session would be new on each return (this.isNew); * Remove the object bound with the specified name from this session. If * does nothing. * the session does not have an object bound with this name, this method name Name of the object to remove from this session. * <code>valueUnbound()</code> on the object. * <code>HttpSessionBindingListener</code>, the container calls * After this method executes, and if the object implements Object object = attributes.get(name); synchronized (attributes) { ((HttpSessionBindingListener) object).valueUnbound (new HttpSessionBindingEvent((HttpSession) this, name)); if (object instanceof HttpSessionBindingListener) { // System.out.println( "Removing attribute " + name ); if (object == null) return; attributes.remove(name); * replaced. * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is value Object to be bound, cannot be null * <code>valueBound()</code> on the object. name Name to which the object is bound, cannot be null * non-serializable object in an environment marked distributable. IllegalArgumentException if an attempt is made to add a throw new IllegalArgumentException attributes.put(name, value); (sm.getString("standardSession.setAttribute.iae")); if ((manager != null) && manager.getDistributable() && !(value instanceof Serializable)) ((HttpSessionBindingListener) value).valueBound if (value instanceof HttpSessionBindingListener) // HttpSession Private Methods * <b>IMPLEMENTATION NOTE</b>: The reference to the owning Manager * is not restored by this method, and must be set explicitly. * object input stream. * Read a serialized version of this session object from the specified IOException if an input/output error occurs ClassNotFoundException if an unknown class is specified stream The input stream to read from creationTime = ((Long) stream.readObject()). isValid = ((Boolean) stream.readObject()).booleanValue(); // Deserialize the scalar instance variables (except Manager) throws ClassNotFoundException, IOException { private void readObject(ObjectInputStream stream) String name = (String) stream.readObject(); for (int i = 0; i < n; i++) { Object value = (Object) stream.readObject(); int n = ((Integer) stream.readObject()).intValue(); // Deserialize the attribute count and attribute values * in the serialized representation of this Session. After calling * <code>readObject()</code>, you must set the associated Manager * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored * object output stream. * Write a serialized version of this session object to the specified * be sure the <code>distributable</code> property of our associated * Manager is set to <code>true</code>. * will be silently ignored. If you do not want any such attributes, * explicitly. * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable private void writeObject(ObjectOutputStream stream) throws IOException { stream The output stream to write to stream.writeObject(new Integer(maxInactiveInterval)); stream.writeObject(new Boolean(isNew)); stream.writeObject(new Long(lastAccessedTime)); stream.writeObject(id); // Write the scalar instance variables (except Manager) stream.writeObject(new Long(creationTime)); // Accumulate the names of serializable attributes stream.writeObject(new Boolean(isValid)); // Serialize the attribute count and the attribute values if (value instanceof Serializable) Object value = attributes.get(attr); stream.writeObject(new Integer(results.size())); stream.writeObject(attributes.get(name)); stream.writeObject(name); String[] getValueNames() | void invalidate() | Enumeration getAttributeNames() | Object getAttribute(String) | long getCreationTime() | crosscut invalidate(StandardSession s): s & (int getMaxInactiveInterval() | boolean isNew() | before { if (!s.isValid()) throw new IllegalStateException static advice(StandardSession s): invalidate(s) { void setAttribute(String, Object)); void removeAttribute(String) | + ".ise")); + thisJoinPoint.methodName (s.sm.getString("standardSession." // Private Class * when <code>HttpSession.getSessionContext()</code> is called. * This class is a dummy implementation of the <code>HttpSessionContext</code> * interface, to conform to the requirement that such an object be returned final class StandardSessionContext implements HttpSessionContext { * interface will be removed in a future version of this API. As of Java Servlet API 2.1 with no replacement. The * within this context. As of Java Servlet API 2.1 with no replacement. * Return the session identifiers of all sessions defined private Vector dummy = new Vector(); public Enumeration getIds() { * and will be removed in a future version of the API. * This method must return an empty <code>Enumeration</code> return (dummy.elements()); id Session identifier for which to look up a session * Return the <code>HttpSession</code> associated with the * specified session identifier. public HttpSession getSession(String id) { * future version of the API. * This method must return null and will be removed in a return (null); Extend object-oriented languages For modularization of crosscutting concerns One module can modify others’ behaviors /* * * ==================================================================== * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * reserved. * Copyright (c) 1999 The Apache Software Foundation. All rights * The Apache Software License, Version 1.1 * 1. Redistributions of source code must retain the above copyright * are met: * the documentation and/or other materials provided with the * distribution. * notice, this list of conditions and the following disclaimer in * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer. itself, * if and wherever such third-party acknowlegements normally appear. * Apache Software Foundation ( * Alternately, this acknowlegement may appear in the software * "This product includes software developed by the * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * Foundation" must not be used to endorse or promote products * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * 5. Products derived from this software may not be called "Apache" * permission, please contact derived * from this software without prior written permission. For written * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * This software consists of voluntary contributions made by many * SUCH DAMAGE. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * information on the Apache Software Foundation, please see * individuals on behalf of the Apache Software Foundation. For more * [Additional notices, if required by prior licensing conditions] */ * < package org.apache.tomcat.session; import java.net.*; import java.util.*; import java.io.*; import org.apache.tomcat.util.StringManager; import org.apache.tomcat.core.*; * Core implementation of an application level session James Duncan Davidson /** import javax.servlet.http.*; import javax.servlet.*; James Todd Jason Hunter private String id; private Hashtable values = new Hashtable(); private StringManager sm = public class ApplicationSession implements HttpSession { StringManager.getManager("org.apache.tomcat.session"); private ServerSession serverSession; private boolean valid = true; private int inactiveInterval = -1; private long lastAccessed = creationTime; private Context context; private long creationTime = System.currentTimeMillis();; private long thisAccessTime = creationTime; this.inactiveInterval = context.getSessionTimeOut(); this.context = context; this.id = id; Context context) { ApplicationSession(String id, ServerSession serverSession, this.serverSession = serverSession; } this.inactiveInterval *= 60; if (this.inactiveInterval != -1) { return serverSession; ServerSession getServerSession() { * inactivities can be dealt with accordingly. * Called by context when request comes in so that accesses and void accessed() { thisAccessTime = System.currentTimeMillis(); lastAccessed = thisAccessTime; // set last accessed to thisAccessTime as it will be left over // from the previous access int thisInterval = if (inactiveInterval != -1) { void validate() { validate(); invalidate(); if (thisInterval > inactiveInterval) { (int)(System.currentTimeMillis() - lastAccessed) / 1000; // if we have an inactive interval, check to see if we've exceeded it if (valid) { // HTTP SESSION IMPLEMENTATION METHODS String msg = sm.getString("applicationSession.session.ise"); public String getId() { throw new IllegalStateException(msg); } else { return id; return creationTime; public long getCreationTime() { public long getLastAccessedTime() { return new SessionContextImpl(); public HttpSessionContext getSessionContext() { return lastAccessed; public void invalidate() { // remove everything in the session serverSession.removeApplicationSession(context); removeValue(name); String name = (String)enum.nextElement(); Enumeration enum = values.keys(); while (enum.hasMoreElements()) { public boolean isNew() { valid = false; if (! valid) { return true; return false; if (thisAccessTime == creationTime) { public void setAttribute(String name, Object value) { setAttribute(name, value); public void putValue(String name, Object value) { removeValue(name); // remove any existing binding throw new IllegalArgumentException(msg); String msg = sm.getString("applicationSession.value.iae"); if (name == null) { new HttpSessionBindingEvent(this, name); ((HttpSessionBindingListener)value).valueBound(e); HttpSessionBindingEvent e = if (value != null && value instanceof HttpSessionBindingListener) { values.put(name, value); public Object getAttribute(String name) { return getAttribute(name); public Object getValue(String name) { return values.get(name); public String[] getValueNames() { names.addElement(e.nextElement()); while (e.hasMoreElements()) { Vector names = new Vector(); Enumeration e = getAttributeNames(); names.copyInto(valueNames); String[] valueNames = new String[names.size()]; public Enumeration getAttributeNames() { return valueNames; return (Enumeration)valuesClone.keys(); Hashtable valuesClone = (Hashtable)values.clone(); public void removeAttribute(String name) { removeAttribute(name); public void removeValue(String name) { Object o = values.get(name); ((HttpSessionBindingListener)o).valueUnbound(e); new HttpSessionBindingEvent(this,name); if (o instanceof HttpSessionBindingListener) { public void setMaxInactiveInterval(int interval) { values.remove(name); public int getMaxInactiveInterval() { inactiveInterval = interval; return inactiveInterval; // ; * Standard implementation of the <b>Session</b> interface. This object is /** * <b>IMPLEMENTATION NOTE</b>: An instance of this class represents both the * <p> * to a different JVM for distributable session support. * serializable, so that it can be stored in persistent storage or transferred * internal (Session) and application level (HttpSession) view of the session. Craig R. McClanahan * * HttpSession view of this instance back to a Session view. * However, because the class itself is not declared public, Java logic outside * of the <code>org.apache.tomcat.session</code> package cannot cast an $Revision: 1.2 $ $Date: 2000/05/15 17:54:10 $ // Constructors implements HttpSession, Session { */ final class StandardSession manager The manager with which this Session is associated * Construct a new Session associated with the specified Manager. this.manager = manager; } super(); public StandardSession(Manager manager) { private long lastAccessedTime = creationTime; * The last accessed time for this Session. * The maximum time interval, in seconds, between client requests before private Manager manager = null; * The Manager with which this Session is associated. private int maxInactiveInterval = -1; * indicates that the session should never time out. * the servlet container may invalidate this session. A negative time private boolean isNew = true; * Flag indicating whether this session is new or not. * Flag indicating whether this session is valid or not. private boolean isValid = false; private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); * The string manager for this package. private static HttpSessionContext sessionContext = null; * The HTTP session context associated with this session. private long thisAccessedTime = creationTime; * The current accessed time for this session. // Session Properties * Set the creation time for this session. This method is called by the time The new creation time * Manager when an existing Session instance is reused. this.thisAccessedTime = time; this.lastAccessedTime = time; public void setCreationTime(long time) { this.creationTime = time; public String getId() { * Return the session identifier for this session. return (this.id); id The new session identifier * Set the session identifier for this session. public void setId(String id) { if ((this.id != null) && (manager != null) && if ((manager != null) && (manager instanceof ManagerBase)) this.id = id; (manager instanceof ManagerBase)) ((ManagerBase) manager).remove(this); ((ManagerBase) manager).add(this); * Return descriptive information about this Session implementation and public String getInfo() { * <code><description>/<version></code>. * the corresponding version number, in the format return (this.info); * Return the last time the client sent a request associated with this * a value associated with the session, do not affect the access time. * GMT. Actions that your application takes, such as getting or setting * session, as the number of milliseconds since midnight, January 1, 1970 return (this.lastAccessedTime); public long getLastAccessedTime() { * Return the Manager within which this Session is valid. return (this.manager); public Manager getManager() { public void setManager(Manager manager) { manager The new Manager * Set the Manager within which this Session is valid. * time indicates that the session should never time out. * before the servlet container will invalidate the session. A negative * Return the maximum time interval, in seconds, between client requests public int getMaxInactiveInterval() { * an invalidated session IllegalStateException if this method is called on return (this.maxInactiveInterval); * Update the accessed time information for this session. This method * should be called by the context when a request comes in for a particular this.thisAccessedTime = System.currentTimeMillis(); this.lastAccessedTime = this.thisAccessedTime; public void access() { * session, even if the application does not reference it. this.isNew=false; public void expire() { * without triggering an exception if the session has already expired. * Perform the internal processing required to invalidate this session, // Remove this session from our manager's active sessions String attr = (String) attrs.nextElement(); while (attrs.hasMoreElements()) { Enumeration attrs = getAttributeNames(); // Unbind any objects associated with this session Vector results = new Vector(); while (names.hasMoreElements()) { removeAttribute(name); String name = (String) names.nextElement(); Enumeration names = results.elements(); results.addElement(attr); setValid(false); // Mark this session as invalid isNew The new value for the <code>isNew</code> flag * Set the <code>isNew</code> flag for this session. void setNew(boolean isNew) { this.isNew = isNew; void setValid(boolean isValid) { isValid The new value for the <code>isValid</code> flag * Set the <code>isValid</code> flag for this session. // HttpSession Properties this.isValid = isValid; IllegalStateException if this method is called on an * midnight, January 1, 1970 GMT. * Return the time when this session was created, in milliseconds since return (this.creationTime); public long getCreationTime() { * invalidated session * replacement. It will be removed in a future version of the As of Version 2.1, this method is deprecated and has no * Return the session context with which this session is associated. * Java Servlet API. sessionContext = new StandardSessionContext(); return (sessionContext); if (sessionContext == null) public HttpSessionContext getSessionContext() { // HttpSession Public Methods * Return the object bound with the specified name in this session, or name Name of the attribute to be returned * <code>null</code> if no object is bound with that name. return (attributes.get(name)); public Object getAttribute(String name) { * containing the names of the objects bound to this session. * Return an <code>Enumeration</code> of <code>String</code> objects return (attributes.keys()); public Enumeration getAttributeNames() { name Name of the value to be returned As of Version 2.2, this method is replaced by return (getAttribute(name)); public Object getValue(String name) { * <code>getAttribute()</code> * are no such objects, a zero-length array is returned. * Return the set of names of objects bound to this session. If there public String[] getValueNames() { * <code>getAttributeNames()</code> return (names); names[i] = (String) results.elementAt(i); for (int i = 0; i < names.length; i++) String names[] = new String[results.size()]; * Invalidates this session and unbinds any objects bound to it. expire(); // Cause this session to expire public void invalidate() { * example, if the server used only cookie-based sessions, and the client * session, or if the client chooses not to join the session. For * Return <code>true</code> if the client does not yet know about the * request. * has disabled the use of cookies, then a session would be new on each return (this.isNew); public boolean isNew() { * Remove the object bound with the specified name from this session. If * After this method executes, and if the object implements * does nothing. * the session does not have an object bound with this name, this method * <code>valueUnbound()</code> on the object. name Name of the object to remove from this session. * <code>HttpSessionBindingListener</code>, the container calls synchronized (attributes) { Object object = attributes.get(name); public void removeAttribute(String name) { ((HttpSessionBindingListener) object).valueUnbound (new HttpSessionBindingEvent((HttpSession) this, name)); if (object instanceof HttpSessionBindingListener) { // System.out.println( "Removing attribute " + name ); if (object == null) return; attributes.remove(name); * replaced. * Bind an object to this session, using the specified name. If an object * of the same name is already bound to this session, the object is value Object to be bound, cannot be null * <code>valueBound()</code> on the object. name Name to which the object is bound, cannot be null * non-serializable object in an environment marked distributable. IllegalArgumentException if an attempt is made to add a throw new IllegalArgumentException public void setAttribute(String name, Object value) { attributes.put(name, value); (sm.getString("standardSession.setAttribute.iae")); if ((manager != null) && manager.getDistributable() && !(value instanceof Serializable)) ((HttpSessionBindingListener) value).valueBound if (value instanceof HttpSessionBindingListener) // HttpSession Private Methods stream The input stream to read from * is not restored by this method, and must be set explicitly. * <b>IMPLEMENTATION NOTE</b>: The reference to the owning Manager * object input stream. * Read a serialized version of this session object from the specified IOException if an input/output error occurs ClassNotFoundException if an unknown class is specified id = (String) stream.readObject(); lastAccessedTime = ((Long) stream.readObject()).longValue(); creationTime = ((Long) stream.readObject()).longValue(); // Deserialize the scalar instance variables (except Manager) private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { isNew = ((Boolean) stream.readObject()).booleanValue(); maxInactiveInterval = ((Integer) stream.readObject()).intValue(); String name = (String) stream.readObject(); Object value = (Object) stream.readObject(); for (int i = 0; i < n; i++) { int n = ((Integer) stream.readObject()).intValue(); // Deserialize the attribute count and attribute values isValid = ((Boolean) stream.readObject()).booleanValue(); * object output stream. * Write a serialized version of this session object to the specified * explicitly. * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable * <code>readObject()</code>, you must set the associated Manager * in the serialized representation of this Session. After calling * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored * Manager is set to <code>true</code>. stream The output stream to write to * be sure the <code>distributable</code> property of our associated * will be silently ignored. If you do not want any such attributes, stream.writeObject(new Long(creationTime)); stream.writeObject(id); // Write the scalar instance variables (except Manager) private void writeObject(ObjectOutputStream stream) throws IOException { stream.writeObject(new Boolean(isNew)); // Accumulate the names of serializable attributes stream.writeObject(new Boolean(isValid)); stream.writeObject(new Integer(maxInactiveInterval)); stream.writeObject(new Long(lastAccessedTime)); if (value instanceof Serializable) Object value = attributes.get(attr); stream.writeObject(new Integer(results.size())); // Serialize the attribute count and the attribute values stream.writeObject(attributes.get(name)); stream.writeObject(name); Enumeration getAttributeNames() | String[] getValueNames() | Object getAttribute(String) | long getCreationTime() | crosscut invalidate(StandardSession s): s & (int getMaxInactiveInterval() | static advice(StandardSession s): invalidate(s) { before { void setAttribute(String, Object)); void removeAttribute(String) | void invalidate() | boolean isNew() | + ".ise")); (s.sm.getString("standardSession." + thisJoinPoint.methodName throw new IllegalStateException if (!s.isValid()) // Private Class * when <code>HttpSession.getSessionContext()</code> is called. * This class is a dummy implementation of the <code>HttpSessionContext</code> * interface, to conform to the requirement that such an object be returned As of Java Servlet API 2.1 with no replacement. The private Vector dummy = new Vector(); final class StandardSessionContext implements HttpSessionContext { * interface will be removed in a future version of this API. * This method must return an empty <code>Enumeration</code> As of Java Servlet API 2.1 with no replacement. * within this context. * Return the session identifiers of all sessions defined * and will be removed in a future version of the API. return (dummy.elements()); public Enumeration getIds() { * This method must return null and will be removed in a id Session identifier for which to look up a session * specified session identifier. * Return the <code>HttpSession</code> associated with the public HttpSession getSession(String id) { * future version of the API. return (null); package org.apache.tomcat.session; import org.apache.tomcat.core.*; import javax.servlet.http.*; import javax.servlet.*; import java.util.*; import org.apache.tomcat.util.StringManager; import java.io.*; import java.net.*; James Duncan Davidson public class ServerSession { */ James Todd * /** * Core implementation of a server session private String id; private long thisAccessTime = creationTime; private long creationTime = System.currentTimeMillis();; private Hashtable appSessions = new Hashtable(); private Hashtable values = new Hashtable(); private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); ServerSession(String id) { private long lastAccessed = creationTime; private int inactiveInterval = -1; return id; public String getId() { } this.id = id; public long getLastAccessedTime() { return creationTime; public long getCreationTime() { (ApplicationSession)appSessions.get(context); ApplicationSession appSession = public ApplicationSession getApplicationSession(Context context, return lastAccessed; boolean create) { // XXX if (appSession == null && create) { appSession = new ApplicationSession(id, this, context); appSessions.put(context, appSession); // sync to ensure valid? return appSession; // a new appSession // make sure that we haven't gone over the end of our // inactive interval -- if so, invalidate and create appSessions.remove(context); void removeApplicationSession(Context context) { * inactivities can be dealt with accordingly. * Called by context when request comes in so that accesses and thisAccessTime = System.currentTimeMillis(); lastAccessed = thisAccessTime; // from the previous access void accessed() { // set last accessed to thisAccessTime as it will be left over void validate() void validate() { (int)(System.currentTimeMillis() - lastAccessed) / 1000; int thisInterval = if (inactiveInterval != -1) { // if we have an inactive interval, check to see if // we've exceeded it if (thisInterval > inactiveInterval) { ssm.removeSession(this); ServerSessionManager.getManager(); invalidate(); ServerSessionManager ssm = (ApplicationSession)appSessions.get(key); Object key = enum.nextElement(); while (enum.hasMoreElements()) { Enumeration enum = appSessions.keys(); synchronized void invalidate() { appSession.invalidate(); String msg = sm.getString("serverSession.value.iae"); throw new IllegalArgumentException(msg); if (name == null) { public void putValue(String name, Object value) { removeValue(name); // remove any existing binding public Object getValue(String name) { values.put(name, value); return values.keys(); public Enumeration getValueNames() { return values.get(name); public void setMaxInactiveInterval(int interval) { values.remove(name); public void removeValue(String name) { public int getMaxInactiveInterval() { inactiveInterval = interval; // solution for this, but we'll determine something else later. // from this while we are reaping. This isn't the most optimal // sync'd for safty -- no other thread should be getting something return inactiveInterval; synchronized void reap() { appSession.validate();

10


Download ppt "Problems of Object-Oriented Design and Implementation"

Similar presentations


Ads by Google