AspectOriented Programming with Aspect J Aspect J org

  • Slides: 182
Download presentation
Aspect-Oriented Programming with Aspect. J™ Aspect. J. org Xerox PARC Erik Hilsdale Gregor Kiczales

Aspect-Oriented Programming with Aspect. J™ Aspect. J. org Xerox PARC Erik Hilsdale Gregor Kiczales with Bill Griswold, Wes Isberg, Mik Kersten, Jeffrey Palm partially funded by DARPA under contract F 30602 -97 -C 0246 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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-Oriented Programming with Aspect. J -- OOPSLA 2001

good modularity • XML parsing in org. apache. tomcat – red shows relevant lines

good modularity • XML parsing in org. apache. tomcat – red shows relevant lines of code – nicely fits in one box 3 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 XML parsing

good modularity URL pattern matching • URL pattern matching in org. apache. tomcat –

good modularity URL pattern matching • URL pattern matching in org. apache. tomcat – red shows relevant lines of code – nicely fits in two boxes (using inheritance) 4 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 5 – red shows lines of code that handle logging – not in just one place – not even in a small number of places Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 package org. apache. tomcat. session; // 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 Illegal. State. Exception(msg ); } 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 "); throw new Illegal. State. Exception(msg ); } if (name == null) { String msg = sm. get. String("application. Session. value. iae 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. *; ; /** * 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 $ */ // ----------------------------- Constructors (( Http. Session. Binding. Listener)value). value. Bound(e } ); values. put(name, value); } /** * Construct a new Session associated with the specified Manager. * * @ param manager The manager with which this Session is associated */ public Standard. Session(Manager manager) { super(); this. manager = manager; "); throw new Illegal. Argument. Exception(msg ); } return values. get(name); } /** * The collection of user data attributes associated with this Session. */ private Hashtable attributes = new Hashtable (); /** * The time this session was created, in milliseconds since midnight, * January 1, 1970 GMT. */ private long creation. Time = 0 L; /** * The session identifier of this Session. */ private String id = null; /** * @deprecated */ public String[] get. Value. Names () { Enumeration e = get. Attribute. Names (); Vector names = new Vector(); /** * Descriptive information describing this Session implementation. */ private static final String info = "Standard. Session/1. 0"; while ( e. has. More. Elements ()) { names. add. Element(e. next. Element ()); } String[] value. Names = new String[names. size()]; names. copy. Into(value. Names ); /** * The last accessed time for this Session. */ private long last. Accessed. Time = creation. Time ; return value. Names ; } if ( this. inactive. Interval != -1) { this. inactive. Interval *= 60; } } 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 Illegal. State. Exception(msg ); } /** * The Manager with which this Session is associated. */ private Manager manager = null; Hashtable values. Clone = ( Hashtable)values. clone (); /** * Called by context when request comes in so that accesses and * inactivities can be dealt with accordingly. */ validate(); } 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; if ( this. Interval > inactive. Interval ) { invalidate(); } } // HTTP SESSION IMPLEMENTATION METHODS public String get. Id () { if (valid) { return id; } else { String msg = sm. get. String("application. Session. session. ise public void remove. Value(String name) { remove. Attribute(name ); } public void remove. Attribute(String name) { if (! valid) { String msg = sm. get. String("application. Session. session. ise "); throw new Illegal. State. Exception(msg ); } "); /** * Flag indicating whether this session is new or not. */ private boolean is. New = true; /** * Flag indicating whether this session is valid or not. */ private boolean is. Valid = false; throw new Illegal. Argument. Exception(msg ); } /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager("org. apache. tomcat. se ssion "); Object o = values. get(name); if (o instanceof Http. Session. Binding. Listener ) { Http. Session. Binding. Event e = new Http. Session. Binding. Event(this, name ); "); (( Http. Session. Binding. Listener)o). value. Unbound(e } public void set. Max. Inactive. Interval(int interval) { if (! valid) { String msg = sm. get. String("application. Session. session. ise "); /** * The HTTP session context associated with this session. */ private static Http. Session. Context session. Context = null; "); /** * The current accessed time for this session. */ private long this. Accessed. Time = creation. Time ; throw new Illegal. State. Exception(msg ); } inactive. Interval = interval; } public int get. Max. Inactive. Interval () { if (! valid) { String msg = sm. get. String("application. Session. session. ise "); throw new Illegal. State. Exception(msg ); } return inactive. Interval ; } } //-----------------------------------"); this. last. Accessed. Time = this. Accessed. Time ; this. Accessed. Time = System. current. Time. Millis (); this. New =false; } /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. */ public void expire() { // Remove this session from our manager's active sessions if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); // 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 ); } // Mark this session as invalid set. Valid(false ); /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { // 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; // Tell our Manager that this Session has been recycled if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). recycle(this); } // ------------------------ Session Package Methods /** * Return the <code> is. Valid </code> flag for this session. */ boolean is. Valid () { return ( this. Valid ); } /** * Set the <code> is. New </code> flag for this session. * * @ param is. New The new value for the <code> is. New </code> flag */ void set. New(boolean is. New ) { // -------------------------- Session Properties /** * Set the creation time for this session. This method is called by the * Manager when an existing Session instance is reused. * * @ param time The new creation time */ public void set. Creation. Time(long time) { throw new Illegal. State. Exception(msg ); } } this. creation. Time = time; this. last. Accessed. Time = time; this. Accessed. Time = time; } /** * Return the session identifier for this session. */ public String get. Id () { /** * 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) { set. Attribute(name , value); } /** * 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) { 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)); } } /** * 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) { remove. 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. 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) { /** * 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 ; } // ------------------------- Http. Session Properties /** * 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 () { return ( this. creation. Time ); } Http. Session Private Methods // 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 (); public final class Standard. Manager extends Manager. Base implements Lifecycle, Runnable { // --------------------------- Instance Variables // 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); } /** * The interval (in seconds) between checks for expired sessions. */ private int check. Interval = 60; /** * Has this component been configured yet? */ private boolean configured = false; } /** * 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 () { if ( session. Context == null) session. Context = new Standard. Session. Context (); return ( session. Context ); } // -----------------------Http. Session Public Methods /** * 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) { return (attributes. get(name)); return (this. id); } if ((this. id != null) && (manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); /** * 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 () { this. id = id; return (attributes. keys()); if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). add(this); } Server. Sess on } /** * Return descriptive information about this Session implementation and * the corresponding version number, in the format * <code>& lt; description> /< 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 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 () { /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager("org. apache. tomcat. session return ( this. last. Accessed. Time ); } /** * Return the Manager within which this Session is valid. */ public Manager get. Manager () { 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) { 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() { // Cause this session to expire expire(); } /** * 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 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) { 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? } * called for each request by a Request. Interceptor. * * @ param session The session to be marked */ public void accessed(Context ctx, Request req, String id) { if( session == null) return; if (session instanceof Session) // cache the Http. Session - avoid another find // XXX should we throw exception or just return null ? ? * <b>IMPLEMENTATION NOTE</b>: Once we commit to the new Manager/Session public Http. Session find. Session ( Context ctx, String id ) { * paradigm, I would suggest moving the logic implemented here back into try { * the core level. 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> } catch ( IOException e) { * XXX - At present, there is no way (via the Session. Manager interface) } for ())); 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? } 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. ())); * * @author Craig R. Mc. Clanahan } public Http. Session create. Session(Context ctx) { return manager. create. Session(). get. 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? } public final class Standard. Session. Manager implements Session. Manager { * Remove all sessions because our associated Context is being shut down. * ())); /** * 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 { * @ param ctx The context that is being shut down // ------------------------------ Constructors */ public void remove. Sessions(Context ctx) { /** * Return the check interval (in seconds) for this Manager. */ public int get. Check. Interval () { // Stop the background reaper thread thread. Stop (); /** * Set the check interval (in seconds) for this Manager. * * @ param check. Interval The new check interval */ public void set. Check. Interval(int check. Interval ) { // 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(); } this. check. Interval = check. Interval ; } } // ---------------------------- Private Methods 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. *; /** * * @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 { private String. Manager sm = String. Manager. get. Manager("org. apache. tomcat. session "); private static Server. Session. Manager manager; // = new Server. Session. Manager (); // XXX // sync'd for safty -- no other thread should be getting something // from this while we are reaping. This isn't the most optimal // solution for this, but we'll determine something else later. synchronized void reap() { Enumeration enum = sessions. keys(); while ( enum. has. More. Elements ()) { Object key = enum. next. Element (); Server. Session session = ( Server. Session)sessions. get(key ); session. reap(); session. validate(); } } synchronized void remove. Session(Server. Session session) { String id = session. get. Id (); session. invalidate(); sessions. remove(id); } static { manager = new Server. Session. Manager (); } public static Server. Session. Manager get. Manager () { return manager; } private Hashtable sessions = new Hashtable (); private Reaper reaper; private Server. Session. Manager () { reaper = Reaper. get. Reaper (); reaper. set. Server. Session. Manager(this ); reaper. start(); } Server. Session serv. S =ap. S. get. Server. Session (); serv. S. accessed (); ap. S. accessed (); // cache it - no need to compute it again req. set. Session ( ap. S ); } 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); if(-1 != inactive. Interval ) { session. set. Max. Inactive. Interval(inactive. Interval ); } return session. get. Application. Session ( ctx, true ); } public Http. Session find. Session(Context ctx, String id) { Server. Session s. Session =(Server. Session)sessions. get(id ); if(s. Session ==null) return null; this. max. Inactive. Interval = interval; return s. Session. get. Application. Session(ctx , false); } } } /** * Return the maximum number of active Sessions allowed, or -1 for * no limit. */ public int get. Max. Active. Sessions () { return ( this. max. Active. Sessions ); } /** * 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) { public void remove. Sessions(Context context) { Enumera 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(); } } /** * Sleep for the duration specified by the <code> * property. */ private void thread. Sleep () { check. Interval </code> try { Thread. sleep(check. Interval * 1000 L); } catch ( Interrupted. Exception e) { ; } this. max. Active. Sessions = max; protected int inactive. Interval = -1; /** * Invalidate all sessions that have expired. */ private void process. Expires () { long time. Now = System. current. Time. Millis (); Session sessions[] = find. Sessions (); return (this. info); } // ----------------------------- 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 () { if (( max. Active. Sessions >= 0) && (sessions. size() >= max. Active. Sessions )) throw new Illegal. State. Exception ( sm. get. String("standard. Manager. create. Session. ise return ( super. create. Session ()); } if (thread != null) return; thread. Done = false; thread = new Thread(this, thread. Name ); thread. set. Daemon(true ); thread. start(); } ")); /** * Stop the background thread that is periodically checking for * session timeouts. */ private void thread. Stop () { if (thread == null) return; thread. Done = true; thread. interrupt(); try { thread. join(); } catch ( Interrupted. Exception e) { ; } thread = null; } // --------------------------- Background Thread /** * The background thread that checks for session timeouts and shutdown. */ public void run() { } } try { ((Lifecycle) manager). configure(null); } catch ( Lifecycle. Exception e) { throw new Illegal. State. Exception ("" + e); } ((Lifecycle) manager). start(); } catch ( Lifecycle. Exception e) { } throw new 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 // Validate and update our current component state if (!started) throw new Lifecycle. Exception ( sm. get. String("standard. Manager. not. Started ")); started = false; /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <code>& lt; description> /< version&gt ; </code>. */ public String get. Info () { manager = new Standard. Manager (); if (manager instanceof Lifecycle) { * descriptor ( web. xml ). This method lets the Context conforgure the // --------------------------- Instance * session manager according to this value. Variables } Server. Session. Manager // contexts, we just want to remove the sessions of ctx! * Create a new Session. Manager that adapts to the corresponding // The manager will still run after that ( i. e. keep database Manager // connection open * implementation. if (manager instanceof Lifecycle) { */ try { public Standard. Session. Manager () { ((Lifecycle) manager). stop(); } // ------------------------------- Properties return ( this. check. Interval ); } Aspec -Or en ed Programm ng w h Aspec J -- OOPSLA 2001 * Mark the specified session's last accessed time. This should be Http. Session session= find. Session(ctx , id); /** * <p> // Parse and process our configuration parameters if (!(" Manager". equals(parameters. get. Node. Name ()))) return; Named. Node. Map attributes = parameters. get. Attributes (); Node node = null; // Loop until the termination semaphore is set while (! thread. Done ) { thread. Sleep (); process. Expires (); } 6 /** req. set. Session ( session ); * XXX - At present, use of <code> Standard. Manager </code> is hard coded, } * and lifecycle configuration is not supported. /** * 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 { /** * Name to register for the background thread. */ private String thread. Name = "Standard. Manager "; return (null); } import org. apache. tomcat. core. Session. Manager ; import org. apache. tomcat. util. Session. Util ; * <p> // Start the background reaper thread thread. Start (); /** * The background thread completion semaphore. */ private boolean thread. Done = false; public void accessed( Context ctx, Request req, String id ) { Application. Session ap. S=(Application. Session)find. Session ( ctx, id); if( ap. S==null) return; return ( this. New ); ")); } // ------------------------------- Private Class 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); import org. apache. tomcat. core. Response; ((Session) session). access(); * Specialized implementation of org. apache. tomcat. core. Session. Manager // 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. */ private Thread thread = null; // 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 )); } final class Standard. Session. Context implements Http. Session. Context { import org. apache. tomcat. core. Request; * that adapts to the new component-based Manager implementation. "); /** * Has this component been started yet? */ private boolean started = false; // 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 ); } /** * 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. */ 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; } /** * 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 () { // 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; import javax. servlet. http. Cookie ; import javax. servlet. http. Http. Session ; // XXX a manager may be shared by multiple /** * The descriptive information about this implementation. */ private static final String info = "Standard. Manager/1. 0"; // 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 )); } 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)); 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")); } } } /** * 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 { } /** * 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 { } /** * Set the session identifier for this session. * * @ param id The new session identifier */ public void set. Id(String id) { // ----------------------------- Public Methods import java. io. IOException ; /** * 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 ) { package org. apache. tomcat. session; // --------------------------- 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)); } // ---------------------- Standard. Session. Manager package org. apache. tomcat. session; import java. io. IOException ; import java. util. Enumeration; import java. util. Hashtable ; import java. util. Vector; import org. apache. tomcat. catalina. *; import javax. servlet. http. Cookie ; import javax. servlet. http. Http. Session ; import org. apache. tomcat. util. String. Manager ; import org. w 3 c. dom. Named. Node. Map; import org. w 3 c. dom. Node; if ((manager != null) && manager. get. Distributable () && !(value instanceof Serializable )) throw new Illegal. Argument. Exception ( sm. get. String("standard. Session. set. Attribute. iae ")); } Standard. Manager Sess on n ercep or } } ); values. remove(name); } throw new Illegal. State. Exception(msg ); } } /** * * @deprecated */ public Http. Session. Context get. Session. Context () { return new Session. Context. Impl (); } public long get. Last. Accessed. Time () { if (valid) { return last. Accessed ; } else { String msg = sm. get. String("application. Session. session. ise /** * @deprecated */ if (name == null) { String msg = sm. get. String("application. Session. value. iae throw new Illegal. State. Exception(msg ); } } public long get. Creation. Time () { if (valid) { return creation. Time ; } else { String msg = sm. get. String("application. Session. session. ise /** * 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; 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 (); /** * 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() { } // -------------------------- Instance Variables if (name == null) { String msg = sm. get. String("application. Session. value. iae this. inactive. Interval = context. get. Session. Time. Out (); // ------------------------- Session Public Methods } throw new Illegal. State. Exception(msg ); } Application. Session(String id, Server. Session server. Session , Context context) { this. server. Session = server. Session ; this. context = context; this. id = id; } final class Standard. Session implements Http. Session , Session { public class Application. Session implements Http. Session { 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; return (( Http. Session ) this); remove. Value(name ); // 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); public Object get. Attribute(String name) { if (! valid) { String msg = sm. get. String("application. Session. session. ise /** * 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] */ import java. io. IOException ; import java. io. Object. Input. Stream ; import java. io. Object. Output. Stream ; import java. io. Serializable ; import java. util. Enumeration; import java. util. Hashtable ; import java. util. Vector; import javax. servlet. Servlet. Exception ; import javax. servlet. http. Http. Session. Binding. Event ; import javax. servlet. http. Http. Session. Binding. Listener import javax. servlet. http. Http. Session. Context ; import org. apache. tomcat. catalina. *; import org. apache. tomcat. util. String. Manager ; "); throw new Illegal. Argument. Exception(msg ); } /** * @deprecated */ public Object get. Value(String name) { return get. Attribute(name ); } package org. apache. tomcat. session; /** * Return the <code> Http. Session </code> for which this object * is the facade. */ public Http. Session get. Session () { ); * * @ param minutes The session inactivity timeout in minutes. /** * The Manager implementation we are actually using. */ private Manager manager = null; */ public void set. Session. Time. Out(int minutes) { if(-1 != minutes) { // The manager works with seconds. . . manager. set. Max. Inactive. Interval(minutes * 60); } } }

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 7 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 8 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 9 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 10 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 Standard. Session S andard. Sess on package org. apache. tomcat. session; // 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 Illegal. State. Exception(msg ); } 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 "); throw new Illegal. State. Exception(msg ); } if (name == null) { String msg = sm. get. String("application. Session. value. iae 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. *; ; /** * 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 $ */ // ----------------------------- Constructors (( Http. Session. Binding. Listener)value). value. Bound(e } ); values. put(name, value); } /** * Construct a new Session associated with the specified Manager. * * @ param manager The manager with which this Session is associated */ public Standard. Session(Manager manager) { super(); this. manager = manager; "); throw new Illegal. Argument. Exception(msg ); } return values. get(name); } /** * The collection of user data attributes associated with this Session. */ private Hashtable attributes = new Hashtable (); /** * The time this session was created, in milliseconds since midnight, * January 1, 1970 GMT. */ private long creation. Time = 0 L; /** * The session identifier of this Session. */ private String id = null; /** * @deprecated */ public String[] get. Value. Names () { Enumeration e = get. Attribute. Names (); Vector names = new Vector(); /** * Descriptive information describing this Session implementation. */ private static final String info = "Standard. Session/1. 0"; while ( e. has. More. Elements ()) { names. add. Element(e. next. Element ()); } String[] value. Names = new String[names. size()]; names. copy. Into(value. Names ); /** * The last accessed time for this Session. */ private long last. Accessed. Time = creation. Time ; return value. Names ; } if ( this. inactive. Interval != -1) { this. inactive. Interval *= 60; } } 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 Illegal. State. Exception(msg ); } /** * The Manager with which this Session is associated. */ private Manager manager = null; Hashtable values. Clone = ( Hashtable)values. clone (); /** * Called by context when request comes in so that accesses and * inactivities can be dealt with accordingly. */ validate(); } 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; if ( this. Interval > inactive. Interval ) { invalidate(); } } // HTTP SESSION IMPLEMENTATION METHODS public String get. Id () { if (valid) { return id; } else { String msg = sm. get. String("application. Session. session. ise public void remove. Value(String name) { remove. Attribute(name ); } public void remove. Attribute(String name) { if (! valid) { String msg = sm. get. String("application. Session. session. ise "); throw new Illegal. State. Exception(msg ); } "); /** * Flag indicating whether this session is new or not. */ private boolean is. New = true; /** * Flag indicating whether this session is valid or not. */ private boolean is. Valid = false; throw new Illegal. Argument. Exception(msg ); } /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager("org. apache. tomcat. se ssion "); Object o = values. get(name); if (o instanceof Http. Session. Binding. Listener ) { Http. Session. Binding. Event e = new Http. Session. Binding. Event(this, name ); "); (( Http. Session. Binding. Listener)o). value. Unbound(e } public void set. Max. Inactive. Interval(int interval) { if (! valid) { String msg = sm. get. String("application. Session. session. ise "); /** * The HTTP session context associated with this session. */ private static Http. Session. Context session. Context = null; "); /** * The current accessed time for this session. */ private long this. Accessed. Time = creation. Time ; throw new Illegal. State. Exception(msg ); } inactive. Interval = interval; } public int get. Max. Inactive. Interval () { if (! valid) { String msg = sm. get. String("application. Session. session. ise "); throw new Illegal. State. Exception(msg ); } return inactive. Interval ; } } //-----------------------------------"); this. last. Accessed. Time = this. Accessed. Time ; this. Accessed. Time = System. current. Time. Millis (); this. New =false; } /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. */ public void expire() { // Remove this session from our manager's active sessions if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); // 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 ); } // Mark this session as invalid set. Valid(false ); /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { // 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; // Tell our Manager that this Session has been recycled if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). recycle(this); } // ------------------------ Session Package Methods /** * Return the <code> is. Valid </code> flag for this session. */ boolean is. Valid () { return ( this. Valid ); } /** * Set the <code> is. New </code> flag for this session. * * @ param is. New The new value for the <code> is. New </code> flag */ void set. New(boolean is. New ) { // -------------------------- Session Properties /** * Set the creation time for this session. This method is called by the * Manager when an existing Session instance is reused. * * @ param time The new creation time */ public void set. Creation. Time(long time) { throw new Illegal. State. Exception(msg ); } } this. creation. Time = time; this. last. Accessed. Time = time; this. Accessed. Time = time; } /** * Return the session identifier for this session. */ public String get. Id () { /** * 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) { set. Attribute(name , value); } /** * 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) { 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)); } } /** * 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) { remove. 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. 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) { /** * 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 ; } // ------------------------- Http. Session Properties /** * 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 () { return ( this. creation. Time ); } Http. Session Private Methods // 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 (); public final class Standard. Manager extends Manager. Base implements Lifecycle, Runnable { // --------------------------- Instance Variables // 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); } /** * The interval (in seconds) between checks for expired sessions. */ private int check. Interval = 60; /** * Has this component been configured yet? */ private boolean configured = false; } /** * 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 () { if ( session. Context == null) session. Context = new Standard. Session. Context (); return ( session. Context ); } // -----------------------Http. Session Public Methods /** * 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) { return (attributes. get(name)); return (this. id); } if ((this. id != null) && (manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). remove(this); /** * 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 () { this. id = id; return (attributes. keys()); if ((manager != null) && (manager instanceof Manager. Base )) (( Manager. Base ) manager). add(this); } Server. Sess on } /** * Return descriptive information about this Session implementation and * the corresponding version number, in the format * <code>& lt; description> /< 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 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 () { /** * The string manager for this package. */ private String. Manager sm = String. Manager. get. Manager("org. apache. tomcat. session return ( this. last. Accessed. Time ); } /** * Return the Manager within which this Session is valid. */ public Manager get. Manager () { 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) { 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() { // Cause this session to expire expire(); } /** * 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 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) { 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? } * called for each request by a Request. Interceptor. * * @ param session The session to be marked */ public void accessed(Context ctx, Request req, String id) { if( session == null) return; if (session instanceof Session) // cache the Http. Session - avoid another find // XXX should we throw exception or just return null ? ? * <b>IMPLEMENTATION NOTE</b>: Once we commit to the new Manager/Session public Http. Session find. Session ( Context ctx, String id ) { * paradigm, I would suggest moving the logic implemented here back into try { * the core level. 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> } catch ( IOException e) { * XXX - At present, there is no way (via the Session. Manager interface) } for ())); 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? } 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. ())); * * @author Craig R. Mc. Clanahan } public Http. Session create. Session(Context ctx) { return manager. create. Session(). get. 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? } public final class Standard. Session. Manager implements Session. Manager { * Remove all sessions because our associated Context is being shut down. * ())); /** * 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 { * @ param ctx The context that is being shut down // ------------------------------ Constructors */ public void remove. Sessions(Context ctx) { /** * Return the check interval (in seconds) for this Manager. */ public int get. Check. Interval () { // Stop the background reaper thread thread. Stop (); /** * Set the check interval (in seconds) for this Manager. * * @ param check. Interval The new check interval */ public void set. Check. Interval(int check. Interval ) { // 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(); } this. check. Interval = check. Interval ; } } // ---------------------------- Private Methods 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. *; /** * * @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 { private String. Manager sm = String. Manager. get. Manager("org. apache. tomcat. session "); private static Server. Session. Manager manager; // = new Server. Session. Manager (); // XXX // sync'd for safty -- no other thread should be getting something // from this while we are reaping. This isn't the most optimal // solution for this, but we'll determine something else later. synchronized void reap() { Enumeration enum = sessions. keys(); while ( enum. has. More. Elements ()) { Object key = enum. next. Element (); Server. Session session = ( Server. Session)sessions. get(key ); session. reap(); session. validate(); } } synchronized void remove. Session(Server. Session session) { String id = session. get. Id (); session. invalidate(); sessions. remove(id); } static { manager = new Server. Session. Manager (); } public static Server. Session. Manager get. Manager () { return manager; } private Hashtable sessions = new Hashtable (); private Reaper reaper; private Server. Session. Manager () { reaper = Reaper. get. Reaper (); reaper. set. Server. Session. Manager(this ); reaper. start(); } Server. Session serv. S =ap. S. get. Server. Session (); serv. S. accessed (); ap. S. accessed (); // cache it - no need to compute it again req. set. Session ( ap. S ); } 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); if(-1 != inactive. Interval ) { session. set. Max. Inactive. Interval(inactive. Interval ); } return session. get. Application. Session ( ctx, true ); } public Http. Session find. Session(Context ctx, String id) { Server. Session s. Session =(Server. Session)sessions. get(id ); if(s. Session ==null) return null; this. max. Inactive. Interval = interval; return s. Session. get. Application. Session(ctx , false); } } } /** * Return the maximum number of active Sessions allowed, or -1 for * no limit. */ public int get. Max. Active. Sessions () { return ( this. max. Active. Sessions ); } /** * 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) { public void remove. Sessions(Context context) { Enumera 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(); } } /** * Sleep for the duration specified by the <code> * property. */ private void thread. Sleep () { check. Interval </code> try { Thread. sleep(check. Interval * 1000 L); } catch ( Interrupted. Exception e) { ; } this. max. Active. Sessions = max; protected int inactive. Interval = -1; /** * Invalidate all sessions that have expired. */ private void process. Expires () { long time. Now = System. current. Time. Millis (); Session sessions[] = find. Sessions (); return (this. info); } // ----------------------------- 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 () { if (( max. Active. Sessions >= 0) && (sessions. size() >= max. Active. Sessions )) throw new Illegal. State. Exception ( sm. get. String("standard. Manager. create. Session. ise return ( super. create. Session ()); } if (thread != null) return; thread. Done = false; thread = new Thread(this, thread. Name ); thread. set. Daemon(true ); thread. start(); } ")); /** * Stop the background thread that is periodically checking for * session timeouts. */ private void thread. Stop () { if (thread == null) return; thread. Done = true; thread. interrupt(); try { thread. join(); } catch ( Interrupted. Exception e) { ; } thread = null; } // --------------------------- Background Thread /** * The background thread that checks for session timeouts and shutdown. */ public void run() { } } try { ((Lifecycle) manager). configure(null); } catch ( Lifecycle. Exception e) { throw new Illegal. State. Exception ("" + e); } ((Lifecycle) manager). start(); } catch ( Lifecycle. Exception e) { } throw new 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 // Validate and update our current component state if (!started) throw new Lifecycle. Exception ( sm. get. String("standard. Manager. not. Started ")); started = false; /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <code>& lt; description> /< version&gt ; </code>. */ public String get. Info () { manager = new Standard. Manager (); if (manager instanceof Lifecycle) { * descriptor ( web. xml ). This method lets the Context conforgure the // --------------------------- Instance * session manager according to this value. Variables } Server. Session. Manager Server. Sess on. Manager // contexts, we just want to remove the sessions of ctx! * Create a new Session. Manager that adapts to the corresponding // The manager will still run after that ( i. e. keep database Manager // connection open * implementation. if (manager instanceof Lifecycle) { */ try { public Standard. Session. Manager () { ((Lifecycle) manager). stop(); } // ------------------------------- Properties return ( this. check. Interval ); } Aspec -Or en ed Programm ng w h Aspec J -- OOPSLA 2001 * Mark the specified session's last accessed time. This should be Http. Session session= find. Session(ctx , id); /** * <p> // Parse and process our configuration parameters if (!(" Manager". equals(parameters. get. Node. Name ()))) return; Named. Node. Map attributes = parameters. get. Attributes (); Node node = null; // Loop until the termination semaphore is set while (! thread. Done ) { thread. Sleep (); process. Expires (); } 11 /** req. set. Session ( session ); * XXX - At present, use of <code> Standard. Manager </code> is hard coded, } * and lifecycle configuration is not supported. /** * 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 { /** * Name to register for the background thread. */ private String thread. Name = "Standard. Manager "; return (null); } import org. apache. tomcat. core. Session. Manager ; import org. apache. tomcat. util. Session. Util ; * <p> // Start the background reaper thread thread. Start (); /** * The background thread completion semaphore. */ private boolean thread. Done = false; public void accessed( Context ctx, Request req, String id ) { Application. Session ap. S=(Application. Session)find. Session ( ctx, id); if( ap. S==null) return; return ( this. New ); ")); } // ------------------------------- Private Class 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); import org. apache. tomcat. core. Response; ((Session) session). access(); * Specialized implementation of org. apache. tomcat. core. Session. Manager // 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. */ private Thread thread = null; // 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 )); } final class Standard. Session. Context implements Http. Session. Context { import org. apache. tomcat. core. Request; * that adapts to the new component-based Manager implementation. "); /** * Has this component been started yet? */ private boolean started = false; // 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 ); } /** * 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. */ 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; } /** * 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 () { // 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; import javax. servlet. http. Cookie ; import javax. servlet. http. Http. Session ; // XXX a manager may be shared by multiple /** * The descriptive information about this implementation. */ private static final String info = "Standard. Manager/1. 0"; // 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 )); } 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)); 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")); } } } /** * 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 { } /** * 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 { } /** * Set the session identifier for this session. * * @ param id The new session identifier */ public void set. Id(String id) { // ----------------------------- Public Methods import java. io. IOException ; /** * 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 ) { package org. apache. tomcat. session; // --------------------------- 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)); } // ---------------------- Standard. Session. Manager S andard. Sess on. Manager package org. apache. tomcat. session; import java. io. IOException ; import java. util. Enumeration; import java. util. Hashtable ; import java. util. Vector; import org. apache. tomcat. catalina. *; import javax. servlet. http. Cookie ; import javax. servlet. http. Http. Session ; import org. apache. tomcat. util. String. Manager ; import org. w 3 c. dom. Named. Node. Map; import org. w 3 c. dom. Node; if ((manager != null) && manager. get. Distributable () && !(value instanceof Serializable )) throw new Illegal. Argument. Exception ( sm. get. String("standard. Session. set. Attribute. iae ")); } Standard. Manager Sess on n ercep or } } ); values. remove(name); } throw new Illegal. State. Exception(msg ); } } /** * * @deprecated */ public Http. Session. Context get. Session. Context () { return new Session. Context. Impl (); } public long get. Last. Accessed. Time () { if (valid) { return last. Accessed ; } else { String msg = sm. get. String("application. Session. session. ise /** * @deprecated */ if (name == null) { String msg = sm. get. String("application. Session. value. iae throw new Illegal. State. Exception(msg ); } } public long get. Creation. Time () { if (valid) { return creation. Time ; } else { String msg = sm. get. String("application. Session. session. ise /** * 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; 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 (); /** * 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() { } // -------------------------- Instance Variables if (name == null) { String msg = sm. get. String("application. Session. value. iae this. inactive. Interval = context. get. Session. Time. Out (); // ------------------------- Session Public Methods } throw new Illegal. State. Exception(msg ); } Application. Session(String id, Server. Session server. Session , Context context) { this. server. Session = server. Session ; this. context = context; this. id = id; } final class Standard. Session implements Http. Session , Session { public class Application. Session implements Http. Session { 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; return (( Http. Session ) this); remove. Value(name ); // 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); public Object get. Attribute(String name) { if (! valid) { String msg = sm. get. String("application. Session. session. ise /** * 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] */ import java. io. IOException ; import java. io. Object. Input. Stream ; import java. io. Object. Output. Stream ; import java. io. Serializable ; import java. util. Enumeration; import java. util. Hashtable ; import java. util. Vector; import javax. servlet. Servlet. Exception ; import javax. servlet. http. Http. Session. Binding. Event ; import javax. servlet. http. Http. Session. Binding. Listener import javax. servlet. http. Http. Session. Context ; import org. apache. tomcat. catalina. *; import org. apache. tomcat. util. String. Manager ; "); throw new Illegal. Argument. Exception(msg ); } /** * @deprecated */ public Object get. Value(String name) { return get. Attribute(name ); } package org. apache. tomcat. session; /** * Return the <code> Http. Session </code> for which this object * is the facade. */ public Http. Session get. Session () { ); * * @ param minutes The session inactivity timeout in minutes. /** * The Manager implementation we are actually using. */ private Manager manager = null; */ public void set. Session. Time. Out(int minutes) { if(-1 != minutes) { // The manager works with seconds. . . manager. set. Max. Inactive. Interval(minutes * 60); } } }

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. Interception 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 12 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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, Forte • user feedback is driving language design – users@aspectj. org – support@aspectj. org • currently at 1. 0 b 1 release 13 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 14 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 15 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 16 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Part II Basic Mechanisms of Aspect. J Aspect-Oriented Programming with Aspect. J -- OOPSLA

