AspectOriented Programming with Aspect J the Aspect J

  • Slides: 160
Download presentation
Aspect-Oriented Programming with Aspect. J™ the Aspect. J. org team Xerox PARC Bill Griswold,

Aspect-Oriented Programming with Aspect. J™ the Aspect. J. org team Xerox PARC Bill Griswold, Erik Hilsdale, Jim Hugunin, Mik Kersten, Gregor Kiczales, Jeffrey Palm partially funded by DARPA under contract F 30602 -97 -C 0246 1 Aspect. J Tutorial

this tutorial is about. . . • using AOP and Aspect. J to: –

this tutorial is about. . . • using AOP and Aspect. J to: – improve the modularity of crosscutting concerns • design modularity • source code modularity • development process • aspects are two things: – concerns that crosscut – a programming construct [design level] [implementation level] • enables crosscutting concerns to be captured in modular units • Aspect. J is: – is an aspect-oriented extension to Java™ that supports general-purpose aspect-oriented programming 2 Aspect. J Tutorial

problems like… logging is not modularized • where is logging in org. apache. tomcat

problems like… logging is not modularized • where is logging in org. apache. tomcat 3 – red shows lines of code that handle logging – not in just one place – not even in a small number of places Aspect. J Tutorial

problems like… session expiration is not modularized Standard. Session Application. Session /* * ==================================

problems like… session expiration is not modularized Standard. Session Application. Session /* * ================================== * * 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, 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 * <http: //www. apache. org/>. * * [Additional notices, if required by prior licensing conditions] * */ public void invalidate() { server. Session. remove. Application. Session (context); // remove everything in the session Enumeration enum = values. keys(); while ( enum. has. More. Elements ()) { String name = (String) enum. next. Element (); remove. Value (name); } valid = false; } public boolean is. New () { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new import import import import if ( this. Access. Time == creation. Time ) { return true; } else { return false; } /** * @deprecated */ public void put. Value (String name, Object value) { set. Attribute (name, value); } public void set. Attribute (String name, Object value) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); Illegal. State. Exception (msg); /** * Standard implementation of the <b>Session</b> interface. This object is * serializable , so that it can be stored in persistent storage or transferred * to a different JVM for distributable session support. * <p> * <b>IMPLEMENTATION NOTE</b>: An instance of this class represents both the * internal (Session) and application level (Http. Session ) view of the session. * However, because the class itself is not declared public, Java logic outside * of the <code>org. apache. tomcat. session</code> package cannot cast an * Http. Session view of this instance back to a Session view. * * @author Craig R. Mc. Clanahan * @version $Revision: 1. 2 $ $Date: 2000/05/15 17: 54: 10 $ */ } if (name == null) { String msg = sm. get. String ("application. Session. value. iae"); throw new Illegal. Argument. Exception (msg); } remove. Value (name); final class Standard. Session implements Http. Session , Session { (( Http. Session. Binding. Listener )value). value. Bound (e); } public Object get. Attribute (String name) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new Illegal. State. Exception (msg); } if (name == null) { String msg = sm. get. String ("application. Session. value. iae"); throw new Illegal. Argument. Exception (msg); } implements Http. Session { return values. get(name); private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. session"); private Hashtable values = new Hashtable (); private String id; private Server. Session server. Session ; private Context context; private long creation. Time = System. current. Time. Millis (); ; private long this. Access. Time = creation. Time ; private long last. Accessed = creation. Time ; private int inactive. Interval = -1; private boolean valid = true; String[] value. Names = new String[names. size()]; != -1) { *= 60; throw new Illegal. State. Exception (msg); } Hashtable values. Clone /** * Called by context when request comes in so that accesses and * inactivities can be dealt with accordingly. */ /** * The session identifier of this Session. */ private String id = null; /** * Descriptive information describing this Session implementation. */ private static final String info = "Standard. Session /1. 0"; /** * The Manager with which this Session is associated. */ private Manager manager = null; /** * @deprecated */ /** * 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 max. Inactive. Interval = -1; public void remove. Value (String name) { remove. Attribute (name); } validate(); /** * Flag indicating whether this session is new or } public void remove. Attribute (String name) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); void validate() { // if we have an inactive interval, check to see if we've exceeded it if ( inactive. Interval != -1) { int this. Interval = ( int)(System. current. Time. Millis () - last. Accessed ) / 1000; throw new // Reset the instance variables associated with this Session attributes. clear(); creation. Time = 0 L; id = null; last. Accessed. Time = 0 L; manager = null; max. Inactive. Interval = -1; is. New = true; is. Valid = false; if (name == null) { String msg = sm. get. String ("application. Session. value. iae"); throw new } // ------------------------ Session Package Methods /** * Return the <code> is. Valid </code> flag for this session. */ boolean is. Valid () { flag } // ---------------------- */ private boolean is. New = true; } // HTTP SESSION IMPLEMENTATION METHODS Object o = values. get(name); } /** * Flag indicating whether this session is valid or not. */ private boolean is. Valid = false; if (o instanceof Http. Session. Binding. Listener ) { Http. Session. Binding. Event e = new Http. Session. Binding. Event (this, name); /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. se ssion"); // ------------------------Http. Session Properties // Deserialize the scalar instance variables (except Manager) creation. Time = ((Long) stream. read. Object ()). long. Value (); id = (String) stream. read. Object (); last. Accessed. Time = ((Long) stream. read. Object ()). long. Value (); max. Inactive. Interval = ((Integer) stream. read. Object ()). int. Value (); is. New = ((Boolean) stream. read. Object ()). boolean. Value (); is. Valid = ((Boolean) stream. read. Object ()). boolean. Value (); /** * Return the time when this session was created, in milliseconds since * midnight, January 1, 1970 GMT. * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public long get. Creation. Time () { values. remove(name); } public long get. Creation. Time () { if (valid) { return creation. Time ; } else { String msg = sm. get. String ("application. Session. session. ise"); public void set. Max. Inactive. Interval (int interval) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new Illegal. State. Exception (msg); } inactive. Interval } /** * * @deprecated */ public int get. Max. Inactive. Interval () { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new /** * The current accessed time for this session. */ private long this. Accessed. Time = creation. Time ; = interval; } public Http. Session. Context get. Session. Context () { return new Session. Context. Impl (); } /** * The HTTP session context associated with this session. */ private static Http. Session. Context session. Context = null; return (this. creation. Time ); } /** * 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 Http. Session. Context get. Session. Context () { Illegal. State. Exception (msg); } return inactive. Interval ; } } //------------------------------------ /** * 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 set. Creation. Time (long time) { this. creation. Time = time; this. last. Accessed. Time = time; this. Accessed. Time = time; Illegal. State. Exception (msg); } } } /** * Return the session identifier for this session. */ public String get. Id () { } // -----------------------Http. Session Public Methods } node = attributes. get. Named. Item ("max. Active. Sessions "); if (node != null) { try { set. Max. Active. Sessions (Integer. parse. Int (node. get. Node. Value ())); } catch ( Throwable t) { ; // XXX - Throw exception? } } if ((this. id != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); this. id = id; Server. Sess on } /** * Return descriptive information about this Session implementation and * the corresponding version number, in the format * <code>& lt; description& gt; /< version& gt; </code>. */ public String get. Info () { return (this. info); /** * Return the object bound with the specified name in this session, or * <code>null</code> if no object is bound with that name. * * @ param name Name of the value to be returned * * @exception Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> get. Attribute ()</code> */ public Object get. Value (String name) { return ( get. Attribute (name)); return (this. last. Accessed. Time ); } // Start the background reaper thread. Start (); /** * Return the Manager within which this Session is valid. */ public Manager get. Manager () { Vector results = new Vector(); Enumeration attrs = get. Attribute. Names (); while ( attrs. has. More. Elements ()) { String attr = (String) attrs. next. Element (); results. add. Element (attr); } String names[] = new String[results. size()]; for ( int i = 0; i < names. length; i++) names[i] = (String) results. element. At (i); return (names); return (this. manager); } /** * Set the Manager within which this Session is valid. * * @ param manager The new Manager */ public void set. Manager (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 Illegal. State. Exception if this method is called on * an invalidated session */ public int get. Max. Inactive. Interval () { return (this. max. Inactive. Interval ); } /** * Set 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. * * @ param interval The new maximum interval */ public void set. Max. Inactive. Interval (int interval) { this. max. Inactive. Interval = interval; 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 <code>Enumeration</code> * and will be removed in a future version of the API. */ public Enumeration get. Ids () { } return (dummy. elements()); /** * Invalidates this session and unbinds any objects bound to it. * * @exception Illegal. State. Exception if this method is called on * an invalidated session */ public void invalidate() { Server. Session. Manager /** * Return the <code> Http. Session </code> 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 Http. Session get. Session (String id) { // Cause this session to expire(); } return (null); /** * Return <code>true</code> 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 Illegal. State. Exception if this method is called on an * invalidated session */ public boolean is. New () { return (this. New ); } { // Stop the background reaper thread. Stop (); // Expire all active sessions Session sessions[] = find. Sessions (); for ( int i = 0; i < sessions. length; i++) { Standard. Session session = ( Standard. Session ) sessions[i]; if (!session. is. Valid ()) continue; session. expire(); } /** * Set the check interval (in seconds) for this Manager. * * @ param check. Interval The new check interval */ public void set. Check. Interval (int check. Interval ) { } this. check. Interval = check. Interval ; } // ---------------------------- Private Methods /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <code>& lt; description& gt; /< version& gt; </code>. */ public String get. Info () { /** * Invalidate all sessions that have expired. */ private void process. Expires () { long time. Now = System. current. Time. Millis (); Session sessions[] = find. Sessions (); return (this. info); // 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. package org. apache. tomcat. session; import org. apache. tomcat. util. *; import org. apache. tomcat. core. *; import java. io. *; import java. net. *; import java. util. *; import javax. servlet. http. *; synchronized void reap() { Enumeration enum = sessions. keys(); /** * * @author James Duncan Davidson [ duncan @eng. sun. com] * @author Jason Hunter [ jch@eng. sun. com] * @author James Todd [gonzo@eng. sun. com] */ public class Server. Session. Manager implements Session. Manager { while ( enum. has. More. Elements ()) { Object key = enum. next. Element (); Server. Session session = ( Server. Session )sessions. get(key); session. reap(); session. validate(); for ( int i = 0; i < sessions. length; i++) { Standard. Session session = ( Standard. Session ) sessions[i]; if (!session. is. Valid ()) continue; int max. Inactive. Interval = session. get. Max. Inactive. Interval (); if ( max. Inactive. Interval < 0) continue; int time. Idle = // Truncate, do not round up ( int) (( time. Now - session. get. Last. Accessed. Time ()) / 1000 L); if ( time. Idle >= max. Inactive. Interval ) session. expire(); } } /** * Return the maximum number of active Sessions allowed, or -1 for * no limit. */ public int get. Max. Active. Sessions () { return (this. max. Active. Sessions ); } } synchronized void remove. Session (Server. Session session) { String id = session. get. Id (); private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. session"); private static Server. Session. Manager manager; // = new Server. Session. Manager (); session. invalidate(); sessions. remove(id); /** * Set the maximum number of actives Sessions allowed, or -1 for * no limit. * * @ param max The new maximum number of sessions */ public void set. Max. Active. Sessions (int max) { /** * Sleep for the duration specified by the <code> * property. */ private void thread. Sleep () { static { manager = new } this. max. Active. Sessions = -1; public void remove. Sessions (Context context) { Enumera private Server. Session. Manager () { reaper = Reaper. get. Reaper (); reaper. set. Server. Session. Manager (this); reaper. start(); } // ----------------------------- Public Methods } /** * Construct and return a new session object, based on the default * settings specified by this Manager's properties. The session * id will be assigned by this method, and available via the get. Id () * method of the returned session. If a new session cannot be created * for any reason, return <code>null</code>. * * @exception Illegal. State. Exception if a new session cannot be * instantiated for any reason */ public Session create. Session () { /** * Start the background thread that will periodically check for * session timeouts. */ private void thread. Start () { public void accessed( Context ctx, Request req, String id ) { Application. Session ap. S =(Application. Session )find. Session ( ctx, id); if( ap. S==null) return; // cache it - no need to compute it again req. set. Session ( ap. S ); if (thread != null) return; thread. Done = false; thread = new Thread(this, thread. set. Daemon (true); thread. start(); if (( max. Active. Sessions >= 0) && (sessions. size() >= max. Active. Sessions )) throw new Illegal. State. Exception (sm. get. String ("standard. Manager. create. Session. ise")); Server. Session serv. S =ap. S. get. Server. Session (); serv. S. accessed(); ap. S. accessed(); } } = max; } Server. Session. Manager (); private Hashtable sessions = new Hashtable (); private Reaper reaper; thread. Name ); } /** * Stop the background thread that is periodically checking for * session timeouts. */ private void thread. Stop () { return (super. create. Session ()); } } if (thread == null) return; public Http. Session create. Session (Context ctx) { String session. Id = Session. Id. Generator. generate. Id (); Server. Session session = new Server. Session (session. Id ); sessions. put( session. Id , session); thread. Done = true; thread. interrupt(); try { thread. join(); } catch ( Interrupted. Exception ; } if(-1 != inactive. Interval ) { session. set. Max. Inactive. Interval (inactive. Interval ); } return session. get. Application. Session ( ctx, true ); } e) { thread = null; public Http. Session find. Session (Context ctx, String id) { Server. Session s. Session =(Server. Session )sessions. get(id); if( s. Session ==null) return null; } return s. Session. get. Application. Session (ctx, false); // --------------------------- Background Thread } /** * The background thread that checks for session timeouts and shutdown. */ public void run() { // Loop until the termination semaphore is set while (! thread. Done ) { thread. Sleep (); process. Expires (); } } } Aspec J Tu or a check. Interval </code> try { Thread. sleep( check. Interval * 1000 L); } catch ( Interrupted. Exception e) { ; } } protected int inactive. Interval } 4 Http. Session - avoid another find req. set. Session ( session ); } Once we commit to the new Manager/Session // XXX should we throw exception or just return null ? ? public Http. Session find. Session ( Context ctx , String id ) { try { The Tomcat. Next "Manager" interface acts more like a Session session = manager. find. Session (id); * collection class, and has minimal knowledge of the detailed request if(session!=null) * processing semantics of handling sessions. return session. get. Session (); * <p> * XXX - At present, there is no way (via the for } catch ( IOException e) { Session. Manager interface) } return (null); * a Context to tell the Manager that we create what the default session } * timeout for this web application (specified in the deployment descriptor) * should be. public Http. Session create. Session (Context ctx ) { * return * @author Craig R. Mc. Clanahan manager. create. Session (). get. Session (); } */ public final class Standard. Session. Manager * Remove all sessions because our associated Context is being shut down. implements Session. Manager { * * @ param ctx The context that is being shut down */ // -----------------------------Constructors public void remove. Sessions (Context ctx ) { // contexts, we just want to remove the sessions of Session. Manager that adapts to the corresponding ctx ! // The manager will still run after that ( i. e. keep database // connection open * implementation. if (manager */ instanceof Lifecycle) { try { public Standard. Session. Manager () { ((Lifecycle) manager). stop(); manager = new if (manager } catch ( Lifecycle. Exception Standard. Manager (); throw new instanceof Lifecycle) { Illegal. State. Exception ("" + e); } try { } ((Lifecycle) manager). configure(null); ((Lifecycle) manager). start(); } catch ( Lifecycle. Exception throw new } e) { Illegal. State. Exception ("" + e); /** } } * Used by context to configure the session manager's inactivity timeout. * * The Session. Manager may have some default session time out, the * Context on the other hand has it's timeout set by the deployment } public static Server. Session. Manager get. Manager () { return manager; } } // cache the * <b>IMPLEMENTATION NOTE</b>: * paradigm, I would suggest moving the logic implemented here back into * the core level. * descriptor (web. xml). This method lets the Context // Validate and update our current component state if (!started) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. not. Started ")); started = false; return (this. check. Interval ); // ------------------------------- Private Class implements Http. Session. Context ((Session) session). access(); Session. Manager * and lifecycle configuration is not supported. * <p> conforgure the * session manager according to this value. * * @ param minutes The session inactivity timeout in minutes. */ /** public void set. Session. Time. Out (int minutes) { * The Manager implementation we are actually using. if(-1 != minutes) { */ // The manager works with seconds. . . private Manager manager = null; manager. set. Max. Inactive. Interval (minutes * 60); } } /** * This class is a dummy implementation of the <code> Http. Session. Context </code> * interface, to conform to the requirement that such an object be returned * when <code> Http. Session. get. Session. Context ()</code> is called. * * @author Craig R. Mc. Clanahan * * @deprecated As of Java Servlet API 2. 1 with no replacement. The * interface will be removed in a future version of this API. */ instanceof Session) * that adapts to the new component-based Manager implementation. * <p> * XXX - At present, use of <code> Standard. Manager </code> is hard coded, // --------------------------- Instance Variables /** * Return the check interval (in seconds) for this Manager. */ public int get. Check. Interval () { } final class Standard. Session. Context * Specialized implementation of org. apache. tomcat. core. } /** * Gracefully terminate the active use of the public methods of this * component. This method should be the last one called on a given * instance of this component. * * @exception Illegal. State. Exception if this component has not been started * @exception Illegal. State. Exception if this component has already * been stopped * @exception Lifecycle. Exception if this component detects a fatal error * that needs to be reported */ public void stop() throws Lifecycle. Exception { // ------------------------------- Properties static advice( Standard. Session s): invalidate(s) { before { if (!s. is. Valid ()) throw new Illegal. State. Exception (s. sm. get. String ("standard. Session. " + this. Join. Point. method. Name + ". ise")); } } ctx , Request req , String id) { session= find. Session (ctx, id); if( session == null) return; if (session } /** * Name to register for the background thread. */ private String thread. Name = "Standard. Manager "; } /** * Return the set of names of objects bound to this session. If there * are no such objects, a zero-length array is returned. * * @exception Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> get. Attribute. Names ()</code> */ public String[] get. Value. Names () { Http. Session /** // Validate and update our current component state if (!configured) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. not. Configured ")); if (started) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. already. Started ")); started = true; /** * The background thread completion semaphore. */ private boolean thread. Done = false; } /** * 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 get. Last. Accessed. Time () { * @ param session The session to be marked public void accessed(Context // XXX a manager may be shared by multiple /** * The background thread. */ private Thread thread = null; crosscut invalidate( Standard. Session s): s & ( int get. Max. Inactive. Interval () | long get. Creation. Time () | Object get. Attribute (String) | Enumeration get. Attribute. Names () | String[] get. Value. Names () | void invalidate() | boolean is. New () | void remove. Attribute (String) | void set. Attribute (String, Object)); } This should be Request. Interceptor. * */ import org. apache. tomcat. core. Session. Manager ; import org. apache. tomcat. util. Session. Util ; /** * Has this component been started yet? */ private boolean started = false; } return (attributes. keys()); if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). add(this); * Mark the specified session's last accessed time. * called for each request by a import org. apache. tomcat. core. Request; import org. apache. tomcat. core. Response; * Create a new Manager * Prepare for the beginning of active use of the public methods of this * component. This method should be called after <code>configure()</code>, * and before any of the public methods of the component are utilized. * * @exception Illegal. State. Exception if this component has not yet been * configured (if required for this component) * @exception Illegal. State. Exception if this component has already been * started * @exception Lifecycle. Exception if this component detects a fatal error * that prevents this component from being used */ public void start() throws Lifecycle. Exception { /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. session"); // Serialize the attribute count and the attribute values stream. write. Object (new Integer(results. size())); Enumeration names = results. elements(); while (names. has. More. Elements ()) { String name = (String) names. next. Element (); stream. write. Object (name); stream. write. Object (attributes. get(name)); } /** * Return an <code>Enumeration</code> of <code>String</code> objects * containing the names of the objects bound to this session. * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public Enumeration get. Attribute. Names () { /** import org. apache. tomcat. catalina. *; import org. apache. tomcat. core. Context; } /** * The maximum number of active Sessions allowed, or -1 for no limit. */ protected int max. Active. Sessions = -1; } /** * Set the session identifier for this session. * * @ param id The new session identifier */ public void set. Id (String id) { import javax. servlet. http. Cookie; import javax. servlet. http. Http. Session ; /** node = attributes. get. Named. Item ("max. Inactive. Interval "); if (node != null) { try { set. Max. Inactive. Interval (Integer. parse. Int (node. get. Node. Value ())); } catch ( Throwable t) { ; // XXX - Throw exception? } } /** * The descriptive information about this implementation. */ private static final String info = " Standard. Manager /1. 0"; // Accumulate the names of serializable attributes Vector results = new Vector(); Enumeration attrs = get. Attribute. Names (); while ( attrs. has. More. Elements ()) { String attr = (String) attrs. next. Element (); Object value = attributes. get( attr); if (value instanceof Serializable ) results. add. Element (attr); } return (attributes. get(name)); return (this. id); node = attributes. get. Named. Item ("check. Interval "); if (node != null) { try { set. Check. Interval (Integer. parse. Int (node. get. Node. Value ())); } catch ( Throwable t) { ; // XXX - Throw exception? } } /** * Has this component been configured yet? */ private boolean configured = false; // Write the scalar instance variables (except Manager) stream. write. Object (new Long( creation. Time )); stream. write. Object (id); stream. write. Object (new Long( last. Accessed. Time )); stream. write. Object (new Integer( max. Inactive. Interval )); stream. write. Object (new Boolean( is. New )); stream. write. Object (new Boolean( is. Valid )); /** * Return the object bound with the specified name in this session, or * <code>null</code> if no object is bound with that name. * * @ param name Name of the attribute to be returned * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public Object get. Attribute (String name) { // Parse and process our configuration parameters if (!("Manager". equals(parameters. get. Node. Name ()))) return; Named. Node. Map attributes = parameters. get. Attributes (); Node node = null; /** * The interval (in seconds) between checks for expired sessions. */ private int check. Interval = 60; /** * Write a serialized version of this session object to the specified * object output stream. * <p> * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored * in the serialized representation of this Session. After calling * <code> read. Object ()</code>, you must set the associated Manager * explicitly. * <p> * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable * will be silently ignored. If you do not want any such attributes, * be sure the <code>distributable</code> property of our associated * Manager is set to <code>true</code>. * * @ param stream The output stream to write to * * @exception IOException if an input/output error occurs */ private void write. Object (Object. Output. Stream stream) throws IOException { if ( session. Context == null) session. Context = new Standard. Session. Context (); return ( session. Context ); // Validate and update our current component state if (configured) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. already. Configured ")); configured = true; if (parameters == null) return; // --------------------------- Instance Variables } // -------------------------- Session Properties import java. io. IOException ; /** * Configure this component, based on the specified configuration * parameters. This method should be called immediately after the * component instance is created, and before <code>start()</code> * is called. * * @ parameters Configuration parameters for this component * (<B>FIXME: What object type should this really be? ) * * @exception Illegal. State. Exception if this component has already been * configured and/or started * @exception Lifecycle. Exception if this component detects a fatal error * in the configuration parameters it was given */ public void configure(Node parameters) throws Lifecycle. Exception { public final class Standard. Manager extends Manager. Base implements Lifecycle, Runnable { // Deserialize the attribute count and attribute values int n = ((Integer) stream. read. Object ()). int. Value (); for ( int i = 0; i < n; i++) { String name = (String) stream. read. Object (); Object value = (Object) stream. read. Object (); attributes. put(name, value); } (( Http. Session. Binding. Listener )o). value. Unbound (e); } Illegal. State. Exception (msg); } } Http. Session Private Methods /** * Read a serialized version of this session object from the specified * object input stream. * <p> * <b>IMPLEMENTATION NOTE</b>: 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 Class. Not. Found. Exception if an unknown class is specified * @exception IOException if an input/output error occurs */ private void read. Object (Object. Input. Stream stream) throws Class. Not. Found. Exception , IOException { this. Valid = is. Valid ; java. io. IOException ; java. util. Enumeration; java. util. Hashtable ; java. util. Vector; org. apache. tomcat. catalina. *; javax. servlet. http. Cookie; javax. servlet. http. Http. Session ; org. apache. tomcat. util. String. Manager ; org. w 3 c. dom. Named. Node. Map ; org. w 3 c. dom. Node; /** * Standard implementation of the <b>Manager</b> interface that provides * no session persistence or distributable capabilities, but does support * an optional, configurable, maximum number of active sessions allowed. * <p> * Lifecycle configuration of this component assumes an XML node * in the following format: * <code> * & lt; Manager class. Name ="org. apache. tomcat. session. Standard. Manager " * check. Interval ="60" max. Active. Sessions ="-1" * max. Inactive. Interval ="-1" /> * </code> * where you can adjust the following parameters, with default values * in square brackets: * <ul> * <li><b>check. Interval </b> - The interval (in seconds) between background * thread checks for expired sessions. [60] * <li><b>max. Active. Sessions </b> - The maximum number of sessions allowed to * be active at once, or -1 for no limit. [-1] * <li><b>max. Inactive. Interval </b> - The default maximum number of seconds of * inactivity before which the servlet container is allowed to time out * a session, or -1 for no limit. This value should be overridden from * the default session timeout specified in the web application deployment * descriptor, if any. [-1] * </ ul> * * @author Craig R. Mc. Clanahan * @version $Revision: 1. 1 $ $Date: 2000/05/02 21: 28: 30 $ */ this. New = is. New ; } /** * Set the <code> is. Valid </code> flag for this session. * * @ param is. Valid The new value for the <code> is. Valid </code> flag */ void set. Valid (boolean is. Valid ) { // ----------------------------- Public Methods // --------------------------- Lifecycle Methods synchronized (attributes) { remove. Attribute (name); attributes. put(name, value); if (value instanceof Http. Session. Binding. Listener ) (( Http. Session. Binding. Listener ) value). value. Bound (new Http. Session. Binding. Event ((Http. Session ) this, name)); } /** * Set the <code> is. New </code> flag for this session. * * @ param is. New The new value for the <code> is. New </code> Standard. Session. Manager package org. apache. tomcat. session; import import import if ((manager != null) && manager. get. Distributable () && !(value instanceof Serializable )) throw new Illegal. Argument. Exception (sm. get. String ("standard. Session. set. Attribute. iae")); return (this. Valid ); } Standard. Manager Sess on n ercep or /** * 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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Bound ()</code> 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 Illegal. Argument. Exception if an attempt is made to add a * non- serializable object in an environment marked distributable. * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public void set. Attribute (String name, Object value) { not. Illegal. Argument. Exception (msg); } public String get. Id () { if (valid) { return id; } else { String msg = sm. get. String ("application. Session. session. ise"); remove. Attribute (name); } // Tell our Manager that this Session has been recycled if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). recycle(this); Illegal. State. Exception (msg); } if ( this. Interval > inactive. Interval ) { invalidate(); } } /** * 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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Unbound ()</code> on the object. * * @ param name Name of the object to remove from this session. * * @exception Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> remove. Attribute ()</code> */ public void remove. Value (String name) { */ void set. New (boolean is. New ) { = ( Hashtable )values. clone(); return (Enumeration) values. Clone. keys(); } void accessed() { // set last accessed to this. Access. Time as it will be left over // from the previous access last. Accessed = this. Access. Time ; this. Access. Time = System. current. Time. Millis (); } /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { /** * The last accessed time for this Session. */ private long last. Accessed. Time = creation. Time ; public Enumeration get. Attribute. Names () { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); Server. Session get. Server. Session () { return server. Session ; } throw new // Unbind any objects associated with this session Vector results = new Vector(); Enumeration attrs = get. Attribute. Names (); while ( attrs. has. More. Elements ()) { String attr = (String) attrs. next. Element (); results. add. Element (attr); } Enumeration names = results. elements(); while (names. has. More. Elements ()) { String name = (String) names. next. Element (); remove. Attribute (name); } names. copy. Into (value. Names ); } synchronized (attributes) { Object object = attributes. get(name); if (object == null) return; attributes. remove(name); // System. out. println ( "Removing attribute " + name ); if (object instanceof Http. Session. Binding. Listener ) { (( Http. Session. Binding. Listener ) object). value. Unbound (new Http. Session. Binding. Event ((Http. Session ) this, name)); } } if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); /** * The time this session was created, in milliseconds since midnight, * January 1, 1970 GMT. */ private long creation. Time = 0 L; return value. Names ; public long get. Last. Accessed. Time () { if (valid) { return last. Accessed ; } else { String msg = sm. get. String ("application. Session. session. ise"); // Remove this session from our manager's active sessions // Mark this session as invalid set. Valid (false); /** * The collection of user data attributes associated with this Session. */ private Hashtable attributes = new Hashtable (); = context. get. Session. Time. Out (); } /** * 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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Unbound ()</code> on the object. * * @ param name Name of the object to remove from this session. * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public void remove. Attribute (String name) { } // -------------------------- Instance Variables /** * @deprecated */ public String[] get. Value. Names () { Enumeration e = get. Attribute. Names (); Vector names = new Vector(); while (e. has. More. Elements ()) { names. add. Element (e. next. Element ()); } set. Attribute (name, value); } = this. Accessed. Time ; = System. current. Time. Millis (); /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. */ public void expire() { } } throw new this. last. Accessed. Time this. New =false; } /** * Construct a new Session associated with the specified Manager. * * @ param manager The manager with which this Session is associated */ public Standard. Session (Manager manager) { } Application. Session (String id, Server. Session server. Session , Context context) { this. server. Session = server. Session ; this. context = context; this. id = id; throw new /** * 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() { super(); this. manager = manager; /** * 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] */ if (this. inactive. Interval // ------------------------Session Public Methods values. put(name, value); /** * @deprecated */ public Object get. Value (String name) { return get. Attribute (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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Bound ()</code> 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 Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> set. Attribute ()</code> */ public void put. Value (String name, Object value) { return (( Http. Session ) this); } // ----------------------------- Constructors } package org. apache. tomcat. session; this. inactive. Interval /** * Return the <code> Http. Session </code> for which this object * is the facade. */ public Http. Session get. Session () { // remove any existing binding if (value != null && value instanceof Http. Session. Binding. Listener ) { Http. Session. Binding. Event e = new Http. Session. Binding. Event (this, name); import org. apache. tomcat. core. *; import org. apache. tomcat. util. String. Manager ; import java. io. *; import java. net. *; import java. util. *; import javax. servlet. http. *; public class Application. Session /** java. io. IOException ; java. io. Object. Input. Stream ; java. io. Object. Output. Stream ; java. io. Serializable ; java. util. Enumeration; java. util. Hashtable ; java. util. Vector; javax. servlet. Servlet. Exception ; javax. servlet. http. Http. Session. Binding. Event ; javax. servlet. http. Http. Session. Binding. Listener ; javax. servlet. http. Http. Session. Context ; org. apache. tomcat. catalina. *; org. apache. tomcat. util. String. Manager ; Illegal. State. Exception (msg); } } throw new package org. apache. tomcat. session; }

problems like… session tracking is not modularized HTTPRequest get. Cookies() get. Request. URI()(doc) get.

problems like… session tracking is not modularized HTTPRequest get. Cookies() get. Request. URI()(doc) get. Session() get. Requested. Session. Id(). . . Session. Interceptor request. Map(request) before. Body(req, resp). . . Session HTTPResponse get. Attribute(name) set. Attribute(name, val) invalidate(). . . get. Request() set. Content. Type(content. Type) get. Outptut. Stream() set. Session. Id(id). . . Servlet 5 Aspect. J Tutorial

the cost of tangled code • redundant code – same fragment of code in

the cost of tangled code • redundant code – same fragment of code in many places • difficult to reason about – non-explicit structure – the big picture of the tangling isn’t clear • difficult to change – have to find all the code involved – and be sure to change it consistently – and be sure not to break it by accident 6 Aspect. J Tutorial

crosscutting concerns HTTPRequest get. Cookies() get. Request. URI()(doc) get. Session() get. Requested. Session. Id().

crosscutting concerns HTTPRequest get. Cookies() get. Request. URI()(doc) get. Session() get. Requested. Session. Id(). . . Session. Interceptor request. Map(request) before. Body(req, resp). . . Session HTTPResponse get. Attribute(name) set. Attribute(name, val) invalidate(). . . get. Request() set. Content. Type(content. Type) get. Outptut. Stream() set. Session. Id(id). . . Servlet 7 Aspect. J Tutorial

the AOP idea aspect-oriented programming • crosscutting is inherent in complex systems • crosscutting

the AOP idea aspect-oriented programming • crosscutting is inherent in complex systems • crosscutting concerns – have a clear purpose – have a natural structure • defined set of methods, module boundary crossings, points of resource utilization, lines of dataflow… • so, let’s capture the structure of crosscutting concerns explicitly. . . – in a modular way – with linguistic and tool support • aspects are – well-modularized crosscutting concerns 8 Aspect. J Tutorial

language support to… App ca on. Sess on Application. Session /* * ================================== *

language support to… App ca on. Sess on Application. Session /* * ================================== * * 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, 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 * <http: //www. apache. org/>. * * [Additional notices, if required by prior licensing conditions] * */ public void invalidate() { server. Session. remove. Application. Session (context); // remove everything in the session Enumeration enum = values. keys(); while ( enum. has. More. Elements ()) { String name = (String) enum. next. Element (); remove. Value (name); } valid = false; } public boolean is. New () { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new import import import import if ( this. Access. Time == creation. Time ) { return true; } else { return false; } /** * @deprecated */ public void put. Value (String name, Object value) { set. Attribute (name, value); } public void set. Attribute (String name, Object value) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); Illegal. State. Exception (msg); /** * Standard implementation of the <b>Session</b> interface. This object is * serializable , so that it can be stored in persistent storage or transferred * to a different JVM for distributable session support. * <p> * <b>IMPLEMENTATION NOTE</b>: An instance of this class represents both the * internal (Session) and application level (Http. Session ) view of the session. * However, because the class itself is not declared public, Java logic outside * of the <code>org. apache. tomcat. session</code> package cannot cast an * Http. Session view of this instance back to a Session view. * * @author Craig R. Mc. Clanahan * @version $Revision: 1. 2 $ $Date: 2000/05/15 17: 54: 10 $ */ } if (name == null) { String msg = sm. get. String ("application. Session. value. iae"); throw new Illegal. Argument. Exception (msg); } remove. Value (name); final class Standard. Session implements Http. Session , Session { (( Http. Session. Binding. Listener )value). value. Bound (e); } public Object get. Attribute (String name) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new Illegal. State. Exception (msg); } if (name == null) { String msg = sm. get. String ("application. Session. value. iae"); throw new Illegal. Argument. Exception (msg); } implements Http. Session { return values. get(name); private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. session"); private Hashtable values = new Hashtable (); private String id; private Server. Session server. Session ; private Context context; private long creation. Time = System. current. Time. Millis (); ; private long this. Access. Time = creation. Time ; private long last. Accessed = creation. Time ; private int inactive. Interval = -1; private boolean valid = true; String[] value. Names = new String[names. size()]; != -1) { *= 60; throw new Illegal. State. Exception (msg); } Hashtable values. Clone /** * Called by context when request comes in so that accesses and * inactivities can be dealt with accordingly. */ /** * The session identifier of this Session. */ private String id = null; /** * Descriptive information describing this Session implementation. */ private static final String info = "Standard. Session /1. 0"; /** * The Manager with which this Session is associated. */ private Manager manager = null; /** * @deprecated */ /** * 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 max. Inactive. Interval = -1; public void remove. Value (String name) { remove. Attribute (name); } validate(); /** * Flag indicating whether this session is new or } public void remove. Attribute (String name) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); void validate() { // if we have an inactive interval, check to see if we've exceeded it if ( inactive. Interval != -1) { int this. Interval = ( int)(System. current. Time. Millis () - last. Accessed ) / 1000; throw new // Reset the instance variables associated with this Session attributes. clear(); creation. Time = 0 L; id = null; last. Accessed. Time = 0 L; manager = null; max. Inactive. Interval = -1; is. New = true; is. Valid = false; if (name == null) { String msg = sm. get. String ("application. Session. value. iae"); throw new } // ------------------------ Session Package Methods /** * Return the <code> is. Valid </code> flag for this session. */ boolean is. Valid () { flag } // ---------------------- */ private boolean is. New = true; } // HTTP SESSION IMPLEMENTATION METHODS Object o = values. get(name); } /** * Flag indicating whether this session is valid or not. */ private boolean is. Valid = false; if (o instanceof Http. Session. Binding. Listener ) { Http. Session. Binding. Event e = new Http. Session. Binding. Event (this, name); /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. se ssion"); // ------------------------Http. Session Properties // Deserialize the scalar instance variables (except Manager) creation. Time = ((Long) stream. read. Object ()). long. Value (); id = (String) stream. read. Object (); last. Accessed. Time = ((Long) stream. read. Object ()). long. Value (); max. Inactive. Interval = ((Integer) stream. read. Object ()). int. Value (); is. New = ((Boolean) stream. read. Object ()). boolean. Value (); is. Valid = ((Boolean) stream. read. Object ()). boolean. Value (); /** * Return the time when this session was created, in milliseconds since * midnight, January 1, 1970 GMT. * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public long get. Creation. Time () { values. remove(name); } public long get. Creation. Time () { if (valid) { return creation. Time ; } else { String msg = sm. get. String ("application. Session. session. ise"); public void set. Max. Inactive. Interval (int interval) { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new Illegal. State. Exception (msg); } inactive. Interval } /** * * @deprecated */ public int get. Max. Inactive. Interval () { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); throw new /** * The current accessed time for this session. */ private long this. Accessed. Time = creation. Time ; = interval; } public Http. Session. Context get. Session. Context () { return new Session. Context. Impl (); } /** * The HTTP session context associated with this session. */ private static Http. Session. Context session. Context = null; return (this. creation. Time ); } /** * 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 Http. Session. Context get. Session. Context () { Illegal. State. Exception (msg); } return inactive. Interval ; } } //------------------------------------ /** * 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 set. Creation. Time (long time) { this. creation. Time = time; this. last. Accessed. Time = time; this. Accessed. Time = time; Illegal. State. Exception (msg); } } } /** * Return the session identifier for this session. */ public String get. Id () { } // -----------------------Http. Session Public Methods } node = attributes. get. Named. Item ("max. Active. Sessions "); if (node != null) { try { set. Max. Active. Sessions (Integer. parse. Int (node. get. Node. Value ())); } catch ( Throwable t) { ; // XXX - Throw exception? } } if ((this. id != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); this. id = id; Server. Sess on } /** * Return descriptive information about this Session implementation and * the corresponding version number, in the format * <code>& lt; description& gt; /< version& gt; </code>. */ public String get. Info () { return (this. info); /** * Return the object bound with the specified name in this session, or * <code>null</code> if no object is bound with that name. * * @ param name Name of the value to be returned * * @exception Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> get. Attribute ()</code> */ public Object get. Value (String name) { return ( get. Attribute (name)); return (this. last. Accessed. Time ); } // Start the background reaper thread. Start (); /** * Return the Manager within which this Session is valid. */ public Manager get. Manager () { Vector results = new Vector(); Enumeration attrs = get. Attribute. Names (); while ( attrs. has. More. Elements ()) { String attr = (String) attrs. next. Element (); results. add. Element (attr); } String names[] = new String[results. size()]; for ( int i = 0; i < names. length; i++) names[i] = (String) results. element. At (i); return (names); return (this. manager); } /** * Set the Manager within which this Session is valid. * * @ param manager The new Manager */ public void set. Manager (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 Illegal. State. Exception if this method is called on * an invalidated session */ public int get. Max. Inactive. Interval () { return (this. max. Inactive. Interval ); } /** * Set 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. * * @ param interval The new maximum interval */ public void set. Max. Inactive. Interval (int interval) { this. max. Inactive. Interval = interval; 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 <code>Enumeration</code> * and will be removed in a future version of the API. */ public Enumeration get. Ids () { } return (dummy. elements()); /** * Invalidates this session and unbinds any objects bound to it. * * @exception Illegal. State. Exception if this method is called on * an invalidated session */ public void invalidate() { Server. Session. Manager Server. Sess on. Manager /** * Return the <code> Http. Session </code> 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 Http. Session get. Session (String id) { // Cause this session to expire(); } return (null); /** * Return <code>true</code> 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 Illegal. State. Exception if this method is called on an * invalidated session */ public boolean is. New () { return (this. New ); } { // Stop the background reaper thread. Stop (); // Expire all active sessions Session sessions[] = find. Sessions (); for ( int i = 0; i < sessions. length; i++) { Standard. Session session = ( Standard. Session ) sessions[i]; if (!session. is. Valid ()) continue; session. expire(); } /** * Set the check interval (in seconds) for this Manager. * * @ param check. Interval The new check interval */ public void set. Check. Interval (int check. Interval ) { } this. check. Interval = check. Interval ; } // ---------------------------- Private Methods /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <code>& lt; description& gt; /< version& gt; </code>. */ public String get. Info () { /** * Invalidate all sessions that have expired. */ private void process. Expires () { long time. Now = System. current. Time. Millis (); Session sessions[] = find. Sessions (); return (this. info); // 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. package org. apache. tomcat. session; import org. apache. tomcat. util. *; import org. apache. tomcat. core. *; import java. io. *; import java. net. *; import java. util. *; import javax. servlet. http. *; synchronized void reap() { Enumeration enum = sessions. keys(); /** * * @author James Duncan Davidson [ duncan @eng. sun. com] * @author Jason Hunter [ jch@eng. sun. com] * @author James Todd [gonzo@eng. sun. com] */ public class Server. Session. Manager implements Session. Manager { while ( enum. has. More. Elements ()) { Object key = enum. next. Element (); Server. Session session = ( Server. Session )sessions. get(key); session. reap(); session. validate(); for ( int i = 0; i < sessions. length; i++) { Standard. Session session = ( Standard. Session ) sessions[i]; if (!session. is. Valid ()) continue; int max. Inactive. Interval = session. get. Max. Inactive. Interval (); if ( max. Inactive. Interval < 0) continue; int time. Idle = // Truncate, do not round up ( int) (( time. Now - session. get. Last. Accessed. Time ()) / 1000 L); if ( time. Idle >= max. Inactive. Interval ) session. expire(); } } /** * Return the maximum number of active Sessions allowed, or -1 for * no limit. */ public int get. Max. Active. Sessions () { return (this. max. Active. Sessions ); } } synchronized void remove. Session (Server. Session session) { String id = session. get. Id (); private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. session"); private static Server. Session. Manager manager; // = new Server. Session. Manager (); session. invalidate(); sessions. remove(id); /** * Set the maximum number of actives Sessions allowed, or -1 for * no limit. * * @ param max The new maximum number of sessions */ public void set. Max. Active. Sessions (int max) { /** * Sleep for the duration specified by the <code> * property. */ private void thread. Sleep () { static { manager = new } this. max. Active. Sessions = -1; public void remove. Sessions (Context context) { Enumera private Server. Session. Manager () { reaper = Reaper. get. Reaper (); reaper. set. Server. Session. Manager (this); reaper. start(); } // ----------------------------- Public Methods } /** * Construct and return a new session object, based on the default * settings specified by this Manager's properties. The session * id will be assigned by this method, and available via the get. Id () * method of the returned session. If a new session cannot be created * for any reason, return <code>null</code>. * * @exception Illegal. State. Exception if a new session cannot be * instantiated for any reason */ public Session create. Session () { /** * Start the background thread that will periodically check for * session timeouts. */ private void thread. Start () { public void accessed( Context ctx, Request req, String id ) { Application. Session ap. S =(Application. Session )find. Session ( ctx, id); if( ap. S==null) return; // cache it - no need to compute it again req. set. Session ( ap. S ); if (thread != null) return; thread. Done = false; thread = new Thread(this, thread. set. Daemon (true); thread. start(); if (( max. Active. Sessions >= 0) && (sessions. size() >= max. Active. Sessions )) throw new Illegal. State. Exception (sm. get. String ("standard. Manager. create. Session. ise")); Server. Session serv. S =ap. S. get. Server. Session (); serv. S. accessed(); ap. S. accessed(); } } = max; } Server. Session. Manager (); private Hashtable sessions = new Hashtable (); private Reaper reaper; thread. Name ); } /** * Stop the background thread that is periodically checking for * session timeouts. */ private void thread. Stop () { return (super. create. Session ()); } } if (thread == null) return; public Http. Session create. Session (Context ctx) { String session. Id = Session. Id. Generator. generate. Id (); Server. Session session = new Server. Session (session. Id ); sessions. put( session. Id , session); thread. Done = true; thread. interrupt(); try { thread. join(); } catch ( Interrupted. Exception ; } if(-1 != inactive. Interval ) { session. set. Max. Inactive. Interval (inactive. Interval ); } return session. get. Application. Session ( ctx, true ); } e) { thread = null; public Http. Session find. Session (Context ctx, String id) { Server. Session s. Session =(Server. Session )sessions. get(id); if( s. Session ==null) return null; } return s. Session. get. Application. Session (ctx, false); // --------------------------- Background Thread } /** * The background thread that checks for session timeouts and shutdown. */ public void run() { // Loop until the termination semaphore is set while (! thread. Done ) { thread. Sleep (); process. Expires (); } } } Aspec J Tu or a check. Interval </code> try { Thread. sleep( check. Interval * 1000 L); } catch ( Interrupted. Exception e) { ; } } protected int inactive. Interval } 9 Http. Session - avoid another find req. set. Session ( session ); } Once we commit to the new Manager/Session // XXX should we throw exception or just return null ? ? public Http. Session find. Session ( Context ctx , String id ) { try { The Tomcat. Next "Manager" interface acts more like a Session session = manager. find. Session (id); * collection class, and has minimal knowledge of the detailed request if(session!=null) * processing semantics of handling sessions. return session. get. Session (); * <p> * XXX - At present, there is no way (via the for } catch ( IOException e) { Session. Manager interface) } return (null); * a Context to tell the Manager that we create what the default session } * timeout for this web application (specified in the deployment descriptor) * should be. public Http. Session create. Session (Context ctx ) { * return * @author Craig R. Mc. Clanahan manager. create. Session (). get. Session (); } */ public final class Standard. Session. Manager * Remove all sessions because our associated Context is being shut down. implements Session. Manager { * * @ param ctx The context that is being shut down */ // -----------------------------Constructors public void remove. Sessions (Context ctx ) { // contexts, we just want to remove the sessions of Session. Manager that adapts to the corresponding ctx ! // The manager will still run after that ( i. e. keep database // connection open * implementation. if (manager */ instanceof Lifecycle) { try { public Standard. Session. Manager () { ((Lifecycle) manager). stop(); manager = new if (manager } catch ( Lifecycle. Exception Standard. Manager (); throw new instanceof Lifecycle) { Illegal. State. Exception ("" + e); } try { } ((Lifecycle) manager). configure(null); ((Lifecycle) manager). start(); } catch ( Lifecycle. Exception throw new } e) { Illegal. State. Exception ("" + e); /** } } * Used by context to configure the session manager's inactivity timeout. * * The Session. Manager may have some default session time out, the * Context on the other hand has it's timeout set by the deployment } public static Server. Session. Manager get. Manager () { return manager; } } // cache the * <b>IMPLEMENTATION NOTE</b>: * paradigm, I would suggest moving the logic implemented here back into * the core level. * descriptor (web. xml). This method lets the Context // Validate and update our current component state if (!started) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. not. Started ")); started = false; return (this. check. Interval ); // ------------------------------- Private Class implements Http. Session. Context ((Session) session). access(); Session. Manager * and lifecycle configuration is not supported. * <p> conforgure the * session manager according to this value. * * @ param minutes The session inactivity timeout in minutes. */ /** public void set. Session. Time. Out (int minutes) { * The Manager implementation we are actually using. if(-1 != minutes) { */ // The manager works with seconds. . . private Manager manager = null; manager. set. Max. Inactive. Interval (minutes * 60); } } /** * This class is a dummy implementation of the <code> Http. Session. Context </code> * interface, to conform to the requirement that such an object be returned * when <code> Http. Session. get. Session. Context ()</code> is called. * * @author Craig R. Mc. Clanahan * * @deprecated As of Java Servlet API 2. 1 with no replacement. The * interface will be removed in a future version of this API. */ instanceof Session) * that adapts to the new component-based Manager implementation. * <p> * XXX - At present, use of <code> Standard. Manager </code> is hard coded, // --------------------------- Instance Variables /** * Return the check interval (in seconds) for this Manager. */ public int get. Check. Interval () { } final class Standard. Session. Context * Specialized implementation of org. apache. tomcat. core. } /** * Gracefully terminate the active use of the public methods of this * component. This method should be the last one called on a given * instance of this component. * * @exception Illegal. State. Exception if this component has not been started * @exception Illegal. State. Exception if this component has already * been stopped * @exception Lifecycle. Exception if this component detects a fatal error * that needs to be reported */ public void stop() throws Lifecycle. Exception { // ------------------------------- Properties static advice( Standard. Session s): invalidate(s) { before { if (!s. is. Valid ()) throw new Illegal. State. Exception (s. sm. get. String ("standard. Session. " + this. Join. Point. method. Name + ". ise")); } } ctx , Request req , String id) { session= find. Session (ctx, id); if( session == null) return; if (session } /** * Name to register for the background thread. */ private String thread. Name = "Standard. Manager "; } /** * Return the set of names of objects bound to this session. If there * are no such objects, a zero-length array is returned. * * @exception Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> get. Attribute. Names ()</code> */ public String[] get. Value. Names () { Http. Session /** // Validate and update our current component state if (!configured) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. not. Configured ")); if (started) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. already. Started ")); started = true; /** * The background thread completion semaphore. */ private boolean thread. Done = false; } /** * 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 get. Last. Accessed. Time () { * @ param session The session to be marked public void accessed(Context // XXX a manager may be shared by multiple /** * The background thread. */ private Thread thread = null; crosscut invalidate( Standard. Session s): s & ( int get. Max. Inactive. Interval () | long get. Creation. Time () | Object get. Attribute (String) | Enumeration get. Attribute. Names () | String[] get. Value. Names () | void invalidate() | boolean is. New () | void remove. Attribute (String) | void set. Attribute (String, Object)); } This should be Request. Interceptor. * */ import org. apache. tomcat. core. Session. Manager ; import org. apache. tomcat. util. Session. Util ; /** * Has this component been started yet? */ private boolean started = false; } return (attributes. keys()); if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). add(this); * Mark the specified session's last accessed time. * called for each request by a import org. apache. tomcat. core. Request; import org. apache. tomcat. core. Response; * Create a new Manager * Prepare for the beginning of active use of the public methods of this * component. This method should be called after <code>configure()</code>, * and before any of the public methods of the component are utilized. * * @exception Illegal. State. Exception if this component has not yet been * configured (if required for this component) * @exception Illegal. State. Exception if this component has already been * started * @exception Lifecycle. Exception if this component detects a fatal error * that prevents this component from being used */ public void start() throws Lifecycle. Exception { /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager ("org. apache. tomcat. session"); // Serialize the attribute count and the attribute values stream. write. Object (new Integer(results. size())); Enumeration names = results. elements(); while (names. has. More. Elements ()) { String name = (String) names. next. Element (); stream. write. Object (name); stream. write. Object (attributes. get(name)); } /** * Return an <code>Enumeration</code> of <code>String</code> objects * containing the names of the objects bound to this session. * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public Enumeration get. Attribute. Names () { /** import org. apache. tomcat. catalina. *; import org. apache. tomcat. core. Context; } /** * The maximum number of active Sessions allowed, or -1 for no limit. */ protected int max. Active. Sessions = -1; } /** * Set the session identifier for this session. * * @ param id The new session identifier */ public void set. Id (String id) { import javax. servlet. http. Cookie; import javax. servlet. http. Http. Session ; /** node = attributes. get. Named. Item ("max. Inactive. Interval "); if (node != null) { try { set. Max. Inactive. Interval (Integer. parse. Int (node. get. Node. Value ())); } catch ( Throwable t) { ; // XXX - Throw exception? } } /** * The descriptive information about this implementation. */ private static final String info = " Standard. Manager /1. 0"; // Accumulate the names of serializable attributes Vector results = new Vector(); Enumeration attrs = get. Attribute. Names (); while ( attrs. has. More. Elements ()) { String attr = (String) attrs. next. Element (); Object value = attributes. get( attr); if (value instanceof Serializable ) results. add. Element (attr); } return (attributes. get(name)); return (this. id); node = attributes. get. Named. Item ("check. Interval "); if (node != null) { try { set. Check. Interval (Integer. parse. Int (node. get. Node. Value ())); } catch ( Throwable t) { ; // XXX - Throw exception? } } /** * Has this component been configured yet? */ private boolean configured = false; // Write the scalar instance variables (except Manager) stream. write. Object (new Long( creation. Time )); stream. write. Object (id); stream. write. Object (new Long( last. Accessed. Time )); stream. write. Object (new Integer( max. Inactive. Interval )); stream. write. Object (new Boolean( is. New )); stream. write. Object (new Boolean( is. Valid )); /** * Return the object bound with the specified name in this session, or * <code>null</code> if no object is bound with that name. * * @ param name Name of the attribute to be returned * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public Object get. Attribute (String name) { // Parse and process our configuration parameters if (!("Manager". equals(parameters. get. Node. Name ()))) return; Named. Node. Map attributes = parameters. get. Attributes (); Node node = null; /** * The interval (in seconds) between checks for expired sessions. */ private int check. Interval = 60; /** * Write a serialized version of this session object to the specified * object output stream. * <p> * <b>IMPLEMENTATION NOTE</b>: The owning Manager will not be stored * in the serialized representation of this Session. After calling * <code> read. Object ()</code>, you must set the associated Manager * explicitly. * <p> * <b>IMPLEMENTATION NOTE</b>: Any attribute that is not Serializable * will be silently ignored. If you do not want any such attributes, * be sure the <code>distributable</code> property of our associated * Manager is set to <code>true</code>. * * @ param stream The output stream to write to * * @exception IOException if an input/output error occurs */ private void write. Object (Object. Output. Stream stream) throws IOException { if ( session. Context == null) session. Context = new Standard. Session. Context (); return ( session. Context ); // Validate and update our current component state if (configured) throw new Lifecycle. Exception (sm. get. String ("standard. Manager. already. Configured ")); configured = true; if (parameters == null) return; // --------------------------- Instance Variables } // -------------------------- Session Properties import java. io. IOException ; /** * Configure this component, based on the specified configuration * parameters. This method should be called immediately after the * component instance is created, and before <code>start()</code> * is called. * * @ parameters Configuration parameters for this component * (<B>FIXME: What object type should this really be? ) * * @exception Illegal. State. Exception if this component has already been * configured and/or started * @exception Lifecycle. Exception if this component detects a fatal error * in the configuration parameters it was given */ public void configure(Node parameters) throws Lifecycle. Exception { public final class Standard. Manager extends Manager. Base implements Lifecycle, Runnable { // Deserialize the attribute count and attribute values int n = ((Integer) stream. read. Object ()). int. Value (); for ( int i = 0; i < n; i++) { String name = (String) stream. read. Object (); Object value = (Object) stream. read. Object (); attributes. put(name, value); } (( Http. Session. Binding. Listener )o). value. Unbound (e); } Illegal. State. Exception (msg); } } Http. Session Private Methods /** * Read a serialized version of this session object from the specified * object input stream. * <p> * <b>IMPLEMENTATION NOTE</b>: 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 Class. Not. Found. Exception if an unknown class is specified * @exception IOException if an input/output error occurs */ private void read. Object (Object. Input. Stream stream) throws Class. Not. Found. Exception , IOException { this. Valid = is. Valid ; java. io. IOException ; java. util. Enumeration; java. util. Hashtable ; java. util. Vector; org. apache. tomcat. catalina. *; javax. servlet. http. Cookie; javax. servlet. http. Http. Session ; org. apache. tomcat. util. String. Manager ; org. w 3 c. dom. Named. Node. Map ; org. w 3 c. dom. Node; /** * Standard implementation of the <b>Manager</b> interface that provides * no session persistence or distributable capabilities, but does support * an optional, configurable, maximum number of active sessions allowed. * <p> * Lifecycle configuration of this component assumes an XML node * in the following format: * <code> * & lt; Manager class. Name ="org. apache. tomcat. session. Standard. Manager " * check. Interval ="60" max. Active. Sessions ="-1" * max. Inactive. Interval ="-1" /> * </code> * where you can adjust the following parameters, with default values * in square brackets: * <ul> * <li><b>check. Interval </b> - The interval (in seconds) between background * thread checks for expired sessions. [60] * <li><b>max. Active. Sessions </b> - The maximum number of sessions allowed to * be active at once, or -1 for no limit. [-1] * <li><b>max. Inactive. Interval </b> - The default maximum number of seconds of * inactivity before which the servlet container is allowed to time out * a session, or -1 for no limit. This value should be overridden from * the default session timeout specified in the web application deployment * descriptor, if any. [-1] * </ ul> * * @author Craig R. Mc. Clanahan * @version $Revision: 1. 1 $ $Date: 2000/05/02 21: 28: 30 $ */ this. New = is. New ; } /** * Set the <code> is. Valid </code> flag for this session. * * @ param is. Valid The new value for the <code> is. Valid </code> flag */ void set. Valid (boolean is. Valid ) { // ----------------------------- Public Methods // --------------------------- Lifecycle Methods synchronized (attributes) { remove. Attribute (name); attributes. put(name, value); if (value instanceof Http. Session. Binding. Listener ) (( Http. Session. Binding. Listener ) value). value. Bound (new Http. Session. Binding. Event ((Http. Session ) this, name)); } /** * Set the <code> is. New </code> flag for this session. * * @ param is. New The new value for the <code> is. New </code> Standard. Session. Manager S andard. Sess on. Manager package org. apache. tomcat. session; import import import if ((manager != null) && manager. get. Distributable () && !(value instanceof Serializable )) throw new Illegal. Argument. Exception (sm. get. String ("standard. Session. set. Attribute. iae")); return (this. Valid ); } Standard. Manager Sess on n ercep or /** * 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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Bound ()</code> 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 Illegal. Argument. Exception if an attempt is made to add a * non- serializable object in an environment marked distributable. * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public void set. Attribute (String name, Object value) { not. Illegal. Argument. Exception (msg); } public String get. Id () { if (valid) { return id; } else { String msg = sm. get. String ("application. Session. session. ise"); remove. Attribute (name); } // Tell our Manager that this Session has been recycled if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). recycle(this); Illegal. State. Exception (msg); } if ( this. Interval > inactive. Interval ) { invalidate(); } } /** * 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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Unbound ()</code> on the object. * * @ param name Name of the object to remove from this session. * * @exception Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> remove. Attribute ()</code> */ public void remove. Value (String name) { */ void set. New (boolean is. New ) { = ( Hashtable )values. clone(); return (Enumeration) values. Clone. keys(); } void accessed() { // set last accessed to this. Access. Time as it will be left over // from the previous access last. Accessed = this. Access. Time ; this. Access. Time = System. current. Time. Millis (); } /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { /** * The last accessed time for this Session. */ private long last. Accessed. Time = creation. Time ; public Enumeration get. Attribute. Names () { if (! valid) { String msg = sm. get. String ("application. Session. session. ise"); Server. Session get. Server. Session () { return server. Session ; } throw new // Unbind any objects associated with this session Vector results = new Vector(); Enumeration attrs = get. Attribute. Names (); while ( attrs. has. More. Elements ()) { String attr = (String) attrs. next. Element (); results. add. Element (attr); } Enumeration names = results. elements(); while (names. has. More. Elements ()) { String name = (String) names. next. Element (); remove. Attribute (name); } names. copy. Into (value. Names ); } synchronized (attributes) { Object object = attributes. get(name); if (object == null) return; attributes. remove(name); // System. out. println ( "Removing attribute " + name ); if (object instanceof Http. Session. Binding. Listener ) { (( Http. Session. Binding. Listener ) object). value. Unbound (new Http. Session. Binding. Event ((Http. Session ) this, name)); } } if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); /** * The time this session was created, in milliseconds since midnight, * January 1, 1970 GMT. */ private long creation. Time = 0 L; return value. Names ; public long get. Last. Accessed. Time () { if (valid) { return last. Accessed ; } else { String msg = sm. get. String ("application. Session. session. ise"); // Remove this session from our manager's active sessions // Mark this session as invalid set. Valid (false); /** * The collection of user data attributes associated with this Session. */ private Hashtable attributes = new Hashtable (); = context. get. Session. Time. Out (); } /** * 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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Unbound ()</code> on the object. * * @ param name Name of the object to remove from this session. * * @exception Illegal. State. Exception if this method is called on an * invalidated session */ public void remove. Attribute (String name) { } // -------------------------- Instance Variables /** * @deprecated */ public String[] get. Value. Names () { Enumeration e = get. Attribute. Names (); Vector names = new Vector(); while (e. has. More. Elements ()) { names. add. Element (e. next. Element ()); } set. Attribute (name, value); } = this. Accessed. Time ; = System. current. Time. Millis (); /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. */ public void expire() { } } throw new this. last. Accessed. Time this. New =false; } /** * Construct a new Session associated with the specified Manager. * * @ param manager The manager with which this Session is associated */ public Standard. Session (Manager manager) { } Application. Session (String id, Server. Session server. Session , Context context) { this. server. Session = server. Session ; this. context = context; this. id = id; throw new /** * 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() { super(); this. manager = manager; /** * 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] */ if (this. inactive. Interval // ------------------------Session Public Methods values. put(name, value); /** * @deprecated */ public Object get. Value (String name) { return get. Attribute (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. * <p> * After this method executes, and if the object implements * <code> Http. Session. Binding. Listener </code>, the container calls * <code> value. Bound ()</code> 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 Illegal. State. Exception if this method is called on an * invalidated session * * @deprecated As of Version 2. 2, this method is replaced by * <code> set. Attribute ()</code> */ public void put. Value (String name, Object value) { return (( Http. Session ) this); } // ----------------------------- Constructors } package org. apache. tomcat. session; this. inactive. Interval /** * Return the <code> Http. Session </code> for which this object * is the facade. */ public Http. Session get. Session () { // remove any existing binding if (value != null && value instanceof Http. Session. Binding. Listener ) { Http. Session. Binding. Event e = new Http. Session. Binding. Event (this, name); import org. apache. tomcat. core. *; import org. apache. tomcat. util. String. Manager ; import java. io. *; import java. net. *; import java. util. *; import javax. servlet. http. *; public class Application. Session /** java. io. IOException ; java. io. Object. Input. Stream ; java. io. Object. Output. Stream ; java. io. Serializable ; java. util. Enumeration; java. util. Hashtable ; java. util. Vector; javax. servlet. Servlet. Exception ; javax. servlet. http. Http. Session. Binding. Event ; javax. servlet. http. Http. Session. Binding. Listener ; javax. servlet. http. Http. Session. Context ; org. apache. tomcat. catalina. *; org. apache. tomcat. util. String. Manager ; Illegal. State. Exception (msg); } } throw new Standard. Session S andard. Sess on package org. apache. tomcat. session; }

modular aspects HTTPRequest get. Cookies() get. Request. URI()(doc) get. Session() get. Requested. Session. Id().

modular aspects HTTPRequest get. Cookies() get. Request. URI()(doc) get. Session() get. Requested. Session. Id(). . . Session. Interceptor request. Map(request) before. Body(req, resp). . . Session HTTPResponse get. Attribute(name) set. Attribute(name, val) invalidate(). . . get. Request() set. Content. Type(content. Type) get. Outptut. Stream() set. Session. Id(id). . . Servlet 10 Aspect. J Tutorial

Aspect. J™ is… • a small and well-integrated extension to Java • a general-purpose

Aspect. J™ is… • a small and well-integrated extension to Java • a general-purpose AO language – just as Java is a general-purpose OO language • freely available implementation – compiler is Open Source • includes IDE support – emacs, JBuilder 3. 5, Forte 4 J • user feedback is driving language design – users@aspectj. org – support@aspectj. org • currently at 0. 7 b 8 release – 1. 0 planned for June 2001 11 Aspect. J Tutorial

expected benefits of using AOP • good modularity, even for crosscutting concerns – less

expected benefits of using AOP • good modularity, even for crosscutting concerns – less tangled code – more natural code – shorter code – easier maintenance and evolution • easier to reason about, debug, change – more reusable • library aspects • plug and play aspects when appropriate 12 Aspect. J Tutorial

outline • I AOP overview – brief motivation, essence of AOP idea • II

outline • I AOP overview – brief motivation, essence of AOP idea • II Aspect. J language mechanisms – basic concepts, language semantics • III development environment – IDE support, running the compiler, debugging etc. • IV using aspects – aspect examples, how to use Aspect. J to program aspects, exercises to solidify the ideas • V related work – survey of other activities in the AOP community 13 Aspect. J Tutorial

looking ahead problem structure Part IV: crosscutting in the design, and how to use

looking ahead problem structure Part IV: crosscutting in the design, and how to use Aspect. J to capture that Aspect. J mechanisms Part II: crosscutting in the code mechanisms Aspect. J provides 14 Aspect. J Tutorial

Part II Basic Mechanisms of Aspect. J 15 Aspect. J Tutorial

Part II Basic Mechanisms of Aspect. J 15 Aspect. J Tutorial

goals of this chapter • present basic language mechanisms – using one simple example

goals of this chapter • present basic language mechanisms – using one simple example • emphasis on what the mechanisms do • small scale motivation • later chapters elaborate on – environment, tools – larger examples, design and SE issues 16 Aspect. J Tutorial

basic mechanisms • 1 overlay onto Java – join points • “points in the

basic mechanisms • 1 overlay onto Java – join points • “points in the execution” of Java programs • 4 small additions to Java – pointcuts • primitive pointcuts – pick out sets of join points and values at those points • user-defined pointcuts – named collections of join points and values – advice • additional action to take at join points in a pointcut – introduction • additional fields/methods/constructors for classes – aspect • a crosscutting type – comprised of advice, introduction, field, constructor and method declarations 17 Aspect. J Tutorial

a simple figure editor class Line implements Figure. Element{ private Point _p 1, _p

a simple figure editor class Line implements Figure. Element{ private Point _p 1, _p 2; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } void set. P 1(Point p 1) { _p 1 = p 1; } void set. P 2(Point p 2) { _p 2 = p 2; } } class Point implements Figure. Element { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void set. X(int x) { _x = x; } void set. Y(int y) { _y = y; } 18 } Aspect. J Tutorial display must be updated when objects move

move tracking • collection of figure elements – that change periodically – must monitor

move tracking • collection of figure elements – that change periodically – must monitor changes to refresh the display as needed – collection can be complex • hierarchical • asynchronous events • other examples – session liveness – value caching 19 Aspect. J Tutorial …

join points key points in dynamic call graph a Figure object receives a method

join points key points in dynamic call graph a Figure object receives a method call and returns or throws dispatch object receives a method call and returns or throws a Line dispatch a method call to another object and a return or exception is received by this method 20 Aspect. J Tutorial

join point terminology key points in dynamic call graph a Line method call reception

join point terminology key points in dynamic call graph a Line method call reception join points • 9 kinds of join points – – – 21 Aspect. J Tutorial dispatch method call join points method & constructor call reception join points method & constructor call join points method & constructor execution join points field get & set join points exception handler execution join points

join point terminology key points in dynamic call graph all join points on this

join point terminology key points in dynamic call graph all join points on this slide are within the control flow of this join point a Line a Point repeated calls to the same method on the same object result in multiple join points a Point a Figure the method call join point corresponding to this method reception join point 22 Aspect. J Tutorial

the pointcut construct names certain join points each time a Line receives a “void

the pointcut construct names certain join points each time a Line receives a “void set. P 1(Point)” or “void set. P 2(Point)” method call name and parameters reception of a “void Line. set. P 1(Point)” call pointcut moves(): or receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)); reception of a “void Line. set. P 2(Point)” call 23 Aspect. J Tutorial

