Presentation is loading. Please wait.

Presentation is loading. Please wait.

© Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 the fun has just begun Gregor Kiczales University of British Columbia © Copyright 2003,

Similar presentations


Presentation on theme: "© Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 the fun has just begun Gregor Kiczales University of British Columbia © Copyright 2003,"— Presentation transcript:

1 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 the fun has just begun Gregor Kiczales University of British Columbia © Copyright 2003, Gregor Kiczales, except for slides explicitly marked with a different copyright. Permission is granted to use this presentation, in whole or in part for educational purposes, provided that every slide used is used in its entirety, with no changes, deletions or additions; and that the copyright notice is preserved on every slide used. software modularity group

2 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 talk timeline and level of abstraction software models conclusiontangle, scatter, crosscut join point mechanisms another view

3 © Copyright 2003, Gregor Kiczales. All rights reserved. scatter tangle crosscut and all that exploring some of the terms we use

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

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

6 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 do we help with this problem? : System.out.println("foo called"); Helper.foo(n/3); : System.out.println("foo called"); Helper.foo(i+j+k); : System.out.println("foo called"); Helper.foo(x); : class Helper { : public static void foo(int n) { … } : } every call to foo is preceded by a log call

7 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 not necessarily : System.out.println("foo called"); Helper.foo(…); : System.out.println("foo called"); Helper.foo(…); : System.out.println("foo called"); Helper.foo(…); : class Helper { : public static void foo(int n) { … } : } class Helper { : public static void foo(int n) { System.out.println("foo called."); … } : } : Helper.foo(n/3); : Helper.foo(i+j+k); : Helper.foo(x); : procedures can modularize this case unless logs use calling context, we dont control source of Helper…

8 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 do we help with this problem? 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() refresh() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() refresh() FigureElement moveBy(int, int) all subclasses have an identical method

9 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 not necessarily 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() refresh() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() refresh() FigureElement moveBy(int, int) 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() FigureElement moveBy(int, int) refresh() inheritance can modularize this

10 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 do we help with this problem? 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() FigureElement moveBy(int, int) refresh() these methods all end with call to: Display.update();

11 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 yes! – this is AspectJs fact(n) DisplayUpdating 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() FigureElement moveBy(int, int) refresh() after(): call(void FigureElement+.set*(..)) || call(void FigureElement.moveBy(int, int)) { Display.update(); }

12 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 observations and questions modularity (aka SOC) techniques –S&T principle, mechanism modular structure –may apply across range of software artifacts many kinds of S&T, principles, structure S&T is not specific to AO AO is just one modularity technique questions to answer include: –what particular modularity problems do we address? our particular kind of S&T? –whats our particular principle? procedure, object… –whats our particular kind of structure? block, classification hierarchy…

13 [Yvonne Coady AOSD 2003] vm_fault vm_pager_getpages vnode_pager_getpages ffs_getpages … ufs_bmap path specific customization ffs_valid ffs_calc_size [Coady AOSD03]

14 CLASSIFYING BY CLASSIFICATION SIBLINGS nontreetree hardwoodsoftwood object plantnestablepredator insect plant nectar plant dandelion bird woodsman locust maple cherry pine object Copyright © 1993 IBM Corporation [Harrison, Ossher OOPSLA93]

15 UBC software modularity group [Jan Hanneman OOPSLA 2002] observer pattern in AspectJ FigureElement getColor(): Color setColor(Color) Point getX(): int getY(): int getColor():Color setX(int) setY(int) setColor(Color) Line getP1():Point getP2():Point getColor():Color setP1(Point) setP2(Point) setColor(Color) Screen display() A Figure Element System Observer Design Pattern Subject addObserver(Observer) removeObserver(Observer) notify() Observer update() ConcreteSubject getState() setState() notify() subjectState ConcreteObserver update(Subject) observerState For all o in observers { o.update(); } observers subject observerState = subject.getState(); [Hanneman OOPSLA02] setX(int) setY(int) setColor(Color) setP1(Point) setP2(Point) setColor(Color)

16 Example of AOP with Composition Filters Add synchronization constraint (mutual exclusion) to a given list of classes Synchronization (assertions, dispatch,..) is expressed by a filter of type Wait (Error, Dispatch,..): –if the condition NoActiveThreads does not hold for an object, –a received message can not pass the filter, –and will be queued until it can pass. filtermodule (declarations + filter definition) is unit of superimposition concern ConcurrentDocumentProcessing // concern unifies aspect & class filtermodule MutExSync // unit of superimposition conditions NoActiveThreads; // is true when no thread is executing within this object inputfilters buffer:Wait={ NoActiveThreads=>*}; // implements synchronization end;... contd [Aksit, Bergmans CACM AOP issue] Copyright © 2003 Mehmet Aksit, Lodewijk Bergmans