Part II Basic Mechanisms of Aspect. J Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 18 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

basic mechanisms • 1 overlay onto Java – dynamic join points • “points in the execution” of Java programs • 4 small additions to Java – pointcuts • pick out join points and values at those points – primitive pointcuts – user-defined pointcuts – advice • additional action to take at join points in a pointcut – intra-class declarations (aka “open classes”) – aspect • a modular unit of crosscutting behavior – comprised of advice, intra-class declarations, field, constructor and method declarations 19 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

a simple figure editor factory methods Display * Figure. Element Figure make. Point(. .

a simple figure editor factory methods Display * Figure. Element Figure make. Point(. . ) make. Line(. . ) Point set. X(int) set. Y(int) 20 move. By(int, int) Line 2 set. P 1(Point) set. P 2(Point) Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 operations that move elements

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) { this. p 1 = p 1; } void set. P 2(Point p 2) { this. p 2 = p 2; } void move. By(int dx, int dy) {. . . } } 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) { this. x = x; } void set. Y(int y) { this. y = y; } void move. By(int dx, int dy) {. . . } } 21 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

display updating • collection of figure elements – – that move periodically must refresh

display updating • collection of figure elements – – that move periodically must refresh the display as needed complex collection asynchronous events • other examples – session liveness – value caching 22 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 we will initially assume just a single display