pointcut designators user-defined pointcut designator pointcut moves(): receptions(void Line. set. P 1(Point)) || receptions(void

pointcut designators user-defined pointcut designator pointcut moves(): receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)); primitive pointcut designator, can also be: - calls, executions - gets, sets - handlers 24 Aspect. J Tutorial - instanceof, - within, withincode - cflow, cflowtop

after advice action to take after computation under join points after advice runs “on

after advice action to take after computation under join points after advice runs “on the way back out” pointcut moves(): receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)); static after(): moves() { <runs after moves> } 25 Aspect. J Tutorial a Line

a simple aspect Move. Tracking { private static boolean _flag = false; public static

a simple aspect Move. Tracking { private static boolean _flag = false; public static boolean test. And. Clear() { boolean result = _flag; _flag = false; return result; } Move. Tracking v 1 aspect defines a special class that can crosscut other classes pointcut moves(): receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)); static after(): moves() { _flag = true; } } box means complete running code 26 Aspect. J Tutorial

without Aspect. J class Line { Move. Tracking v 1 class Move. Tracking {

without Aspect. J class Line { Move. Tracking v 1 class Move. Tracking { private Point _p 1, _p 2; private static boolean _flag = false; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } public static void set. Flag() { _flag = true; } void set. P 1(Point p 1) { _p 1 = p 1; Move. Tracking. set. Flag(); } void set. P 2(Point p 2) { _p 2 = p 2; Move. Tracking. set. Flag(); } public static boolean test. And. Clear() { boolean result = _flag; _flag = false; return result; } } } • what you would expect – calls to set flag are tangled through the code – “what is going on” is less explicit 27 Aspect. J Tutorial

the pointcut construct can cut across multiple classes pointcut moves(): receptions(void 28 Aspect. J

the pointcut construct can cut across multiple classes pointcut moves(): receptions(void 28 Aspect. J Tutorial Line. set. P 1(Point)) || Line. set. P 2(Point)) || Point. set. X(int)) || Point. set. Y(int));