17 traversals and class graphs P1 P2 P3 P1 P6 P2 P5 P3 P4 P1 P2 Copyright © 2003 MiraMezini, David Lorenz, Karl Lieberherr [Mezini, Lorenz, Lieberherr c.'98]

18 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 analysis of some of our accounts tyranny of the dominant decomposition crosscutting structure aspect weaving an attempt to classify and evaluate some of the accounts – what do they address, strengths, weaknesses by "account" I mean a story we tell to explain part or all of AOSD

19 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 tyrannny… describes –the problem –sometimes a single decomposition cant localize all concerns –want multiple decompositions but… –exactly when does a single decomposition fail? –two decompositions? two decomposition paradigms?... where do you file Sacred Hoops? fitting Line in to FigureElement and Point fitting DisplayUpdating in to FigureElement, Point and Line vs. DisplayUpdating # change after change() 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() FigureElement moveBy(int, int) refresh() 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() FigureElement moveBy(int, int) refresh()

20 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 aspect describes –entities that become local in the alternate decomposition –aspect-of is different than part-of wheel is a part of a car wind resistance is an aspect of a car DisplayUpdating is an aspect of Point & Line –when setX is called, updating happens the prefetching optimization is an aspect of virtual memory –runs as integral part of vnode access but… –what is the nature of the relationship exactly? –how does the alternate decomposition localize the aspect? –litmus test for a definition: discriminate between aspect and object? –how does this fit with symmetric AOP each player vs. great ball movement

21 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 crosscutting describes –nature of relation between decompositions –cases where a single decomposition fails but… –what crosscuts? concern? structure? natural structure? –crosscutting concern concern for which natural structures crosscut –precise definition of crosscutting? 1 to many and many to 1 correspondence (in general) DisplayUpdating # change after change() 2 Point getX() getY() setX(int) setY(int) moveBy(int, int) draw() Line getP1() getP2() setP1(Point) setP2(Point) moveBy(int, int) draw() FigureElement moveBy(int, int) refresh() nontreetree hardwoodsoftwood object plantnestablepredator insect plant nectar plant dandelion bird woodsman locust maple cherry pine object like a Fourier transform

22 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 join point mechanisms describes –mechanism –coordinates (weaves) different semantic effects together at join points –quantification and ob*** (transparency) –these accounts are the most solid but… –weaving connotes source code pre-processing? interleaving? –quantification connotes meta-programing –applicability of a technique doesnt work to define an approach –I tried to downplay weaving, but… systematically propagate and coordinate effects

23 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 summary so far current accounts of aspect-orientation –problem: tyranny of single decomposition cannot, in a single decomposition, modularize all concerns bad modularity brittle (non-adaptive), fragile, buggy mess –principle: aspects … concerns that are local in the alternate decomposition aspect of is different than part of –structure: crosscutting relationship between decompositions such that –some concerns are localized (aspects) –and others are potentially spread out –mechanism: join point mechanisms coordinates effect of programs from different decompositions

24 © Copyright 2003, Gregor Kiczales. All rights reserved. the join point mechanism the claim that this is the communitys main contribution to date

25 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 join point mechanisms one ontology for JP mechanisms –the join points –a means of identifying join points –a means of semantic effect at join points after(): call(void FigureElement+.set*(..)) || call(void FigureElement.moveBy(int, int)) { Display.update(); }

26 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 join pointsmeans of identifying JPs means of semantic effect at JPS AJ dyn points in runtime control flow graph by declaration signature including wildcards, lexical and dynamic properties execute before, after or around AJ static member signatures by signature including wildcards and lexical properties warn, error add member HJmember signatures by signature including wildcards and lexical properties extract to slice compose in numerous ways DJ CF … diversity of JP mechanisms

27 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 join pointsmeans of identifying JPs means of semantic effect at JPS AJ dyn points in runtime control flow graph by declaration signature including wildcards, lexical and dynamic properties execute before, after or around AJ static member signatures by signature including wildcards and lexical properties warn, error add member HJmember signatures by signature including wildcards and lexical properties extract to slice compose in numerous ways DJ diversity of JP mechanisms AJdyn HJ DJ fine dynamic static coarse ??? AJstatic

28 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 communitys key contributions to date have discovered the space of join point mechanisms –different kinds of join points –different kinds of means of identifying join points –different kinds of means of specifying semantics have used this to program from multiple decompositions –bearing a variety of simultaneous structural relationships block, hierarchical, crosscutting

29 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 pointcut entry(): !within(com.acme.product..*) && call(public * com.acme.product..*(..)); pointcut initialEntry(): entry() && !cflowbelow(entry()); around(): initialEntry() { proceed(); } compositional crosscutting package structure wrt control flow

30 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 join point mechanisms but –if you add a new field color –you have to extend this pointcut so… after(): call(void Point.setX(int)) || call(void Point.setY(int)) || call(void Line.setP1(Point)) || call(void Line.setP2(Point)) || call(void FigureElement.moveBy(int, int)) { Display.update(); } it is still it is better than without AOP the dependence is explicit, localized, modular clear declarative interface (the structure of the crosscutting concern is explicit)

31 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 a more precise means of identifying JPs robust against some edits the abstraction of the pointcut is now more clear but –if you add a field that doesnt have a set method –you still have to update the pointcut so… –you could solve this problem by prohibiting wildcards? –you could solve this problem by requiring tags on methods? –NO! solve it by making the means of identifying JPs more precise after(): call(void FigureElement+.set*(..)) || call(void FigureElement.moveBy(int, int)) { Display.update(); }

32 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 idea for a more precise mechanism predict the control flow of FigureElement.draw() consider HOW the dependencies are stated, not just WHAT is depended on sets to such fields require display update find fields referenced in that control flow pointcut* displayState(): pcflow(execution(void FigureElement+.draw()) && get(* FigElt+.*); after set( ) (): { Display.update(); }

33 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 other ideas… dflow(, ) –did the value of the variable come in a dataflow through min(, ) –the least common caller of the two cflows JP mechanism opens a new design space –a language design for packaging such analyses –how to think about programming with them –how to limit to tractable cases

34 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 summary so far a number of accounts help describe the space –get at different aspects of our work –none is completely satisfactory JP mechanisms are key contribution to date –discovery of the space of join point mechanisms –using them to program from multiple decompositions we should increase the power of JP mechanisms –to make means of identifying JPs more precise –to make AOP more useful –and to make AOP more principled, more robust…

35 © Copyright 2003, Gregor Kiczales. All rights reserved. another perspective on join point mechanisms the concepts of registration, effectiveness and the middle distance between connection and disconnection

36 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 [Smith, On the Origin of Objects 1 ] how is it that we can see the world in different ways? registration is –process of parsing objects out of fog of undifferentiated stuff –constantly registering and re-registering the world –mediates different perspectives on a changing world –enables moving in and out of connection with the world critical properties of registration –multiple routes to reference (aliasing is inherent) morning star, evening star –ability to exceed causal reach person closest to average height in Gorbachev's office now –indexical reference the one in front of him 1. On this slide, object means in the real-world.

37 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting some program stream of instructions

38 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting pick out some of the points and register them into this structure

39 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting and add to the instruction stream there

40 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting and add to the instruction stream there

41 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting

42 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting

43 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting

44 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 how JP mechanisms enable crosscutting

45 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 JP mechanisms reconsidered how to decompose software in different ways register aspects out of fog of undifferentiated points –means of identifying JPs (aka pointcut) registers –aspects/slices/concerns… group over that connect and have effect through that registration –means of semantic effect (aka advice) critical properties of registration –multiple routes to reference void setX(int nx) { … }, call(void setX(int)), cflow(…) –exceed causal reach within(com.sun..*), !within(com.mycompany.mysystem) –indexical reference cflow(…)

46 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 a simple bridge

47 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 models programs and systems system model effective abstract

48 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 models programs and systems i = 1 while (i < 4) { print(i) i = i + 1 } system model abstract effective programs live in this magic space

49 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 models programs and systems i = 1 while (i < 4) { print(i) i = i + 1 } system model Brians account talks (in part) about this space abstract effective programs live in this magic space

50 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 models programs and systems i = 1 while (i < 4) { print(i) i = i + 1 } system model abstract effective programs live in this magic space cc Brians account talks (in part) about this space

51 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 models programs and systems i = 1 while (i < 4) { print(i) i = i + 1 } system model abstract effective programs live in this magic space cc Brians account talks (in part) about this space

52 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 summary account of JP mechanism in terms of registration –possible basis for better foundational account of AO more interesting than objects? harder than objects? –relation among problems, decompositions, structures, mechanisms –read On the Origin of Objects (except it is not written in computer science vocabulary) JP mechanism seen as –means of connecting via different decompositions –means of switching between connected and disconnected

53 © Copyright 2003, Gregor Kiczales. All rights reserved. join point mechanisms and software models what can we do for models, model based development, fluid AO

54 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 impact of JP mechanism on sw models models that abstract –simple UML class diagrams models that crosscut –patterns –UML sequence, state… models that connect and disconnect –fluid aspect-orientation

55 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 use cases what is the system supposed to do for each user the use cases crosscut the components JP mechanism provides principled support to organize modeling, implementation, testing… multiple effects at a JP –identifies an interaction in the design –means for resolving the issue –traceability in the code reasoning about composition of use cases = reasoning about composition of aspects

56 Solid Palette Gradient Palette I Gradient Palette II APPLYING THESE COLORS 1.1. 2.2. 3.3. Click on the desired color Click on the paintbrush tool located on your toolbar Click on the object you want to colorize Helpful tip: Double click the paintbrush tool to apply color to more than one object at a time. To use or remove these color palettes, go to View/Master/Slide Master Optional logo for your notes/handouts slides Do not use Gradient fills for slides to be used for Webinars Use cases – use case realizations -- components Each use case is realized by a collaboration - a set of classes A class plays different roles in different use case realizations The total responsibility of a class is the composition of these roles Each use case is realized by a collaboration - a set of classes A class plays different roles in different use case realizations The total responsibility of a class is the composition of these roles Withdraw Cash Deposit Funds Transfer Funds Cash Withdrawal Cash Interface Cash Interface Deposit Funds Transfer Funds Interface Funds Deposit Cash Transfer Funds Cash Withdrawal Use case Specification Use case design Component design & implementation

57 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 Observer Subject Observer: Display change update: {...} class Point { int x; Getter/Setter int y; void draw() { Graphics.drawOval(…); }... } patterns and classes pattern must be effective (connect to code) wizards might weave the pattern in –brittle, hard to understand, hard to maintain would rather preserve a structure like this

58 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 Observer Subject Observer: Display change update: {...} class Point { int x; Getter/Setter int y; void draw() { Graphics.drawOval(…); }... } patterns and classes Observer refers to expansion of Getter/Setter –clearly, reliably, stably –alternate reference, beyond causal reach, indexical multiple routes to reference beyond causal reach indexical

59 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 fluid AO static aspects –crosscut, but structures themselves are fixed fluid aspects –fluid connection and disconnection of models –models are used to edit code –non-effective models and domain transform idea connect model edit code via model disconnect model

60 Extracting Latent Concerns RegularTracked name() check() print() EmployeeResearch CorePersonnel name() check() print() name() check() print() name() check() print() RegularTracked tax() pay() EmployeeResearch Payroll tax() pay() tax() pay() tax() pay() package Personnel Concern Mapping Feature.CorePersonnel operation taxFeature.Payroll operation payFeature.Payroll class Employee { String name() {...} boolean check() {…} void print() {…} float tax() {...} void pay() {…} … }FeatureClass EmployeeResearchRegularTracked … merge by name Copyright © 2000 IBM Corporation

61 1.use pointcut to identify scattered aspect 2.shows up below 3.delete them all 4.rewrite with advice

62 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 connected non-effective models models that are not sufficiently complete to yield code but can be used to analyze code connect such models using JP mechanism edit code through the model feature analysis? [robillard, murphy] –remove features that are mixed at finer granularity –compose features verification? testing?...

63 © Copyright 2003, Gregor Kiczales. All rights reserved. summary

64 © Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 the fun has just begun JP mechanism is incredibly powerful and deep –connects programs/models/… with different decompositions current accounts of AO are intuitively useful –more work is needed for them to be foundational –thats not surprising, see [Smith] for some ideas on this more fun with programming languages/tools –increase power of JP mechanisms to make languages/tools more practical, more useful, more principled more fun with models –patterns, use cases, more abstract models its a technology of connection across different perspectives –can bridge across software development process???


Download ppt "© Copyright 2003, Gregor Kiczales. All rights reserved. AOSD 2003 the fun has just begun Gregor Kiczales University of British Columbia © Copyright 2003,"

Similar presentations


Ads by Google