join points key points in dynamic call graph a method is called and returns

join points key points in dynamic call graph a method is called and returns or throws a Figure a method is called and returns or throws dispatch a Line a method executes and returns or throws 23 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 dispatch

join point terminology method call join points a Line dispatch method execution join points

join point terminology method call join points a Line dispatch method execution join points • several kinds of join points – – – 24 method & constructor call join points method & constructor execution join points field get & set join points exception handler execution join points static & dynamic initialization join points Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 Figure repeated calls result in new join points 25 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

primitive pointcuts “a means of identifying join points” a pointcut is a kind of

primitive pointcuts “a means of identifying join points” a pointcut is a kind of predicate on join points that: – can match or not match any given join point and – optionally, can pull out some of the values at that join point call(void Line. set. P 1(Point)) matches if the join point is a method call with this signature 26 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

pointcut composition pointcuts compose like predicates, using &&, || and ! a “void Line.

pointcut composition pointcuts compose like predicates, using &&, || and ! a “void Line. set. P 1(Point)” call or call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)); a “void Line. set. P 2(Point)” call each time a Line receives a “void set. P 1(Point)” or “void set. P 2(Point)” method call 27 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

user-defined pointcuts defined use the pointcut construct user-defined (aka named) pointcuts – can be

user-defined pointcuts defined use the pointcut construct user-defined (aka named) pointcuts – can be used in the same way as primitive pointcuts name parameters pointcut move(): call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)); more on parameters and how pointcut can expose values at join points in a few slides 28 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