a multi-class aspect Move. Tracking { private static boolean _flag = false; public static

a multi-class aspect Move. Tracking { private static boolean _flag = false; public static boolean test. And. Clear() { boolean result = _flag; _flag = false; return result; } pointcut moves(): receptions(void Line. set. P 1(Point)) || Line. set. P 2(Point)) || Point. set. X(int)) || Point. set. Y(int)); static after(): moves() { _flag = true; } } 29 Aspect. J Tutorial Move. Tracking v 2

using context in advice demonstrate first, explain in detail afterwards • pointcut can explicitly

using context in advice demonstrate first, explain in detail afterwards • pointcut can explicitly expose certain values • advice can use value pointcut moves(Figure. Element fig. Elt): instanceof(fig. Elt) && (receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)) || receptions(void Point. set. X(int)) || receptions(void Point. set. Y(int))); static after(Figure. Element fe): moves(fe) { <fe is bound to the figure element> } 30 Aspect. J Tutorial parameter mechanism is being used

context & multiple classes Move. Tracking v 3 aspect Move. Tracking { private static

context & multiple classes Move. Tracking v 3 aspect Move. Tracking { private static Set _movees = new Hash. Set(); public static Set get. Movees() { Set result = _movees; _movees = new Hash. Set(); return result; } pointcut moves(Figure. Element fig. Elt): instanceof(fig. Elt) && (receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)) || receptions(void Point. set. X(int)) || receptions(void Point. set. Y(int))); static after(Figure. Element fe): moves(fe) { _movees. add(fe); } 31 } Aspect. J Tutorial