pointcuts user-defined pointcut designator pointcut move(): call(void Line. set. P 1(Point)) || call(void Line.

pointcuts user-defined pointcut designator pointcut move(): call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)); primitive pointcut designator, can also be: - call, execution - this, target - get, set - within, withincode - handler - cflow, cflowbelow - initialization, staticinitialization 29 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 move(): call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)); after() returning: move() { <code here runs after each move> } 30 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 a Line

a simple aspect Display. Updating v 1 an aspect defines a special class that

a simple aspect Display. Updating v 1 an aspect defines a special class that can crosscut other classes aspect Display. Updating { pointcut move(): call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)); after() returning: move() { Display. update(); } } box means complete running code 31 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

without Aspect. J Display. Updating v 1 class Line { private Point p 1,

without Aspect. J Display. Updating v 1 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) { this. p 1 = p 1; Display. update(); } void set. P 2(Point p 2) { this. p 2 = p 2; Display. update(); } } • what you would expect – update calls are tangled through the code – “what is going on” is less explicit 32 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

pointcuts can cut across multiple classes pointcut move(): call(void Line. set. P 1(Point)) ||

pointcuts can cut across multiple classes pointcut move(): call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int)); 33 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

pointcuts can use interface signatures pointcut move(): call(void Figure. Element. move. By(int, int)) ||

pointcuts can use interface signatures pointcut move(): call(void Figure. Element. move. By(int, int)) || call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int)); 34 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

a multi-class aspect Display. Updating v 2 aspect Display. Updating { pointcut move(): call(void

a multi-class aspect Display. Updating v 2 aspect Display. Updating { pointcut move(): call(void Figure. Element. move. By(int, int)) || call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int)); 35 after() returning: move() { Display. update(); } } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

using values at join points demonstrate first, explain in detail afterwards • pointcut can

using values at join points demonstrate first, explain in detail afterwards • pointcut can explicitly expose certain values • advice can use value parameter mechanism being used pointcut move(Figure. Element fig. Elt): target(fig. Elt) && (call(void Figure. Element. move. By(int, int)) || call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int))); 36 after(Figure. Element fe) returning: move(fe) { <fe is bound to the figure element> } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

explaining parameters… of user-defined pointcut designator • variable in place of type name in

explaining parameters… of user-defined pointcut designator • variable in place of type name in pointcut designator – pulls corresponding value out of join points • variable bound in user-defined pointcut designator – makes value accessible on pointcut parameters pointcut move(Line l): target(l) && (call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point))); typed variable in place of type name 37 after(Line line): move(line) { <line is bound to the line> } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

explaining 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 move(Line l): target(l) && (call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point))); advice parameters 38 after(Line line): move(line) { <line is bound to the line> } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 typed variable in place of type name

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

explaining 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 move(Line l): target(l) && (call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point))); 39 after(Line line): move(line) { <line is bound to the line> } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

target primitive pointcut designator target(<type name>) any join point at which target object is

target primitive pointcut designator target(<type name>) any join point at which target object is an instance of type (or class) name target(Point) target(Line) target(Figure. Element) “any join point” means it matches join points of all kinds • • • 40 method & constructor call join points method & constructor execution join points field get & set join points exception handler execution join points static & dynamic initialization join points Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

an idiom for… getting target object in a polymorphic pointcut target(<supertype name>) && • does not further restrict the join points • does pick up the target object pointcut move(Figure. Element fig. Elt): target(fig. Elt) && (call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int))); after(Figure. Element fe): move(fe) { <fe is bound to the figure element> } 41 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

context & multiple classes Display. Updating v 3 aspect Display. Updating { pointcut move(Figure.

context & multiple classes Display. Updating v 3 aspect Display. Updating { pointcut move(Figure. Element fig. Elt): target(fig. Elt) && (call(void Figure. Element. move. By(int, int)) || call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int))); after(Figure. Element fe): move(fe) { Display. update(fe); } } 42 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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) { this. p 1 = p 1; } void set. P 2(Point p 2) { this. 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) { this. x = x; } void set. Y(int y) { this. y = y; 43 } } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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) { this. p 1 = p 1; Display. update(); } void set. P 2(Point p 2) { this. p 2 = p 2; Display. update(); } } class Point { private int x = 0, y= 0; int get. X() { return x; } int get. Y() { return y; } void set. X(int x) { this. x = x; } void set. Y(int y) { this. y = y; 44 } } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 Display. Updating v 1

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) { this. p 1 = p 1; Display. update(); } void set. P 2(Point p 2) { this. p 2 = p 2; Display. update(); } } class Point { private int x = 0, y = 0; int get. X() { return x; } int get. Y() { return y; } 45 void set. X(int x) { this. x = x; Display. update(); } void set. Y(int y) { this. y = y; Display. update(); } } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 Display. Updating v 2

without Aspect. J Display. Updating v 3 class Line { private Point p 1,

without Aspect. J Display. Updating v 3 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) { this. p 1 = p 1; Display. update(this); } void set. P 2(Point p 2) { this. p 2 = p 2; Display. update(this); } } class Point { private int x = 0, y = 0; int get. X() { return x; } int get. Y() { return y; } 46 • no locus of “display updating” void set. X(int x) { this. x = x; Display. update(this); } void set. Y(int y) { this. y = y; Display. update(this); } } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 – evolution is cumbersome – changes in all classes – have to track & change all callers

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) { this. p 1 = p 1; } void set. P 2(Point p 2) { this. 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) { this. x = x; } void set. Y(int y) { this. y = y; } } 47 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

with Aspect. J class Line { Display. Updating v 1 aspect Display. Updating {

with Aspect. J class Line { Display. Updating v 1 aspect Display. Updating { 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) { this. p 1 = p 1; } void set. P 2(Point p 2) { this. p 2 = p 2; } } pointcut move(): call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)); after() returning: move() { Display. update(); } } class Point { private int x = 0, y = 0; int get. X() { return x; } int get. Y() { return y; } void set. X(int x) { this. x = x; } void set. Y(int y) { this. y = y; } } 48 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

with Aspect. J class Line { Display. Updating v 2 aspect Display. Updating {

with Aspect. J class Line { Display. Updating v 2 aspect Display. Updating { 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) { this. p 1 = p 1; } void set. P 2(Point p 2) { this. p 2 = p 2; } } pointcut move(): call(void Figure. Element. move. By(int, int) || call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int)); after() returning: move() { Display. update(); } } class Point { private int x = 0, y = 0; int get. X() { return x; } int get. Y() { return y; } void set. X(int x) { this. x = x; } void set. Y(int y) { this. y = y; } } 49 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

with Aspect. J class Line { Display. Updating v 3 aspect Display. Updating {

with Aspect. J class Line { Display. Updating v 3 aspect Display. Updating { 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) { this. p 1 = p 1; } void set. P 2(Point p 2) { this. p 2 = p 2; } } class Point { pointcut move(Figure. Element fig. Elt): target(fig. Elt) && (call(void Figure. Element. move. By(int, int) || call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int))); after(Figure. Element fe) returning: move(fe) { movees. add(fe); } } private int x = 0, y = 0; int get. X() { return x; } int get. Y() { return y; } void set. X(int x) { this. x = x; } void set. Y(int y) { this. y = y; } } 50 • clear display updating module Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 – all changes in single aspect – evolution is modular

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 51 on arrival at join point gets explicit control over when&if program proceeds Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 52 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