parameters… of user-defined pointcut designator • variable bound in user-defined pointcut designator • variable

parameters… of user-defined pointcut designator • variable bound in user-defined pointcut designator • variable in place of type name in pointcut designator – pulls corresponding value out of join points – makes value accessible on pointcut parameters pointcut moves(Line l): receptions(void l. set. P 1(Point)) || receptions(void l. set. P 2(Point)); variable in place of type name static after(Line line): moves(line) { <line is bound to the line> } 32 Aspect. J Tutorial

parameters… of advice • variable bound in advice • variable in place of type

parameters… of advice • variable bound in advice • variable in place of type name in pointcut designator – pulls corresponding value out of join points – makes value accessible within advice pointcut moves(Line l): receptions(void l. set. P 1(Point)) || receptions(void l. set. P 2(Point)); advice parameters typed variable in place of type name static after(Line line): moves(line) { <line is bound to the line> } 33 Aspect. J Tutorial

parameters… • value is ‘pulled’ – right to left across ‘: ’ left side

parameters… • value is ‘pulled’ – right to left across ‘: ’ left side : right side – from pointcut designators to user-defined pointcut designators – from pointcut to advice pointcut moves(Line l): receptions(void l. set. P 1(Point)) || receptions(void l. set. P 2(Point)); static after(Line line): moves(line) { <line is bound to the line> } 34 Aspect. J Tutorial

instanceof primitive pointcut designator instanceof(<type name>) any join point at which currently executing object

instanceof primitive pointcut designator instanceof(<type name>) any join point at which currently executing object is ‘instanceof’ type (or class) name instanceof(Point) instanceof(Line) instanceof(Figure. Element) “any join point” means it matches join points of all 9 kinds • • • 35 method & constructor call join points method & constructor call reception join points method & constructor execution join points field get & set join points exception handler execution join points Aspect. J Tutorial

an idiom for… getting object in a polymorphic pointcut instanceof(<supertype name>) && • does

an idiom for… getting object in a polymorphic pointcut instanceof(<supertype name>) && • does not further restrict the join points • does pick up the currently executing object (this) pointcut moves(Figure. Element fig. Elt): instanceof(fig. Elt) && (receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)) || receptions(void Point. set. X(int)) || receptions(void Point. set. Y(int))); static after(Figure. Element fe): moves(fe) { <fe is bound to the figure element> } 36 Aspect. J Tutorial

context & multiple classes Move. Tracking v 3 aspect Move. Tracking { private static

context & multiple classes Move. Tracking v 3 aspect Move. Tracking { private static Set _movees = new Hash. Set(); public static Set get. Movees() { Set result = _movees; _movees = new Hash. Set(); return result; } pointcut moves(Figure. Element fig. Elt): instanceof(fig. Elt) && (receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)) || receptions(void Point. set. X(int)) || receptions(void Point. set. Y(int))); static after(Figure. Element fe): moves(fe) { _movees. add(fe); } 37 } Aspect. J Tutorial

without Aspect. J class Line { private Point _p 1, _p 2; Point get.

without Aspect. J class Line { private Point _p 1, _p 2; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } void set. P 1(Point p 1) { _p 1 = p 1; } void set. P 2(Point p 2) { _p 2 = p 2; } } class Point { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void set. X(int x) { _x = x; } void set. Y(int y) { _y = y; } 38 } Aspect. J Tutorial