pre-condition using before advice aspect Point. Bounds. Pre. Condition { before(int new. X): call(void

pre-condition using before advice aspect Point. Bounds. Pre. Condition { before(int new. X): call(void Point. set. X(int)) && args(new. X) { assert(new. X >= MIN_X); what follows the ‘: ’ is assert(new. X <= MAX_X); always a pointcut – } primitive or user-defined before(int new. Y): call(void Point. set. Y(int)) && args(new. Y) { assert(new. Y >= MIN_Y); assert(new. Y <= MAX_Y); } private void assert(boolean v) { if ( !v ) throw new Runtime. Exception(); } } 53 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

post-condition using after advice aspect Point. Bounds. Post. Condition { after(Point p, int new.

post-condition using after advice aspect Point. Bounds. Post. Condition { after(Point p, int new. X): call(void Point. set. X(int)) && target(p) && args(new. X) { assert(p. get. X() == new. X); } after(Point p, int new. Y): call(void Point. set. Y(int)) && target(p) && args(new. Y) { assert(p. get. Y() == new. Y); } private void assert(boolean v) { if ( !v ) throw new Runtime. Exception(); } } 54 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

condition enforcement using around advice aspect Point. Bounds. Enforcement { void around(Point p, int new. X): call(void Point. set. X(int)) && target(p) && args(new. X) { proceed(p, clip(new. X, MIN_X, MAX_X)); } void around(Point p, int new. Y): call(void Point. set. Y(int)) && target(p) && args(new. Y) { proceed(p, clip(new. Y, MIN_Y, MAX_Y)); } private int clip(int val, int min, int max) { return Math. max(min, Math. min(max, val)); } } 55 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

special static method <result type> proceed(arg 1, arg 2, …) available only in around advice means “run what would have run if this around advice had not been defined” 56 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

other primitive pointcuts this(<type name>) withincode(<method/constructor signature>) any join point at which currently executing

other primitive pointcuts this(<type name>) withincode(<method/constructor signature>) any join point at which currently executing object is an instance of type or class name currently executing code is contained within class name currently executing code is specified method or constructor get(int Point. x) set(int Point. x) field reference or assignment join points 57 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

fine-grained protection a runtime error class Figure { public Point make. Line(Line p 1,

fine-grained protection a runtime error class Figure { public Point make. Line(Line p 1, Line p 2) { new Line. . . } public Point make. Point(int x, int y) { new Point. . . } want to ensure that any creation of figure elements goes through the factory methods aspect Factory. Enforcement { pointcut illegal. New. Fig. Elt(): (call(Point. new(. . )) || call(Line. new(. . ))) && !withincode(* Figure. make*(. . )); before(): illegal. New. Fig. Elt() { throw new Error("Use factory method instead. "); } } 58 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

fine-grained protection a compile-time error class Figure { public Point make. Line(Line p 1,

fine-grained protection a compile-time error class Figure { public Point make. Line(Line p 1, Line p 2) { new Line. . . } public Point make. Point(int x, int y) { new Point. . . } want to ensure that any creation of figure elements goes through the factory methods aspect Factory. Enforcement { pointcut illegal. New. Fig. Elt(): (call(Point. new(. . )) || call(Line. new(. . ))) && !withincode(* Figure. make*(. . )); declare error: illegal. New. Fig. Elt() "Use factory method instead. "); } } 59 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 must be a “static pointcut” (more on this later)

fine-grained protection as a static inner class Line implements Figure. Element{ private Point p

fine-grained protection as a static inner 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) { this. p 1 = p 1; } void set. P 2(Point p 2) { this. p 2 = p 2; } void move. By(int dx, int dy) {. . . } static aspect Setter. Enforcement { declare error: set(Point Line. *) && !withincode(void Line. set. P*(Point)) "Use setter method, even inside Line class. "; } 60 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

wildcarding in pointcuts target(Point) target(graphics. geom. *) target(graphics. . *) 61 “*” is wild

wildcarding in pointcuts target(Point) target(graphics. geom. *) target(graphics. . *) 61 “*” is wild card “. . ” is multi-part wild card any type in graphics. geom any type in any sub-package of graphics call(void Point. set. X(int)) call(public * Point. *(. . )) call(public * *(. . )) any public method on Point any public method on any call(void Point. get. X()) call(void Point. get. Y()) call(void Point. get*()) call(void get*()) any getter call(Point. new(int, int)) call(new(. . )) any constructor Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

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-Oriented Programming with Aspect. J -- OOPSLA 2001

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

property-based crosscutting aspect Public. Error. Logging { Log log = new Log(); neatly captures public interface of mypackage pointcut public. Interface(): call(public * com. xerox. . *. *(. . )); 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-Oriented Programming with Aspect. J -- OOPSLA 2001

special value reflective* access to the join point this. Join. Point. Signature get. Signature()

special value reflective* access to the join point this. Join. Point. Signature get. Signature() Object[] get. Args(). . . available in any advice this. Join. Point is abbreviated to ‘tjp’ in these slides to save slide space * introspective subset of reflection consistent with Java 64 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

using this. Join. Point in highly polymorphic advice aspect Point. Coordinate. Tracing { before(Point

using this. Join. Point in highly polymorphic advice aspect Point. Coordinate. Tracing { before(Point p, int new. Val): set(int Point. *) && target(p) && args(new. Val) { System. out. println("At " + tjp. get. Signature() + " field is set to " + new. Val + ". "); } } using this. Join. Point makes it possible for the advice to recover information about where it is running 65 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

other primitive pointcuts execution(void Point. set. X(int)) method/constructor execution join points (actual running method)

other primitive pointcuts execution(void Point. set. X(int)) method/constructor execution join points (actual running method) initialization(Point) object initialization join points staticinitialization(Point) class initialization join points (as the class is loaded) 66 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

other primitive pointcuts cflow(pointcut designator) all join points within the dynamic control flow of any join pointcut designator cflowbelow(pointcut designator) all join points within the dynamic control flow below any join pointcut designator 67 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

context sensitive aspects Display. Updating v 4 aspect Display. Updating { pointcut move(Figure. Element

context sensitive aspects Display. Updating v 4 aspect Display. Updating { pointcut move(Figure. Element fig. Elt): target(fig. Elt) && the non-reentrant calls idiom: (call(void Figure. Element. move. By(int, int)) || call(void Line. set. P 1(Point)) || ptc && !cflowbelow(ptc) call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int))); pointcut top. Level. Move(Figure. Element fig. Elt): move(fig. Elt) && !cflowbelow(move(Figure. Element)); after(Figure. Element fe) returning: top. Level. Move(fe) { Display. update(fe); } } 68 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

wildcarding in pointcuts target(Point) target(graphics. geom. *) target(graphics. . *) 69 “*” is wild

wildcarding in pointcuts target(Point) target(graphics. geom. *) target(graphics. . *) 69 “*” is wild card “. . ” is multi-part wild card any type in graphics. geom any type in any sub-package of graphics call(void Point. set. X(int)) call(public * Point. *(. . )) call(public * *(. . )) any public method on Point any public method on any call(void Point. get. X()) call(void Point. get. Y()) call(void Point. get*()) call(void get*()) any getter call(Point. new(int, int)) call(new(. . )) any constructor Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

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 70 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

property-based crosscutting aspect Public. Error. Logging { Log log = new Log(); neatly captures public interface of mypackage pointcut public. Interface(): call(public * com. xerox. . *. *(. . )); 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 71 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

intra-type declarations 1 Display. Updating v 5 aspect Display. Updating { adds members to

intra-type declarations 1 Display. Updating v 5 aspect Display. Updating { adds members to target interface/class private Display Figure. Element. display; static void set. Display(Figure. Element fe, Display d) { fe. display = d; } pointcut move(Figure. Element fig. Elt): <as before>; after(Figure. Element fe): move(fe) { fe. display. update(fe); } } 1. recently termed “open classes” 72 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

field/getter/setter idiom aspect Display. Updating { private with respect to enclosing aspect declaration private

field/getter/setter idiom aspect Display. Updating { private with respect to enclosing aspect declaration private Display Figure. Element. display; static void set. Display(Figure. Element fe, Display d) { fe. display = d; } the display field – is a field of Figure. Element, but pointcut move(Figure. Element fig. Elt): <as before>; – belongs to Display. Updating aspect – Display. Updating aspect should provide getter/setter after(Figure. Element fe): move(fe) { fe. display. update(fe); } } 73 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

is this still a “GOF pattern”? aspect Display. Updating { private List Figure. Element.

is this still a “GOF pattern”? aspect Display. Updating { private List Figure. Element. observers = new Linked. List(); static void add. Display(Figure. Element fe, Display d) { fe. observers. add(d); } static void remove. Display(Figure. Element fe, Display d) { fe. observers. remove(d); } pointcut move(Figure. Element fig. Elt): <as before>; 74 after(Figure. Element fe): move(fe) { Iterator iter = fe. observers. iterator(); . . . } } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

another pattern aspect Mumble. RWSynchronization { pointcut readers(. . ): …; pointcut writers(. .

another pattern aspect Mumble. RWSynchronization { pointcut readers(. . ): …; pointcut writers(. . ): …; before(. . ): readers(. ) { before. Reader(. . ); } after (. . ): readers(. ) { after. Writer(. . ); } before(. . ): writers(. ) { before. Writer(. . ); } after (. . ): readers(. ) { after. Writer(. . ); } private before. Reader(. . ) { . . . } <other helper methods here> } 75 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 • move() 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 76 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

a shared pointcut public class Figure. Editor { . . . pointcut move(Figure. Element

a shared pointcut public class Figure. Editor { . . . pointcut move(Figure. Element fig. Elt): target(fig. Elt) &&. . . ; . . . } aspect Display. Updating { . . . after(Figure. Element fe) returning: Figure. Editor. move(fe) { . . . } 77 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

a reusable aspect abstract public aspect Remote. Exception. Logging { abstract pointcut log. Point(); abstract after() throwing (Remote. Exception e): log. Point() { log. println(“Remote call failed in: ” + this. Join. Point. to. String() + “(” + e + “). ”); } } public aspect My. RMILogging extends Remote. Exception. Logging { pointcut log. Point(): call(* Registry. Server. *. *(. . )) || call(private * RMIMessage. Broker. Impl. *. *(. . )); } 78 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

an aspect as a reusable pattern aspect RWSynchronization { abstract pointcut readers(. . ):

an aspect as a reusable pattern aspect RWSynchronization { abstract pointcut readers(. . ): …; abstract pointcut writers(. . ): …; before(. . ): readers(. ) { before. Reader(. . ); } after (. . ): readers(. ) { after. Writer(. . ); } before(. . ): writers(. ) { before. Writer(. . ); } after (. . ): readers(. ) { after. Writer(. . ); } <helper methods as before> } aspect Mumble. RWSynchronization extends RWSynchronization { abstract pointcut readers(. . ): …; abstract pointcut writers(. . ): …; 79 } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

aspect instances aspect Public. Error. Logging pertarget(Public. Error. Logging. public. Interface()) { Log log

aspect instances aspect Public. Error. Logging pertarget(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(): call(public * com. xerox. . *. *(. . )); after() throwing (Error e): public. Interface() { log. write(e); } 80 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 – for default aspects takes no argument – for aspects of pertarget/perthis takes an Object – for aspects of percflow takes no arguments • returns aspect instance 81 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

aspect relations pertarget(<pointcut>) perthis(<pointcut>) one aspect instance for each object that is ever “this” at the join points percflow(<pointcut>) percflowbelow(<pointcut>) one aspect instance for each join pointcut, is available at all joinpoints in cflow or cflowbelow 82 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 p 1 l 1 p 2 p 3 l 2

context sensitive aspects Display. Updating v 4 aspect Display. Updating { List movers =

context sensitive aspects Display. Updating v 4 aspect Display. Updating { List movers = new Linked. List(); List movees = new Linked. List(); // … pointcut move. Call(Object mover, Figure. Element movee): this(mover) && target(movee) && (call(void Line. set. P 1(Point)) || call(void Line. set. P 2(Point)) || call(void Point. set. X(int)) || call(void Point. set. Y(int))); after(Object mover, Figure. Element movee) returning: move. Call(mover, movee) { movers. add(mover); movees. add(movee); } } 83 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

summary join points method & constructor call execution field get set exception handler execution

summary join points method & constructor call execution field get set exception handler execution initialization aspects crosscutting type pertarget perthis percflowbelow 84 pointcuts -primitivecall execution handler get set initialization dispatch this target withincode cflowbelow -user-definedpointcut declaration abstract overriding static Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 advice before after around intra-type decls declare error

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 85 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Part III Aspect. J IDE support Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Part III Aspect. J IDE support Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

programming environment • AJDE support for – emacs, JBuilder, Forte • also jdb style

programming environment • AJDE support for – emacs, JBuilder, Forte • also jdb style debugger (ajdb) • and window-based debugger • • navigating Aspect. J code compiling tracking errors debugging • ajdoc 87 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Part IV Using Aspects Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Part IV Using Aspects Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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? 89 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

example 1 plug & play tracing • simple tracing – exposes join points and

example 1 plug & play tracing • simple tracing – exposes join points and uses very simple advice • an unpluggable aspect – core program functionality is unaffected by the aspect 90 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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); } 91 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-Oriented Programming with Aspect. J -- OOPSLA 2001

a clear crosscutting structure Trace. Support all modules of the system use the trace

a clear crosscutting structure Trace. Support all modules of the system use the trace facility in a consistent way: entering the methods and exiting the methods this line is about interacting with the trace facility 92 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

tracing as an aspect Point. Coord. Tracing { Trace. Support pointcut trace(): within(com. bigboxco.

tracing as an aspect Point. Coord. Tracing { Trace. Support pointcut trace(): within(com. bigboxco. boxes. *) && execution(* *(. . )); before(): trace() { Trace. Support. trace. Entry( this. Join. Point. get. Signature()); } after(): trace() { Trace. Support. trace. Exit( this. Join. Point. get. Signature()); } } 93 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

plug and debug • plug in: • unplug: ajc Point. java Line. java Trace.

plug and debug • plug in: • unplug: ajc Point. java Line. java Trace. Support. java Point. Tracing. java ajc Point. java Line. java • or… 94 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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"); 95 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 96 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

aspects in the design have these benefits • objects are no longer responsible for

aspects in the design have these benefits • objects are no longer responsible for using the trace facility – trace aspect encapsulates that responsibility, for appropriate objects • 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 97 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 98 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 99 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 • using an aspect captures the consistent usage of the tracing support by the objects Trace. Support

tracing exercises 1. Make a Tracing library aspect, and redefine Point. Tracing as extension

tracing exercises 1. Make a Tracing library aspect, and redefine Point. Tracing as extension of it. 2. The original after advice runs whether computation returned normally or threw an exception. Instead, define one advice for normal return, and a second for abrupt return that also prints the exception. 100 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 abstract aspect Tracing { // what goes here? } aspect Point. Tracing extends Tracing { // what goes here? } 101 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

discussion • what, at the design level, does each of these aspects implement? •

discussion • what, at the design level, does each of these aspects implement? • did you retain Trace. Support class? • what do you think of the names Tracing and Point. Tracing for these aspects? what did you name the abstract pointcut • can you combine the techniqes of OO frameworks with these aspects to make the Tracing aspect even more flexible? is it a good idea to do so? • … 102 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

example 2 103 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 roles/views

example 2 103 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 roles/views

Cloneable. Point aspect Cloneable. Point { declare parents: Point implements Cloneable; public Object Point.

Cloneable. Point aspect Cloneable. Point { declare parents: Point implements Cloneable; public Object Point. 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(); } } 104 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

roles/views exercise/discussion • 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? 105 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 * the bytes ever written to an Output. Stream. */ aspect Byte. Counting { int count = 0; int get. Count() { return count; } // // what goes here? // // } 106 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 { int count = 0; int get. Count() { return count; } } 107 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

counting bytes v 1 a first attempt aspect Byte. Counting { int count = 0; int get. Count() { return count; } after() returning: call(void Output. Stream. write(byte)) { count = count + 1; } after(byte[] bytes) returning: call(void Output. Stream. write(bytes)) { count = count + bytes. length; } } 108 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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) { … } } 109 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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] { b }; write(bs); } public void write(byte[] b) { … } } 110 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

counting bytes v 2 using cflowbelow for more robust counting aspect Byte. Counting { int count = 0; int get. Count() { return count; } pointcut write(): call(void Output. Stream. write(byte)) || call(void Output. Stream. write(byte[])); pointcut write. Cflow(): cflowbelow(write()); after() returning: !write. Cflow() && call(void Output. Stream. write(byte)) { count++; } after(byte[] bytes) returning: !write. Cflow() && call(void Output. Stream. write(bytes)) { count = count + bytes. length; } } 111 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

counting bytes v 3 per-stream counting aspect Byte. Counting { /* put declarations here

counting bytes v 3 per-stream counting aspect Byte. Counting { /* put declarations here that provide per-stream count state */ pointcut write(): call(void Output. Stream. write(byte)) || call(void Output. Stream. write(byte[])); /*. . . and show to properly increment the count state */ . . . count = count + 1; . . . count = count + bytes. length; } 112 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

counting bytes v 3 per-stream counting aspect Byte. Counting { /* put declarations here

counting bytes v 3 per-stream counting aspect Byte. Counting { /* put declarations here that provide per-stream count state */ private int Output. Stream. count = 0; static public int get. Count(Output. Stream os) { return os. count; } /* or ? ? ? */ public int Output. Stream. get. Count() { return count; } third party perspective: pointcut write(): call(void Output. Stream. write(byte)) || call(void Output. Stream. write(byte[])); s. get. Count(); Byte. Counting. get. Count(s); /*. . . and show to properly increment the count state */ . . . s. count = s. count + 1; . . . s. count = s. count + bytes. length; } 113 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

counting bytes exercises • How do the aspects change if the method void write(Collection

counting bytes exercises • How do the aspects change if the method void write(Collection c) is added to the Output. Stream interface? • How would you change v 2 to handle byte generators: interface Byte. Generator { int get. Length(); void generate. To(Output. Stream s); } 114 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 115 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 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 116 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 worker 2 worker 3

context-passing aspects pointcut invocations(Caller c): this(c) && call(void Service. do. Service(String)); 117 Aspect-Oriented Programming

context-passing aspects pointcut invocations(Caller c): this(c) && call(void Service. do. Service(String)); 117 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

context-passing aspects pointcut invocations(Caller c): this(c) && call(void Service. do. Service(String)); pointcut work. Points(Worker w): target(w) && call(void Worker. do. Task(Task)); 118 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

context-passing aspects pointcut invocations(Caller c): this(c) && call(void Service. do. Service(String)); pointcut work. Points(Worker w): target(w) && call(void Worker. do. Task(Task)); pointcut per. Caller. Work(Caller c, Worker w): cflow(invocations(c)) && work. Points(w); 119 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

context-passing aspects abstract aspect Capability. Checking { pointcut invocations(Caller c): this(c) && call(void Service. do. Service(String)); pointcut work. Points(Worker w): target(w) && call(void Worker. 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); } } 120 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

example 5 interface Forest { int how. Many. Trees(); int how. Many. Birds(); .

example 5 interface Forest { int how. Many. Trees(); int how. Many. Birds(); . . . } pointcut forest. Call(): call(* Forest. *(. . )); before(): forest. Call(): { } 121 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 properties of interfaces

example n 1 • points – with location and color • a screen –

example n 1 • points – with location and color • a screen – that monitors location changes – that monitors color changes – that monitors screen changes 122 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

observe set. X, set. Y Display println(String) update. Status(String) Point set. X(int) set. Y(int)

observe set. X, set. Y Display println(String) update. Status(String) Point set. X(int) set. Y(int) set. Color(Color) 123 observe set. Color Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 observe println

<point 12> moved <point 28> changed color observe set. X, set. Y Point set.

<point 12> moved <point 28> changed color observe set. X, set. Y Point set. X(int) set. Y(int) set. Color(Color) observe set. Color <point 12> movedobserve <point 28> changed color println last change: 14: 02: 29 124 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise complete the code aspect Coordinate. Observing { Hash. Map per. Point. Observers =

exercise complete the code aspect Coordinate. Observing { Hash. Map per. Point. Observers = new Weak. Hash. Map(); static void add. Observer(Point p, Display d) {. . . } static void remove. Observer(Point p, Display d) {. . . } Iterator get. Observers(Point p) {. . . } pointcut change(): (call(void Point. set. X(int)) || call(void Point. set. Y(int))) && target(p); after(Point p) returning: change() { // iterate for each display in observers… update(p, d); } void update(Point p, Display d) { d. println(“Point “ + p + “has moved” …); } } 125 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise complete the code aspect Coordinate. Observing { Hash. Map per. Point. Observers =

exercise complete the code aspect Coordinate. Observing { Hash. Map per. Point. Observers = new Weak. Hash. Map(); static void add. Observer(Point p, Display d) {. . . } static void remove. Observer(Point p, Display d) {. . . } Iterator get. Observers(Point p) {. . . } pointcut change(): (call(void Point. set. X(int)) || call(void Point. set. Y(int))) && target(p); after(Point p) returning: change() { // iterate for each display in observers… update(p, d); } void update(Point p, Display d) { d. println(“Point “ + p + “has moved” …); } } 126 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise complete the code aspect Observing { Hash. Map per. Point. Observers = new

exercise complete the code aspect Observing { Hash. Map per. Point. Observers = new Weak. Hash. Map(); static void add. Observer(Object p, Object d) {. . . } static void remove. Observer(Point p, Display d) {. . . } Iterator get. Observers(Point p) {. . . } abstract pointcut change(); after(Point p) returning: change() { // iterate for each display in observers… update(p, d); } abstract void update(Point p, Display d); } } 127 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise complete the code aspect Color. Observing { Display d; // assume this is

exercise complete the code aspect Color. Observing { Display d; // assume this is set up for you } 128 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise complete the code for Display. XXX aspect Display. Observing { Display d; //

exercise complete the code for Display. XXX aspect Display. Observing { Display d; // assume this is set up for you } 129 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise abstract these into a reusable aspect Observing { } 130 Aspect-Oriented Programming with

exercise abstract these into a reusable aspect Observing { } 130 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise abstract these into a reusable aspect abstract aspect Observing { private Weak. Hash.

exercise abstract these into a reusable aspect abstract aspect Observing { private Weak. Hash. Map per. Subject. Observers = new Weak. Hash. Map(); private Collection get. Observers(Subject s) { Collection observers = (Collection)per. Subject. Observers. get(s); if ( observers == null ) { observers = new Linked. List(); per. Subject. Observers. put(s, observers); } return observers; } protected interface Subject { } protected interface Observer { } public void add. Observer(Subject s, Observer o) { get. Observers(s). add(o); } public void remove. Observer(Subject s, Observer o) { get. Observers(s). remove(o); } abstract pointcut change(); after(Subject s): change() { Iterator iter = get. Observers(s). iterator (); while ( iter. has. Next() ) { update. Observer(s, ((Observer)iter. next())); } } abstract void update. Observer(Subject s, Observer o); } 131 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise abstract these into a reusable aspect public aspect Color. Observing extends Observing {

exercise abstract these into a reusable aspect public aspect Color. Observing extends Observing { declare parents: Point implements Subject; declare parents: Screen implements Observer; pointcut changes(Subject s): call(void Point. set. Color(Color)) && target(s); void update. Observer(Subject s, Observer o) { ((Screen)o). display("Screen updated because color changed. "); } } 132 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise abstract these into a reusable aspect public aspect Coordinate. Observing extends Observing {

exercise abstract these into a reusable aspect public aspect Coordinate. Observing extends Observing { declare parents: Point implements Subject; declare parents: Screen implements Observer; pointcut changes(Subject s): (call(void Point. set. X(int)) || call(void Point. set. Y(int)) ) && target(s); void update. Observer(Subject s, Observer o) { ((Screen)o). display("Screen updated because coordinates changed. "); } } 133 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise abstract these into a reusable aspect public aspect Screen. Observing extends Observing {

exercise abstract these into a reusable aspect public aspect Screen. Observing extends Observing { declare parents: Screen implements Subject; declare parents: Screen implements Observer; pointcut changes(Subject s): call(void Screen. display(String)) && target(s); void update. Observer(Subject s, Observer o) { ((Screen)o). display("Screen updated because screen displayed. "); } } 134 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

aspects on interfaces a first attempt aspect Forestry { pointcut forest. Call(): call(* Forest.

aspects on interfaces a first attempt aspect Forestry { pointcut forest. Call(): call(* Forest. *(. . )); before(): forest. Call() { System. out. println(tjp. get. Signature() + " is a Forest-Method. "); } } 135 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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; } } • 136 interface Forest includes methods from Object, such as to. String() Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

aspects on interfaces adding constraints aspect Forestry { pointcut forest. Call(): call(* Forest. *(.

aspects on interfaces adding constraints aspect Forestry { pointcut forest. Call(): call(* Forest. *(. . )) && !call(* Object. *(. . )); before(): forest. Call() { System. out. println(this. Join. Point. method. Name + " is a Forest-method. "); } } 137 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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? 138 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

example 6 139 RMI exception aspects client reactions to failures: - abort - try

example 6 139 RMI exception aspects client reactions to failures: - abort - try another server Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

a Time. Server design 140 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

a Time. Server design 140 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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"; } 141 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 */ public Date get. Time() throws Remote. Exception {return new Date(); } public String get. Name() throws Remote. Exception {return to. String(); } /** * Make a new server object and register it */ public static void main(String[] args) { Time. Server ts = new Time. Server(); Naming. bind(Time. Service. name. Base, ts); } /** * Exception pointcuts. Code is not complete without advice on them. */ pointcut create(): within(Time. Server) && call(Time. Server. new()); no exception catching here, but notice pointcut bind(): within(Time. Server) && call(void Naming. bind(String, . . )); pointcut bind. Name(String name): args(name, . . ) && bind(); } 142 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Abort. My. Server aspect Abort. My. Server { Time. Server around(): Time. Server. create()

Abort. My. Server aspect Abort. My. Server { Time. Server around(): Time. Server. create() { Time. Server result = null; try { result = proceed(); } catch (Remote. Exception e){ System. out. println("Time. Server err: " + e. get. Message()); System. exit(2); } return result; } declare soft: Remote. Exception: Time. Server. create(); void around(String name): Time. Server. bind. Name(name) { try { proceed(name); System. out. println("Time. Server: bound name. "); } catch (Exception e) { System. err. println("Time. Server: error " + e); System. exit(1); } } declare soft: Exception: Time. Server. bind(); } 143 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Retry. My. Server aspect Retry. My. Server { Time. Server around(): Time. Server. create()

Retry. My. Server aspect Retry. My. Server { Time. Server around(): Time. Server. create() { Time. Server result = null; try { result = proceed(); } catch (Remote. Exception e){ System. out. println("Time. Server error. "); e. print. Stack. Trace(); } return result; } declare soft: Remote. Exception: Time. Server. create(); void around(String name): Time. Server. bind. Name(name) { for (int tries = 0; tries < 3; tries++) { try { proceed(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); } declare soft: Exception: Time. Server. bind(); } 144 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 is not complete without advice on them. */ pointcut setup(): call(Remote Naming. lookup(. . )); pointcut setup. Client(Client c): this(c) && setup(); pointcut serve(): call(* Time. Service. *(. . )); pointcut serve. Client(Client c, Time. Service ts): this(c) && target(ts) && serve(); 145 … other methods … } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

Abort. My. Client aspect Abort. My. Client { Remote around(Client c): Client. setup. Client(c) { Remote result = null; try { result = proceed(c); } catch (Exception e) { System. out. println("Client: No server. Aborting. "); System. exit(0); } return result; } declare soft: Exception: Client. setup(); 146 Object around(Client c, Time. Service ts): Client. serve. Client(c, ts) { Object result = null; try { result = proceed(c, ts); } catch (Remote. Exception e) { System. out. println("Client: Remote Exception. Aborting. "); System. exit(0); } return result; } declare soft: Remote. Exception: Client. serve(); } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

Retry. My. Client aspect Retry. My. Client { Remote around(Client c): Client. setup. Client(c) { Remote result = null; try { result = proceed(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; } declare soft: Exception: Client. setup(); 147 Object around(Client c, Time. Service ts): Client. serve. Client(c, ts) { try { return proceed(c, ts); } catch (Remote. Exception e) { c. server = find. New. Server(Time. Service. name. Base , c. server, 3); if (c. server == null) System. exit(1); /* No server found */ try { return proceed(c, c. server); } catch (Remote. Exception e 2) { System. exit(2); } return null; } } declare soft: Remote. Exception: Client. serve(); static Time. Service find. New. Server(String base. Name, Object current. Server, int nservers) { … } } Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 148 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 149 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

exercise aspect Use. Local. Client { Object around(Client c, Time. Service ts): Client. serve.

exercise aspect Use. Local. Client { Object around(Client c, Time. Service ts): Client. serve. Client(c, ts) { Object result = null; try { result = proceed(c, ts); } catch (Remote. Exception e) { c. s = new Time. Server(); proceed(c, s); } return result; } declare soft: Remote. Exception: Client. serve(); } 150 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 –. . . 151 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

telecom basic design Customer Call start. Call(Customer) void pickup. Call(Call) void merge. Calls(Call, Call) void 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 152 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 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 153 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 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 154 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 connection made: start timing connection dropped: stop timing Long. Distance

timing additional design elements long get. Time() 0. . N Customer 1 Timer void

timing additional design elements long get. Time() 0. . N Customer 1 Timer void stop() void start() long get. Time() invoke when connection drops set and invoke upon new connection 1 1 0. . N caller receiver Connection Local 155 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 Call Long. Distance

timing exercise • Write an aspect representing the timing protocol. 156 Aspect-Oriented Programming with

timing exercise • Write an aspect representing the timing protocol. 156 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 157 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

timing an aspect implementation aspect Timing { private Timer Connection. timer = new Timer();

timing an aspect implementation aspect Timing { private Timer Connection. timer = new Timer(); private long Customer. total. Connect. Time = 0; public static long get. Total. Connect. Time(Customer c) { return c. total. Connect. Time; } pointcut start. Timing(Connection c): target(c) && call(void c. complete()); pointcut end. Timing(Connection c): target(c) && call(void c. drop()); after(Connection c): start. Timing(c) { c. timer. start(); } after(Connection c): end. Timing(c) { Timer timer = c. timer; timer. stop(); long curr. Time = timer. get. Time(); c. get. Caller(). total. Connect. Time += curr. Time; c. get. Receiver(). total. Connect. Time += curr. Time; } } 158 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 159 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 160 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 161 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 162 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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? 163 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 164 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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

consistency checking Customer Call start. Call(Customer) void pickup. Call(Call) void merge. Calls(Call, Call) void 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 165 Long. Distance Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 List of Calls List of Connections check at the end of simulation

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

consistency checking aspect Consistency. Checker { Vector calls = new Vector(), connections = new Vector(); /* The lifecycle of calls */ after(Call c): target(c) && call(Call. new(. . )) { calls. add. Element(c); } after(Call c): target(c) && call(* Call. hangup(. . )) { calls. remove. Element(c); } after(Call other): args(other) && (void Call. merge(Call)) { calls. remove. Element(other ); } /* The lifecycle of connections */ after(Connection c): target(c) && call(Connection. new(. . )) { connections. add. Element(c ); } after(Connection c): target(c) && call(* Connection. drop(. . )) { connections. remove. Element(c ); } 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. "); } } 166 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 167 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 168 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

… 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 169 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

… 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 170 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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. 171 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001 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 172 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Part V References, Related Work Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Part V References, Related Work Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

AOP and Aspect. J on the web • aspectj. org • aosd. net (www.

AOP and Aspect. J on the web • aspectj. org • aosd. net (www. parc. xerox. com/aop) 174 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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/ • ECOOP’ 01 175 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

growing interest in separation of crosscutting concerns • see workshop proceedings • upcoming AOSD

growing interest in separation of crosscutting concerns • see workshop proceedings • upcoming AOSD conference 176 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 177 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 178 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 179 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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 (1. 0 b 1 is current) – tools • IDE extensions: Emacs, JBuilder 3. 5, JBuilder 4, 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 – Feb 2001: 600 downloads/mo, 600 members on users list 180 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

Aspect. J future continue building language, compiler & tools • 1. 0 – compilation

Aspect. J future continue building language, compiler & tools • 1. 0 – compilation direct to bytecodes • 1. 1 – incremental compiler • 1. 2 – source of target classes not required? • 2. 0 – new dynamic crosscut constructs commercialization decision after 1. 0 181 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001

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, Wes Isberg, Vladimir Ivanovic, 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 182 Aspect-Oriented Programming with Aspect. J -- OOPSLA 2001