without Aspect. J class Line { class Move. Tracking { private Point _p 1,

without Aspect. J class Line { class Move. Tracking { private Point _p 1, _p 2; private static boolean _flag = false; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } public static void set. Flag() { _flag = true; } void set. P 1(Point p 1) { _p 1 = p 1; Move. Tracking. set. Flag(); } void set. P 2(Point p 2) { _p 2 = p 2; Move. Tracking. set. Flag(); } } class Point { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void set. X(int x) { _x = x; } void set. Y(int y) { _y = y; } 39 Move. Tracking v 1 } Aspect. J Tutorial public static boolean test. And. Clear() { boolean result = _flag; _flag = false; return result; } }

without Aspect. J class Line { class Move. Tracking { private Point _p 1,

without Aspect. J class Line { class Move. Tracking { private Point _p 1, _p 2; private static boolean _flag = false; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } public static void set. Flag() { _flag = true; } void set. P 1(Point p 1) { _p 1 = p 1; Move. Tracking. set. Flag(); } void set. P 2(Point p 2) { _p 2 = p 2; Move. Tracking. set. Flag(); } } class Point { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void set. X(int x) { _x = x; Move. Tracking. set. Flag(); } void set. Y(int y) { _y = y; Move. Tracking. set. Flag(); } 40 Move. Tracking v 2 } Aspect. J Tutorial public static boolean test. And. Clear() { boolean result = _flag; _flag = false; return result; } }

without Aspect. J class Line { Move. Tracking v 3 class Move. Tracking {

without Aspect. J class Line { Move. Tracking v 3 class Move. Tracking { private Point _p 1, _p 2; private static Set _movees = new Hash. Set(); Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } public static void collect. One(Object o) { _movees. add(o); } void set. P 1(Point p 1) { _p 1 = p 1; Move. Tracking. collect. One(this); } void set. P 2(Point p 2) { _p 2 = p 2; Move. Tracking. collect. One(this); } public static Set getmovees() { Set result = _movees; _movees = new Hash. Set(); return result; } } } class Point { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void set. X(int x) { _x = x; Move. Tracking. collect. One(this); } void set. Y(int y) { _y = y; Move. Tracking. collect. One(this); } 41 } Aspect. J Tutorial • evolution is cumbersome – changes in all three classes – have to track all callers • change method name • add argument

with Aspect. J class Line { private Point _p 1, _p 2; Point get.

with Aspect. J class Line { private Point _p 1, _p 2; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } void set. P 1(Point p 1) { _p 1 = p 1; } void set. P 2(Point p 2) { _p 2 = p 2; } } class Point { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void _x } void _y } set. X(int x) { = x; set. Y(int y) { = y; } 42 Aspect. J Tutorial

with Aspect. J class Line { aspect Move. Tracking { private static boolean _flag

with Aspect. J class Line { aspect Move. Tracking { private static boolean _flag = false; public static boolean test. And. Clear() { boolean result = _flag; _flag = false; return result; } private Point _p 1, _p 2; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } void set. P 1(Point p 1) { _p 1 = p 1; } void set. P 2(Point p 2) { _p 2 = p 2; } pointcut moves(): receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)); static after(): moves() { _flag = true; } } class Point { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void _x } void _y } set. X(int x) { = x; set. Y(int y) { = y; } 43 Aspect. J Tutorial Move. Tracking v 1 }

with Aspect. J class Line { aspect Move. Tracking { private static boolean _flag

with Aspect. J class Line { aspect Move. Tracking { private static boolean _flag = false; public static boolean test. And. Clear() { boolean result = _flag; _flag = false; return result; } private Point _p 1, _p 2; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } void set. P 1(Point p 1) { _p 1 = p 1; } void set. P 2(Point p 2) { _p 2 = p 2; } pointcut moves(): receptions(void } class Point private int _x = 0, _y = 0; } void _x } void _y } set. X(int x) { = x; set. Y(int y) { = y; } 44 Aspect. J Tutorial Line. set. P 1(Point)) || Line. set. P 2(Point)) || Point. set. X(int)) || Point. set. Y(int)); static after(): moves() { _flag = true; } { int get. X() { return _x; } int get. Y() { return _y; } Move. Tracking v 2

with Aspect. J class Line { aspect Move. Tracking { private static Set _movees

with Aspect. J class Line { aspect Move. Tracking { private static Set _movees = new Hash. Set(); public static Set getmovees() { Set result = _movees; _movees = new Hash. Set(); return result; } private Point _p 1, _p 2; Point get. P 1() { return _p 1; } Point get. P 2() { return _p 2; } void set. P 1(Point p 1) { _p 1 = p 1; } void set. P 2(Point p 2) { _p 2 = p 2; } pointcut moves(Figure. Element fig. Elt): instanceof(fig. Elt) && (receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)) || receptions(void Point. set. X(int)) || receptions(void Point. set. Y(int))); } class Point { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void _x } void _y } set. X(int x) { = x; set. Y(int y) { = y; } 45 Aspect. J Tutorial Move. Tracking v 3 static after(Figure. Element fe): moves(fe) { _movees. add(fe); } } • evolution is more modular – all changes in single aspect

advice is • before additional action to take at join points before proceeding at

advice is • before additional action to take at join points before proceeding at join point • after returning a value to join point • after throwing a throwable to join point • after returning to join point either way • around 46 Aspect. J Tutorial on arrival at join point gets explicit control over when&if program proceeds

contract checking simple example of before/after/around • pre-conditions – check whether parameter is valid

contract checking simple example of before/after/around • pre-conditions – check whether parameter is valid • post-conditions – check whether values were set • condition enforcement – force parameters to be valid 47 Aspect. J Tutorial

pre-condition using before advice aspect Point. Bounds. Pre. Condition { static before(Point p, int

pre-condition using before advice aspect Point. Bounds. Pre. Condition { static before(Point p, int new. X): receptions(void p. set. X(new. X)) { assert(new. X >= MIN_X); what follows the ‘: ’ is assert(new. X <= MAX_X); always a pointcut – } primitive or user-defined static before(Point p, int new. Y): receptions(void p. set. Y(new. Y)) { assert(new. Y >= MIN_Y); assert(new. Y <= MAX_Y); } static void assert(boolean v) { if ( !v ) throw new Runtime. Exception(); } } 48 Aspect. J Tutorial

post-condition aspect Point. Bounds. Post. Condition { static after(Point p, int new. X): receptions(void

post-condition aspect Point. Bounds. Post. Condition { static after(Point p, int new. X): receptions(void p. set. X(new. X)) { assert(p. get. X() == new. X); } static after(Point p, int new. Y): receptions(void p. set. Y(new. Y)) { assert(p. get. Y() == new. Y); } static void assert(boolean v) { if ( !v ) throw new Runtime. Exception(); } } 49 Aspect. J Tutorial using after advice

condition enforcement using around advice aspect Point. Bounds. Enforcement { static around(Point p, int

condition enforcement using around advice aspect Point. Bounds. Enforcement { static around(Point p, int new. X) returns void: receptions(void p. set. X(new. X)) { this. Join. Point. run. Next(p, clip(new. X, MIN_X, MAX_X)); } static around(Point p, int new. Y) returns void: receptions(void p. set. Y(new. Y)) { this. Join. Point. run. Next(p, clip(new. Y, MIN_Y, MAX_Y)); } static int clip(int val, int min, int max) { return Math. max(min, Math. min(max, val)); } } 50 Aspect. J Tutorial

special static method <result type> run. Next(arg 1, arg 2…) available only in around

special static method <result type> run. Next(arg 1, arg 2…) available only in around advice means “run what would have run if this around advice had not been defined” 51 Aspect. J Tutorial

other primitive pointcuts instanceof(<type or class name>) within(<class name>) withincode(<method/constructor signature>) any join point

other primitive pointcuts instanceof(<type or class name>) within(<class name>) withincode(<method/constructor signature>) any join point at which currently executing object is ‘instanceof’ type or class name currently executing code is contained within class name currently executing code is specified method or constructor gets(int sets(int 52 Point. x)[val] Point. x)[old. Val][new. Val] field reference or assignment join points Aspect. J Tutorial

using field set pointcuts aspect Point. Coordinate. Tracing { pointcut coord. Changes(Point p, int

using field set pointcuts aspect Point. Coordinate. Tracing { pointcut coord. Changes(Point p, int old. Val, int new. Val): sets(int p. _x)[old. Val][new. Val] || sets(int p. _y)[old. Val][new. Val]; static after(Point p, int old. Val, int new. Val): coord. Changes(p, old. Val, new. Val) { System. out. println(“The ” + tjp. field. Name + “ field of ” + p + “ was changed from ” + old. Val + “ to ” + new. Val + “. ”); } } 53 Aspect. J Tutorial

special value reflective* access to the join point • this. Join. Point. String class.

special value reflective* access to the join point • this. Join. Point. String class. Name String method. Name String[] parameter. Names Class[] parameter. Types Object[] parameters. . . these will soon change to get. Class. Name()… available in any advice this. Join. Point is abbreviated to ‘tjp’ occasionally in these slides * introspective subset of reflection consistent with Java 54 Aspect. J Tutorial

other primitive pointcuts calls(void Point. set. X(int)) method/constructor call join points (at call site)

other primitive pointcuts calls(void Point. set. X(int)) method/constructor call join points (at call site) receptions(void Point. set. X(int)) method/constructor call reception join points (at called object) executions(void Point. set. X(int)) method/constructor execution join points (at actual called method) 55 Aspect. J Tutorial

context sensitive aspects Move. Tracking v 4 a aspect Move. Tracking { List _movers

context sensitive aspects Move. Tracking v 4 a aspect Move. Tracking { List _movers = new Linked. List(); List _movees = new Linked. List(); // … pointcut move. Calls(Object mover, Figure. Element movee): instanceof(mover) && (line. Move. Calls(movee) || point. Move. Calls(movee)); pointcut line. Move. Calls(Line ln): calls(void ln. set. P 1(Point)) || calls(void ln. set. P 2(Point)); pointcut point. Move. Calls(Point pt): calls(void pt. set. X(int)) || calls(void pt. set. Y(int)); static after(Object mover, Figure. Element movee): move. Calls(mover, movee) { _movers. add(mover); _movees. add(movee); } } 56 Aspect. J Tutorial

context sensitive aspects Move. Tracking v 4 b aspect Move. Tracking { List _movers

context sensitive aspects Move. Tracking v 4 b aspect Move. Tracking { List _movers = new Linked. List(); List _movees = new Linked. List(); // … pointcut move. Calls(Object mover, Figure. Element movee): instanceof(mover) && (calls(void ((Line)movee). set. P 1(Point)) || calls(void ((Line)movee). set. P 2(Point)) || calls(void ((Point)movee). set. X(int)) || calls(void ((Point)movee). set. Y(int))); static after(Object mover, Figure. Element movee): move. Calls(mover, movee) { _movers. add(mover); _movees. add(movee); } } 57 Aspect. J Tutorial ? does this make sense

fine-grained protection class Point implement Figure. Element { private int _x = 0, _y

fine-grained protection class Point implement Figure. Element { private int _x = 0, _y = 0; int get. X() { return _x; } int get. Y() { return _y; } void set. X(int nv) { primitive. Set. X(nv); } void set. Y(int nv) { primitive. Set. Y(nv); } void primitive. Set. X(int x) { _x = x; } void primitive. Set. Y(int y) { _y = y; } } aspect Primitive. Setter. Enforcement { pointcut illegal. Sets(Point pt): !(withincode(void Point. primitive. Set. X(int)) || withincode(void Point. primitive. Set. Y(int))) && (sets(int pt. _x) || sets(int pt. _y)); static before(Point p): illegal. Sets(p) { throw new Error("Illegal primitive setter call. "); } } 58 Aspect. J Tutorial

other primitive pointcuts cflow(pointcut designator) cflowtop(pointcut designator) all join points within the dynamic control

other primitive pointcuts cflow(pointcut designator) cflowtop(pointcut designator) all join points within the dynamic control flow of any join pointcut designator cflowtop doesn’t “start a new one” on re-entry 59 Aspect. J Tutorial

context sensitive aspects Move. Tracking v 5 aspect Move. Tracking { private static Set

context sensitive aspects Move. Tracking v 5 aspect Move. Tracking { private static Set _movees = new Hash. Set(); public static Set get. Movees() { Set result = _movees; _movees = new Hash. Set(); return result; } pointcut moves(Figure. Element fig. Elt): instanceof(fig. Elt) && (receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)) || receptions(void Point. set. X(int)) || receptions(void Point. set. Y(int))); pointcut top. Level. Moves(Figure. Element fig. Elt): moves(fig. Elt) && !cflow(moves(Figure. Element)); static after(Figure. Element fe): top. Level. Moves(fe) { _movees. add(fe); } } 60 Aspect. J Tutorial

wildcarding in pointcuts instanceof(Point) instanceof(graphics. geom. *) instanceof(graphics. . *) “*” is wild card

wildcarding in pointcuts instanceof(Point) instanceof(graphics. geom. *) instanceof(graphics. . *) “*” is wild card “. . ” is multi-part wild card any type in graphics. geom any type in any sub-package of graphics receptions(void Point. set. X(int)) receptions(public * Point. *(. . )) any public method on Point receptions(public * *. *(. . )) any public method on any type receptions(void Point. get. X()) Point. get. Y()) Point. get*()) receptions(Point. new(int, int)) receptions(new(. . )) 61 Aspect. J Tutorial any getter any constructor

property-based crosscutting package com. xerox. scan; public class C 2 { package com. xerox.

property-based crosscutting package com. xerox. scan; public class C 2 { package com. xerox. print; … package com. xerox. copy; public int frotz() { public class C 1 { public class C 3 { A. do. Something(…); … … … public void foo() { public String s 1() { } A. do. Something(…); public int bar() { … … A. do. Something(…); } } … … … } } } … } • crosscuts of methods with a common property – public/private, return a certain value, in a particular package • logging, debugging, profiling – log on entry to every public method 62 Aspect. J Tutorial

property-based crosscutting aspect Public. Error. Logging { static Log log = new Log(); neatly

property-based crosscutting aspect Public. Error. Logging { static Log log = new Log(); neatly captures public interface of mypackage pointcut public. Interface (): receptions(public * com. xerox. . *. *(. . )); static after() throwing (Error e): public. Interface() { log. write(e); } } consider code maintenance • another programmer adds a public method • i. e. extends public interface – this code will still work • another programmer reads this code • “what’s really going on” is explicit 63 Aspect. J Tutorial

aspect state what if you want a per-object log? aspect Public. Error. Logging of

aspect state what if you want a per-object log? aspect Public. Error. Logging of eachobject(Public. Error. Logging. public. Interface()) { Log log = new Log(); one instance of the aspect for each object that ever executes at these points pointcut public. Interface (): receptions(public * com. xerox. . *. *(. . )); after() throwing (Error e): public. Interface() { log. write(e); } body of advice is like body of a method: - “this” is bound to instance of aspect, - aspect fields are accessed freely variable & advice are not static 64 Aspect. J Tutorial

looking up aspect instances : static Log get. Log(Object obj) { return (Public. Error.

looking up aspect instances : static Log get. Log(Object obj) { return (Public. Error. Logging. aspect. Of(obj)). log; } } • static method of aspects that are – of eachobject – of eachclass – of eachcflowroot • returns aspect instance or null 65 Aspect. J Tutorial

of each relations eachobject(<pointcut>) one aspect instance for each object that is ever “this”

of each relations eachobject(<pointcut>) one aspect instance for each object that is ever “this” at the join points p 1 l 1 p 2 p 3 l 2 eachclass(<pointcut>) one aspect instance for each class of object that is ever “this” at the join points eachcflowroot(<pointcut>) 66 one aspect instance for each join pointcut, is available at all joinpoints in <pointcut> && cflow(<pointcut>) Aspect. J Tutorial Figure. Element Point Line

inheritance & specialization • pointcuts can have additional advice – aspect with • concrete

inheritance & specialization • pointcuts can have additional advice – aspect with • concrete pointcut • perhaps no advice on the pointcut – in figure editor • moves() can have advice from multiple aspects – module can expose certain well-defined pointcuts • abstract pointcuts can be specialized – aspect with • abstract pointcut • concrete advice on the abstract pointcut 67 Aspect. J Tutorial

a shared pointcut public class Figure. Editor { public pointcut moves(Figure. Element fig. Elt):

a shared pointcut public class Figure. Editor { public pointcut moves(Figure. Element fig. Elt): instanceof(fig. Elt) && (receptions(void Line. set. P 1(Point)) || receptions(void Line. set. P 2(Point)) || receptions(void Point. set. X(int)) || receptions(void Point. set. Y(int))); . . . } aspect Move. Tracking { static after(Figure. Element fe): Figure. Editor. moves(fe) {. . . } 68 Aspect. J Tutorial

a reusable aspect abstract public aspect Remote. Exception. Logging { abstract pointcut log. Points();

a reusable aspect abstract public aspect Remote. Exception. Logging { abstract pointcut log. Points(); abstract static after() throwing (Remote. Exception e): log. Points() { log. println(“Remote call failed in: ” + this. Join. Point. to. String() + “(” + e + “). ”); } } public aspect My. RMILogging extends Remote. Exception. Logging { pointcut log. Points(): receptions(* Registry. Server. *. *(. . )) || receptions(private * RMIMessage. Broker. Impl. *. *(. . )); } 69 Aspect. J Tutorial

introduction (like “open classes”) aspect Move. Tracking { private static Set _movees = new

introduction (like “open classes”) aspect Move. Tracking { private static Set _movees = new Hash. Set(); public static Set get. Movees() { Set result = _ movees; _movees = new Hash. Set(); return result; } Move. Tracking v 6 introduction adds members to target type introduction Figure. Element { private Object last. Moved. By; public Object get. Last. Moved. By() { return last. Moved. By; } } pointcut Move. Calls(Object mover, Figure. Element movee): instanceof(mover) && (line. Move. Calls(movee) || point. Move. Calls(movee)); pointcut line. Move. Calls(Line ln): calls(void ln. set. P 1(Point)) || calls(void ln. set. P 2(Point)); pointcut point. Move. Calls(Point pt): calls(void pt. set. X(int)) || calls(void pt. set. Y(int)); public and private are with respect to enclosing aspect declaration static after(Object mover, Figure. Element movee): Move. Calls(mover, movee) { _movees. add(movee); movee. last. Moved. By = mover; } } 70 Aspect. J Tutorial

calls/receptions/executions differences among : class My. Point extends Point { : int get. X()

calls/receptions/executions differences among : class My. Point extends Point { : int get. X() { return super. get. X(); } : } aspect Show. Accesses { static before(): calls(void Point. get. X()) { <a> } static before(): receptions(void Point. get. X()) { <b> } static before(): executions(void Point. get. X()) { <c> } } (new My. Point()). get. X() 71 Aspect. J Tutorial code <a> runs once code <b> runs once code <c> runs twice

calls/receptions/executions differences among : class My. Point extends Point { : My. Point() {.

calls/receptions/executions differences among : class My. Point extends Point { : My. Point() {. . . } : } remember the implicit super call here! aspect Show. Accesses { static before(): calls(Point. new()) { <a> } static before(): receptions(Point. new()) { <b> } static before(): executions(Point. new()) { <c> } } new My. Point() 72 Aspect. J Tutorial code <a> runs once code <b> runs once code <c> runs twice

summary join points method & constructor calls call receptions executions field gets sets exception

summary join points method & constructor calls call receptions executions field gets sets exception handler executions aspects 73 crosscutting type of eachobject …class …cflowroot Aspect. J Tutorial pointcuts -primitivecalls receptions executions handlers gets sets dispatch instanceof hasaspect withincode cflowtop -user-definedpointcut declaration ‘abstract’ overriding advice before after around static non-static of each… inheritance introduction

where we have been… … and where we are going problem structure Part IV:

where we have been… … and where we are going problem structure Part IV: crosscutting in the design, and how to use Aspect. J to capture that Aspect. J mechanisms Part II: crosscutting in the code mechanisms Aspect. J provides 74 Aspect. J Tutorial

Part III Aspect. J IDE support 75 Aspect. J Tutorial

Part III Aspect. J IDE support 75 Aspect. J Tutorial

programming environment • AJDE support for – emacs, Jbuilder 3. 5, Forte 4 J

programming environment • AJDE support for – emacs, Jbuilder 3. 5, Forte 4 J • also jdb style debugger (ajdb) • and window-based debugger • • navigating Aspect. J code compiling tracking errors debugging • ajdoc 76 Aspect. J Tutorial

Part IV Using Aspects 77 Aspect. J Tutorial

Part IV Using Aspects 77 Aspect. J Tutorial

where we have been… … and where we are going problem structure Part IV:

where we have been… … and where we are going problem structure Part IV: crosscutting in the design, and how to use Aspect. J to capture that Aspect. J mechanisms Part II: crosscutting in the code mechanisms Aspect. J provides 78 Aspect. J Tutorial

goals of this chapter • present examples of aspects in design – intuitions for

goals of this chapter • present examples of aspects in design – intuitions for identifying aspects • present implementations in Aspect. J – how the language support can help • work on implementations in Aspect. J – putting Aspect. J into practice • raise some style issues – objects vs. aspects • when are aspects appropriate? 79 Aspect. J Tutorial

example 1 plug & play tracing • plug tracing into the system – exposes

example 1 plug & play tracing • plug tracing into the system – exposes join points and uses very simple advice • an unpluggable aspect – the program’s functionality is unaffected by the aspect • uses both aspect and object 80 Aspect. J Tutorial

tracing without Aspect. J class Trace. Support { Trace. Support static int TRACELEVEL =

tracing without Aspect. J class Trace. Support { Trace. Support static int TRACELEVEL = 0; static protected Print. Stream stream = null; static protected int call. Depth = -1; static void init(Print. Stream _s) {stream=_s; } static void trace. Entry(String str) { if (TRACELEVEL == 0) return; call. Depth++; print. Entering(str); } static void trace. Exit(String str) { if (TRACELEVEL == 0) return; call. Depth--; print. Exiting(str); } 81 } class Point { void set(int x, int y) { Trace. Support. trace. Entry(“Point. set”); _x = x; _y = y; Trace. Support. trace. Exit(“Point. set”); } } Aspect. J Tutorial

a clear crosscutting structure Trace. Support this line is about interacting with the trace

a clear crosscutting structure Trace. Support this line is about interacting with the trace facility 82 Aspect. J Tutorial all modules of the system use the trace facility in a consistent way: entering the methods and exiting the methods

tracing as an aspect My. Class. Tracing { Trace. Support pointcut points(): within(com. bigboxco.

tracing as an aspect My. Class. Tracing { Trace. Support pointcut points(): within(com. bigboxco. boxes. *) && executions(* *(. . )); static before(): points() { Trace. Support. trace. Entry( tjp. class. Name + “. ” + tjp. method. Name); } static after(): points() { Trace. Support. trace. Exit( tjp. class. Name + “. ” + tjp. method. Name); } } 83 Aspect. J Tutorial

plug and debug • plug in: • unplug: • or… 84 Aspect. J Tutorial

plug and debug • plug in: • unplug: • or… 84 Aspect. J Tutorial ajc Point. java Line. java Trace. Support. java My. Class. Tracing. java ajc Point. java Line. java

plug and debug //From Context. Manager public void service( Request rrequest, Response rresponse )

plug and debug //From Context. Manager public void service( Request rrequest, Response rresponse ) { // log( "New request " + rrequest ); try { // System. out. print("A"); rrequest. set. Context. Manager( this ); rrequest. set. Response(rresponse); rresponse. set. Request(rrequest); // wront request - parsing error int status=rresponse. get. Status(); // log( "New request " + rrequest ); // System. out. print(“A”); if( status < 400 ) status= process. Request( rrequest ); if(status==0) status=authenticate( rrequest, rresponse ); if(status == 0) status=authorize( rrequest, rresponse ); if( status == 0 ) { rrequest. get. Wrapper(). handle. Request(rrequest, rresponse); } else { // something went wrong handle. Error( rrequest, rresponse, null, status ); } } catch (Throwable t) { handle. Error( rrequest, rresponse, t, 0 ); } // System. out. print("B"); try { rresponse. finish(); rrequest. recycle(); rresponse. recycle(); } catch( Throwable ex ) { if(debug>0) log( "Error closing request " + ex); } // log( "Done with request " + rrequest ); // System. out. print("C"); return; } // System. out. print("B"); if(debug>0) log("Error closing request " + ex); // log("Done with request " + rrequest); // System. out. print("C"); 85 Aspect. J Tutorial

plug and debug • turn debugging on/off without editing classes • debugging disabled with

plug and debug • turn debugging on/off without editing classes • debugging disabled with no runtime cost • can save debugging code between uses • can be used for profiling, logging • easy to be sure it is off 86 Aspect. J Tutorial

Gregor Kiczales: aspects in the design these next two slides seem redundant hilsdale: No,

Gregor Kiczales: aspects in the design these next two slides seem redundant hilsdale: No, they seem repetetive. have these They’re here so we can stress design vs. implementation. Perhaps we should emphasize (bold/ital) “responsible for” vs “contains”, etc? Another option would be to “invert” the slides: instead of having 2 slides with threeencapsulates points each (2 x 3), that haveresponsibility, 3 trace aspect for slides of 2 points each. appropriate objects benefits • objects are no longer responsible for using the trace facility – • if the Trace interface changes, that change is shielded from the objects – only the trace aspect is affected • removing tracing from the design is trivial – just remove the trace aspect 87 Aspect. J Tutorial

aspects in the code have these benefits • object code contains no calls to

aspects in the code have these benefits • object code contains no calls to trace functions – trace aspect code encapsulates those calls, for appropriate objects • if the trace interface changes, there is no need to modify the object classes – only the trace aspect class needs to be modified • removing tracing from the application is trivial – compile without the trace aspect class 88 Aspect. J Tutorial

tracing: object vs. aspect • using an object captures tracing support, but does not

tracing: object vs. aspect • using an object captures tracing support, but does not capture its consistent usage by other objects Trace. Support 89 Aspect. J Tutorial • using an aspect captures the consistent usage of the tracing support by the objects Trace. Support

tracing exercises • Make the tracing aspect a library aspect by using an abstract

tracing exercises • Make the tracing aspect a library aspect by using an abstract pointcut. • The after advice used runs whether the points returned normally or threw exceptions, but the exception thrown is not traced. Add advice to do so. 90 Aspect. J Tutorial

exercise refactor Trace. My. Classes into a reusable (library) aspect and an extension equivalent

exercise refactor Trace. My. Classes into a reusable (library) aspect and an extension equivalent to Trace. My. Classes aspect Tracing. XXX { // what goes here? } aspect Trace. My. Classes extends Tracing. XXX { // what goes here? } 91 Aspect. J Tutorial

exercise we now have the Trace class, and two aspects, from a design perspective,

exercise we now have the Trace class, and two aspects, from a design perspective, what does each implement? abstract aspect Tracing. Protocol { abstract pointcut trace. Points(); static before(): points() { Trace. trace. Entry(tjp. class. Name + “. ” + tjp. method. Name); } static after(): points() { Trace. trace. Exit(tjp. class. Name + “. ” + tjp. method. Name); } } aspect Trace. My. Classes extends Tracing. Protocol { pointcut points(): within(com. bigboxco. boxes. *) && executions(* *(. . )); } 92 Aspect. J Tutorial

Gregor Kiczales: there are many possible interesting things to do abstract here: aspect Tracing.

Gregor Kiczales: there are many possible interesting things to do abstract here: aspect Tracing. Protocol { - teach that you pointcut points(); can haveabstract a pointcut execution. Points(): points() && executions(* *(. . )); pointcut as shown here static before(): execution. Points() { -teach that you Trace. trace. Entry(tjp. class. Name + “. ” + tjp. method. Name); might fold Trace } into Tracing static after(): execution. Points() { Protocol (call. Trace. trace. Exit( it tjp. class. Name + “. ” + tjp. method. Name); Tracing) } } aspect Trace. My. Classes extends Tracing. Protocol { pointcut points(): within(com. bigboxco. boxes. *); } 93 Aspect. J Tutorial

example 2 94 Aspect. J Tutorial roles/views

example 2 94 Aspect. J Tutorial roles/views

Cloneable. Point aspect Cloneable. Point { introduction Point { implements Cloneable; public Object clone()

Cloneable. Point aspect Cloneable. Point { introduction Point { implements Cloneable; public Object clone() throws Clone. Not. Supported. Exception { // we choose to bring all fields up to date before cloning make. Rectangular(); // defined in class Point make. Polar(); // defined in class Point return super. clone(); } } } 95 Aspect. J Tutorial

Serializable. Point aspect Serializable. Point { introduction Point { implements Serializable; private static final

Serializable. Point aspect Serializable. Point { introduction Point { implements Serializable; private static final Object. Stream. Field[] serial. Persistent. Fields = { new Object. Stream. Field("x", Double. TYPE), new Object. Stream. Field("y", Double. TYPE) }; private void write. Object(Object. Output. Stream s) throws IOException { make. Rectangular(); s. default. Write. Object(); } private void read. Object(Object. Input. Stream s) throws IOException, Class. Not. Found. Exception s. default. Read. Object(); rectangular = true; polar = false; } } 96 } Aspect. J Tutorial {

roles/views exercises • Write the Hashable. Point and Comparable. Point aspects. • Consider a

roles/views exercises • Write the Hashable. Point and Comparable. Point aspects. • Consider a more complex system. Would you want the Hashable. Point aspect associated with the Point class, or with other Hashable. X objects, or both? • Compare using aspects for role/view abstraction with other techniques or patterns. 97 Aspect. J Tutorial

example 3 counting bytes interface Output. Stream { public void write(byte b); public void

example 3 counting bytes interface Output. Stream { public void write(byte b); public void write(byte[] b); } /** * This SIMPLE aspect keeps a global count of all * all the bytes ever written to an Output. Stream. */ aspect Byte. Counting { static int count = 0; static int get. Count() { return count; } // // // what goes here? // // // } 98 Aspect. J Tutorial

exercise complete the code for Byte. Counting /** * This SIMPLE aspect keeps a

exercise complete the code for Byte. Counting /** * This SIMPLE aspect keeps a global count of all * all the bytes ever written to an Output. Stream. */ aspect Byte. Counting { static int count = 0; static int get. Count() { return count; } } 99 Aspect. J Tutorial

counting bytes v 1 a first attempt aspect Byte. Counting { static int count

counting bytes v 1 a first attempt aspect Byte. Counting { static int count = 0; static int get. Count() { return count; } static after(): receptions(void Output. Stream. write(byte)) { count = count + 1; } static after(byte[] bytes): receptions(void Output. Stream. write(bytes)) { count = count + bytes. length; } } 100 Aspect. J Tutorial

counting bytes some stream implementations class Simple. Output. Stream implements Output. Stream { public

counting bytes some stream implementations class Simple. Output. Stream implements Output. Stream { public void write(byte b) { } public void write(byte[] b) { for (int i = 0; i < b. length; i++) write(b[i]); } } class One. Output. Stream implements Output. Stream { public void write(byte b) {. . } public void write(byte[] b) {. . } } 101 Aspect. J Tutorial

counting bytes another implementation class Other. Output. Stream implements Output. Stream { public void

counting bytes another implementation class Other. Output. Stream implements Output. Stream { public void write(byte b) { byte[] bs = new byte[1]; bs[0] = b; write(bs); } public void write(byte[] b) { } } 102 Aspect. J Tutorial

counting bytes v 2 using cflow for more robust counting aspect Byte. Counting {

counting bytes v 2 using cflow for more robust counting aspect Byte. Counting { static int count = 0; static int get. Count() { return count; } pointcut all. Writes(): receptions(void Output. Stream. write(byte)) || receptions(void Output. Stream. write(byte[])); pointcut within. Write(): cflow(all. Writes()); static after(): !within. Write() && receptions(void Output. Stream. write(byte)) { count++; } static after(byte[] bytes): !within. Write() && receptions(void Output. Stream. write(bytes)) { count = count + bytes. length; } } 103 Aspect. J Tutorial

counting bytes v 3 per-stream counting aspect Byte. Counting of eachobject(all. Writes()) { int

counting bytes v 3 per-stream counting aspect Byte. Counting of eachobject(all. Writes()) { int count; static int get. Count. Of(Output. Stream str) { return Byte. Counting. aspect. Of(str). count; }. . . count++; . . . count += bytes. length; } 104 Aspect. J Tutorial

counting bytes exercises • How would you count bytes written over this interface without

counting bytes exercises • How would you count bytes written over this interface without aspects? • How do the aspects change if the method void write(Collection c) is added to the Output. Stream interface? • Consider a system in which you wrote not only bytes, but byte generators (Objects with a run() method that may output its own bytes). How would you need to change v 2? 105 Aspect. J Tutorial

example 4 context-passing aspects caller 1 Service caller 2 workers need to know the

example 4 context-passing aspects caller 1 Service caller 2 workers need to know the caller: • capabilities • charge backs • to customize result worker 1 106 Aspect. J Tutorial worker 2 worker 3

context-passing aspects caller 1 Service caller 2 workers need to know the caller: •

context-passing aspects caller 1 Service caller 2 workers need to know the caller: • capabilities • charge backs • to customize result worker 1 107 Aspect. J Tutorial worker 2 worker 3

context-passing aspects pointcut invocations(Caller c): instanceof(c) && calls(void Service. do. Service(String)); 108 Aspect. J

context-passing aspects pointcut invocations(Caller c): instanceof(c) && calls(void Service. do. Service(String)); 108 Aspect. J Tutorial

context-passing aspects pointcut invocations(Caller c): instanceof(c) && calls(void Service. do. Service(String)); pointcut work. Points(Worker

context-passing aspects pointcut invocations(Caller c): instanceof(c) && calls(void Service. do. Service(String)); pointcut work. Points(Worker w): receptions(void w. do. Task(Task)); 109 Aspect. J Tutorial

context-passing aspects pointcut invocations(Caller c): instanceof(c) && calls(void Service. do. Service(String)); pointcut work. Points(Worker

context-passing aspects pointcut invocations(Caller c): instanceof(c) && calls(void Service. do. Service(String)); pointcut work. Points(Worker w): receptions(void w. do. Task(Task)); pointcut per. Caller. Work(Caller c, Worker w): cflow(invocations(c)) && work. Points(w); 110 Aspect. J Tutorial

context-passing aspects abstract aspect Capability. Checking { pointcut invocations(Caller c): instanceof(c) && calls(void Service.

context-passing aspects abstract aspect Capability. Checking { pointcut invocations(Caller c): instanceof(c) && calls(void Service. do. Service(String)); pointcut work. Points(Worker w): receptions(void w. do. Task(Task)); pointcut per. Caller. Work(Caller c, Worker w): cflow(invocations(c)) && work. Points(w); before (Caller c, Worker w): per. Caller. Work(c, w) { w. check. Capabilities(c); } } 111 Aspect. J Tutorial

context-passing aspects exercises • The before advice on the per. Caller. Work pointcut calls

context-passing aspects exercises • The before advice on the per. Caller. Work pointcut calls the worker’s check. Capabilities method to check the capabilities of the caller. What would be an appropriate way to write that method? 112 Aspect. J Tutorial

example 5 properties of interfaces interface Forest { int how. Many. Trees(); int how.

example 5 properties of interfaces interface Forest { int how. Many. Trees(); int how. Many. Birds(); . . . } pointcut forest. Receptions(): receptions(* Forest. *(. . )); before(): forest. Receptions(): } 113 Aspect. J Tutorial {

aspects on interfaces a first attempt aspect Forestry { pointcut Forest. Method. Receptions(): receptions(*

aspects on interfaces a first attempt aspect Forestry { pointcut Forest. Method. Receptions(): receptions(* Forest. *(. . )); static before(): Forest. Method. Receptions() { System. out. println(this. Join. Point. method. Name + " is a Forest-method. "); } } 114 Aspect. J Tutorial

aspects on interfaces an implementation class Forest. Impl implements Forest { public static void

aspects on interfaces an implementation class Forest. Impl implements Forest { public static void main(String[] args) { Forest f 1 = new Forest. Impl(); f 1. to. String(); f 1. how. Many. Trees(); } public int how. Many. Trees() { return 100; } public int how. Many. Birds() { return 200; } } • 115 interface Forest includes methods from Object, such as to. String() Aspect. J Tutorial

aspects on interfaces adding constraints aspect Forestry { pointcut Forest. Method. Receptions(): receptions(* Forest.

aspects on interfaces adding constraints aspect Forestry { pointcut Forest. Method. Receptions(): receptions(* Forest. *(. . )) && !receptions(* Object. *(. . )); static before(): Forest. Method. Receptions() { System. out. println(this. Join. Point. method. Name + " is a Forest-method. "); } } 116 Aspect. J Tutorial

aspects on interfaces exercises • In this example you needed to constrain a pointcut

aspects on interfaces exercises • In this example you needed to constrain a pointcut because of undesired inheritance. Think of an example where you would want to capture methods in a super-interface. • Constraining a pointcut in this way can be seen as an aspect idiom. What other idioms have you seen in this tutorial? 117 Aspect. J Tutorial

example 6 118 Aspect. J Tutorial RMI exception aspects client reactions to failures: -

example 6 118 Aspect. J Tutorial RMI exception aspects client reactions to failures: - abort - try another server

a Time. Server design 119 Aspect. J Tutorial

a Time. Server design 119 Aspect. J Tutorial

the Time. Service public interface Time. Service extends Remote { /** * What's the

the Time. Service public interface Time. Service extends Remote { /** * What's the time? */ public Date get. Time() throws Remote. Exception; /** * Get the name of the server */ public String get. Name() throws Remote. Exception; /** * Exported base name for the service */ public static final String name. Base = "Time. Service"; } 120 Aspect. J Tutorial

the Time. Server public class Time. Server extends Unicast. Remote. Object implements Time. Service

the Time. Server public class Time. Server extends Unicast. Remote. Object implements Time. Service { /** * The remotely accessible methods Gregor Kiczales: */ public Date get. Time() throws {return new Date(); } people liked this. Remote. Exception – public String get. Name() throws it teaches using. Remote. Exception {return to. String(); } /** Aspect. J to expose * Make a new server object and register it an internal */ interface public static void main(String[] args) { Time. Server ts = new Time. Server(); Naming. bind(Time. Service. name. Base, ts); } /** * Exception pointcuts. Code won’t compile without advising them */ pointcut create() returns Time. Server: within(Time. Server) && calls(Time. Server. new()); no exception catching here, but notice pointcut bind(String name) returns void: within(Time. Server) && calls(void Naming. bind(name, . . )); } 121 Aspect. J Tutorial

Abort. My. Server aspect Abort. My. Server { static around() returns Time. Server: Time.

Abort. My. Server aspect Abort. My. Server { static around() returns Time. Server: Time. Server. create() { Time. Server result = null; try { result = this. Join. Point. run. Next(); } catch (Remote. Exception e){ System. out. println("Time. Server err: " + e. get. Message()); System. exit(2); } return result; } static around(String name) returns void: Time. Server. bind(name) { try { this. Join. Point. run. Next(name); System. out. println("Time. Server: bound name. "); } catch (Exception e) { System. err. println("Time. Server: error " + e); System. exit(1); } } } 122 Aspect. J Tutorial

Retry. My. Server aspect Retry. My. Server { static around() returns Time. Server: Time.

Retry. My. Server aspect Retry. My. Server { static around() returns Time. Server: Time. Server. create() { Time. Server result = null; try { result = this. Join. Point. run. Next(); } catch (Remote. Exception e){ System. out. println("Time. Server error. "); e. print. Stack. Trace(); } return result; } static around(String name) returns void: Time. Server. bind(name) { for (int tries = 0; tries < 3; tries++) { try { this. Join. Point. run. Next(name + tries); System. out. println("Time. Server: Name bound in registry. "); return; } catch (Already. Bound. Exception e) { System. err. println("Time. Server: name already bound"); } System. err. println("Time. Server: Giving up. "); System. exit(1); } } 123 Aspect. J Tutorial

the Client again, no exception catching here public class Client { Time. Service server

the Client again, no exception catching here public class Client { Time. Service server = null; /** * Get a server and ask it the time occasionally */ void run() { server = (Time. Service)Naming. lookup(Time. Service. name. Base); System. out. println("n. Remote Server=" + server. get. Name() + "nn"); while (true) { System. out. println("Time: " + server. get. Time()); pause(); } } /** * Exception pointcuts. Code won’t compile without advising them */ pointcut setup(Client c) returns Remote: instanceof(c) & calls(Remote Naming. lookup(. . )); pointcut serve(Client c, Time. Service ts) returns Object: instanceof(c) & calls(* ts. *(. . )); … other methods … } 124 Aspect. J Tutorial

Abort. My. Client aspect Abort. My. Client { static around(Client c) returns Remote: Client.

Abort. My. Client aspect Abort. My. Client { static around(Client c) returns Remote: Client. setup(c) { Remote result = null; try { result = this. Join. Point. run. Next(c); } catch (Exception e) { System. out. println("Client: No server. Aborting. "); System. exit(0); } return result; } static around(Client c, Time. Service ts) returns Object: Client. serve(c, ts) { Object result = null; try { result = this. Join. Point. run. Next(c, ts); } catch (Remote. Exception e) { System. out. println("Client: Remote Exception. Aborting. "); System. exit(0); } return result; } } 125 Aspect. J Tutorial

Retry. My. Client aspect Retry. My. Client { static around(Client c) returns Remote: Client.

Retry. My. Client aspect Retry. My. Client { static around(Client c) returns Remote: Client. setup(c) { Remote result = null; try { result = this. Join. Point. run. Next(c); } catch (Not. Bound. Exception e) { System. out. println("Client: Trying alternative name. . . "); result = find. New. Server(Time. Service. name. Base, c. server, 3); if (result == null) System. exit(1); /* No server found */ } catch (Exception e 2) { System. exit(2); } return result; } static around(Client c, Time. Service ts) returns Object: Client. serve(c, ts) { try { return this. Join. Point. run. Next(c, ts); } catch (Remote. Exception e) { /* Ignore and try other servers */ } c. server = find. New. Server(Time. Service. name. Base, c. server, 3); if (c. server == null) System. exit(1); /* No server found */ try { return this. Join. Point. run. Next(c, c. server); } catch (Remote. Exception e 2) { System. exit(2); } return null; } static Time. Service find. New. Server (String base. Name, Object current. Server, int nservers) { … } } 126 Aspect. J Tutorial

building the client • abort mode: ajc Client. java Time. Server_Stub. java Abort. My.

building the client • abort mode: ajc Client. java Time. Server_Stub. java Abort. My. Client. java • retry mode: ajc Client. java Time. Server_Stub. java Retry. My. Client. java • switch to different failure handling modes without editing • no need for subclassing or delegation • reusable failure handlers 127 Aspect. J Tutorial

RMI exception handling exercises • Write another exception handler that, on exceptions, gives up

RMI exception handling exercises • Write another exception handler that, on exceptions, gives up the remote mode and instantiates a local Time. Server. • How would this client look like if the exception handling were not designed with aspects? Can you come up with a flexible OO design for easily switching between exception handlers? • Compare the design of exception handlers with aspects vs. with your OO design 128 Aspect. J Tutorial

example 7 layers of functionality • given a basic telecom operation, with customers, calls,

example 7 layers of functionality • given a basic telecom operation, with customers, calls, connections • model/design/implement utilities such as – timing – consistency checks –. . . 129 Aspect. J Tutorial

telecom basic design Customer Call void start. Call(Customer) pickup. Call(Call) merge. Calls(Call, Call) hangup.

telecom basic design Customer Call void start. Call(Customer) pickup. Call(Call) merge. Calls(Call, Call) hangup. Call(Call) 1 Call 1 0. . N Customer get. Caller() void pickup() void merge(Call) void hangup() 1 0. . N Connection caller receiver Customer get. Caller() Customer get. Receiver() void complete() void drop() Local 130 Aspect. J Tutorial Long. Distance These classes define the protocols for setting up calls (includes conference calling) and establishing connections

timing store total connection time entities 0. . N Customer 1 1 Call 1

timing store total connection time entities 0. . N Customer 1 1 Call 1 0. . N caller receiver Connection Local 131 Aspect. J Tutorial time each connection Long. Distance

timing connection dropped: add time some actions 0. . N Customer 1 1 Call

timing connection dropped: add time some actions 0. . N Customer 1 1 Call 1 0. . N caller receiver Connection Local 132 Aspect. J Tutorial connection made: start timing connection dropped: stop timing Long. Distance

timing additional design elements long get. Time() void add. To. Time(long t) Gregor Kiczales:

timing additional design elements long get. Time() void add. To. Time(long t) Gregor Kiczales: 0. . N Customer this piece of setup is inconsistent with the code Timer void stop() void start() long get. Time() 1 invoke when connection drops set and invoke upon new connection 1 1 0. . N caller receiver Connection Local 133 Aspect. J Tutorial Call Long. Distance

timing exercise • Write an aspect representing the timing protocol. 134 Aspect. J Tutorial

timing exercise • Write an aspect representing the timing protocol. 134 Aspect. J Tutorial

timing what is the nature of the crosscutting? • connections and calls are involved

timing what is the nature of the crosscutting? • connections and calls are involved • well defined protocols among them • pieces of the timing protocol must be triggered by the execution of certain basic operations. e. g. – when connection is completed, set and start a timer – when connection drops, stop the timer and add time to customers’ connection time 135 Aspect. J Tutorial

timing an aspect implementation aspect Timing { static aspect Connection. Timing of eachobject(instanceof(Connection)) {

timing an aspect implementation aspect Timing { static aspect Connection. Timing of eachobject(instanceof(Connection)) { private Timer timer = new Timer(); } static aspect Customer. Timing of eachobject(instanceof(Customer)) { private long total. Connect. Time = 0; public long get. Total. Connect. Time() { return total. Connect. Time; } } pointcut start. Timing(Connection c): receptions(void c. complete()); pointcut end. Timing(Connection c): receptions(void c. drop()); static after(Connection c): start. Timing(c) { Connection. Timing. aspect. Of(c). timer. start(); } static after(Connection c): end. Timing(c) { Timer timer = Connection. Timing. aspect. Of(c). timer; timer. stop(); long curr. Time = timer. get. Time(); Customer. Timing. aspect. Of(c. get. Caller()). total. Connect. Time += curr. Time; Customer. Timing. aspect. Of(c. get. Receiver()). total. Connect. Time += curr. Time; } } 136 Aspect. J Tutorial

timing as an object Customer. . . long get. Time() void add. To. Time(long)

timing as an object Customer. . . long get. Time() void add. To. Time(long) 0. . N 1 add. To. Time(timer. get. Time()) 0. . N Timer void stop() void start() long get. Time() Connection. . . drop() new(. . ) timing as an object captures timing support, but does not capture the protocols involved in implementing the timing feature 137 Aspect. J Tutorial

timing as an aspect Timing long get. Time() void add. To. Time(long t) Customer.

timing as an aspect Timing long get. Time() void add. To. Time(long t) Customer. . . 0. . N 1 add. To. Time(timer. get. Time()) 0. . N Timer void stop() void start() long get. Time() Connection. . . drop() new(. . ) timing as an aspect captures the protocols involved in implementing the timing feature 138 Aspect. J Tutorial

timing as an aspect has these benefits • basic objects are not responsible for

timing as an aspect has these benefits • basic objects are not responsible for using the timing facility – timing aspect encapsulates that responsibility, for appropriate objects • if requirements for timing facility change, that change is shielded from the objects – only the timing aspect is affected • removing timing from the design is trivial – just remove the timing aspect 139 Aspect. J Tutorial

timing with Aspect. J has these benefits • object code contains no calls to

timing with Aspect. J has these benefits • object code contains no calls to timing functions – timing aspect code encapsulates those calls, for appropriate objects • if requirements for timing facility change, there is no need to modify the object classes – only the timing aspect class and auxiliary classes needs to be modified • removing timing from the application is trivial – compile without the timing aspect class 140 Aspect. J Tutorial

timing exercises • How would you change your program if the interface to Timer

timing exercises • How would you change your program if the interface to Timer objects changed to Timer void start() long stop. And. Get. Time() • What changes would be necessary without the aspect abstraction? 141 Aspect. J Tutorial

telecom, continued layers of functionality: consistency • ensure that all calls and connections are

telecom, continued layers of functionality: consistency • ensure that all calls and connections are being shut down in the simulation 142 Aspect. J Tutorial

consistency checking Customer Call void start. Call(Customer) pickup. Call(Call) merge. Calls(Call, Call) hangup. Call(Call)

consistency checking Customer Call void start. Call(Customer) pickup. Call(Call) merge. Calls(Call, Call) hangup. Call(Call) 1 store each new call remove calls that Customer get. Caller() • hangup void pickup() • merge void merge(Call) Call 1 0. . N void hangup() 0. . N 1 0. . N Connection caller receiver Customer get. Caller() Customer get. Receiver() void complete() void drop() store each new connection remove connections that drop 0. . N Local 143 Aspect. J Tutorial List of Calls Long. Distance List of Connections check at the end of simulation

consistency checking aspect Consistency. Checker { static Vector calls = new Vector(), connections =

consistency checking aspect Consistency. Checker { static Vector calls = new Vector(), connections = new Vector(); /* The lifecycle of calls */ static after(Call c): receptions(c. new(. . )) { calls. add. Element(c); } static after(Call c): receptions(* c. hangup(. . )) { calls. remove. Element(c); } static after(Call other): receptions(void Call. merge(other)) { calls. remove. Element(other); } /* The lifecycle of connections */ static after(Connection c): receptions(c. new(. . )) { connections. add. Element(c); } static after(Connection c): receptions(* c. drop(. . )) { connections. remove. Element(c); } static after(): within(Telecom. Demo) && executions(void main(. . )) { if (calls. size() != 0) println("ERROR on calls clean up. "); if (connections. size()!=0) println("ERROR on connections clean up. "); } } 144 Aspect. J Tutorial

summary so far • presented examples of aspects in design – intuitions for identifying

summary so far • presented examples of aspects in design – intuitions for identifying aspects • presented implementations in Aspect. J – how the language support can help • raised some style issues – objects vs. aspects 145 Aspect. J Tutorial

when are aspects appropriate? • is there a concern that: – crosscuts the structure

when are aspects appropriate? • is there a concern that: – crosscuts the structure of several objects or operations – is beneficial to separate out 146 Aspect. J Tutorial

… crosscutting • a design concern that involves several objects or operations • implemented

… crosscutting • a design concern that involves several objects or operations • implemented without AOP would lead to distant places in the code that – do the same thing • e. g. trace. Entry(“Point. set”) • try grep to find these [Griswold] – do a coordinated single thing • e. g. timing, observer pattern • harder to find these 147 Aspect. J Tutorial

… beneficial to separate out • does it improve the code in real ways?

… beneficial to separate out • does it improve the code in real ways? – separation of concerns • e. g. think about service without timing – clarifies interactions, reduces tangling • e. g. all the trace. Entry are really the same – easier to modify / extend • e. g. change the implementation of tracing • e. g. abstract aspect re-use – plug and play • tracing aspects unplugged but not deleted 148 Aspect. J Tutorial

good designs summary • capture “the story” well • may lead to good implementations,

good designs summary • capture “the story” well • may lead to good implementations, measured by – code size – tangling – coupling – etc. 149 Aspect. J Tutorial learned through experience, influenced by taste and style

expected benefits of using AOP • good modularity, even in the presence of crosscutting

expected benefits of using AOP • good modularity, even in the presence of crosscutting concerns – less tangled code, more natural code, smaller code – easier maintenance and evolution • easier to reason about, debug, change – more reusable • more possibilities for plug and play • abstract aspects 150 Aspect. J Tutorial

Part V References, Related Work 15 Aspect. J Tutorial

Part V References, Related Work 15 Aspect. J Tutorial

AOP and Aspect. J on the web • aspectj. org • www. parc. xerox.

AOP and Aspect. J on the web • aspectj. org • www. parc. xerox. com/aop 152 Aspect. J Tutorial

Workshops • ECOOP’ 97 – http: //wwwtrese. cs. utwente. nl/aop-ecoop 97 • ICSE’ 98

Workshops • ECOOP’ 97 – http: //wwwtrese. cs. utwente. nl/aop-ecoop 97 • ICSE’ 98 – http: //www. parc. xerox. com/aop/icse 98 • ECOOP’ 98 – http: //wwwtrese. cs. utwente. nl/aop-ecoop 98 • ECOOP’ 99 – http: //wwwtrese. cs. utwente. nl/aop-ecoop 99 • OOPSLA’ 99 – http: //www. cs. ubc. ca/~murphy/multid-workshop-oopsla 99/index. htm • ECOOP’ 00 – http: //trese. cs. utwente. nl/Workshops/adc 2000/ • OOPSLA’ 00 – http: //trese. cs. utwente. nl/Workshops/OOPSLA 2000/ 153 Aspect. J Tutorial

growing interest in separation of crosscutting concerns • aspect-oriented programming – composition filters @

growing interest in separation of crosscutting concerns • aspect-oriented programming – composition filters @ U Twente • [Aksit] – adaptive programming @ Northeastern U • [Lieberherr] • multi-dimensional separation of concerns @ IBM – [Ossher, Tarr] • assessment of SE techniques @ UBC – [Murphy] • information transparency @ UCSD – [Griswold] • … 154 Aspect. J Tutorial

AOP future – idea, language, tools • objects are • • code and state

AOP future – idea, language, tools • objects are • • code and state “little computers” message as goal hierarchical structure • languages support • encapsulation • polymorphism • inheritance • tools • browser, editor, debuggers • preserve object abstraction • aspects are • • + crosscutting structure • languages support • • • + crosscutting • tools • • + preserve aspect abstraction 155 Aspect. J Tutorial

AOP future • language design – more dynamic crosscuts, type system … • tools

AOP future • language design – more dynamic crosscuts, type system … • tools – more IDE support, aspect discovery, re-factoring, recutting… • software engineering – finding aspects, modularity principles, … • metrics – measurable benefits, areas for improvement • theory – type system for crosscutting, fast compilation, advanced crosscut constructs 156 Aspect. J Tutorial

Aspect. J & the Java platform • Aspect. J is a small extension to

Aspect. J & the Java platform • Aspect. J is a small extension to the Java programming language – all valid programs written in the Java programming language are also valid programs in the Aspect. J programming language • Aspect. J has its own compiler, ajc – ajc runs on Java 2 platform – ajc is available under Open Source license – ajc produces Java platform compatible. class files 157 Aspect. J Tutorial

Aspect. J status • release status – 3 major, ~18 minor releases over last

Aspect. J status • release status – 3 major, ~18 minor releases over last year (0. 7 beta 8 is current) – tools • IDE extensions: Emacs, JBuilder 3. 5, Forte 4 J • ajdoc to parallel javadoc • debugger: command line, GUI, & IDE – license • compiler, runtime and tools are free for any use • compiler and tools are Open Source • aspectj. org – May 1999: 90 downloads/mo, 20 members on users list – May 2000: 500 downloads/mo, 500 members on users list • tutorials & training. Gregor Kiczales: – 3 tutorials in 1999, 8 catch in 1999, 12 in 2000 dates up 158 Aspect. J Tutorial

Aspect. J future continue building language, compiler & tools • 0. 8 – one

Aspect. J future continue building language, compiler & tools • 0. 8 – one more IDE – more powerful join point designators • 0. 9 Gregor Kiczales: – inheritance, a few other language cleanups • 1. 0 • catch this up to what we said at – minor language tuning OOPSLA, I think, – incremental compilation, compilation to bytecodes for example, that – at least two more IDEs first version incremental is 1. 1 coming sooner – faster incremental compiler (up to 5 k classes) than this says – source of target classes not required • 2. 0 – new dynamic crosscut constructs commercialization decision after 1. 0 159 Aspect. J Tutorial

credits Aspect. J. org is a Xerox PARC project: Bill Griswold, Erik Hilsdale, Jim

credits Aspect. J. org is a Xerox PARC project: Bill Griswold, Erik Hilsdale, Jim Hugunin, Mik Kersten, Gregor Kiczales, Jeffrey Palm slides, compiler, tools & documentation are available at aspectj. org partially funded by DARPA under contract F 30602 -97 -C 0246 160 Aspect. J Tutorial