Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
Everything is About Good Code Architecture ! SEAS : Part III Programing models, tools and techniques with one shared goal : ! ! Aspect-Oriented Programming AspectJ ! ! Vania Marangozova, [email protected] (kindly replacing Sara Bouchenak, [email protected]) © S. Bouchenak ! ! Produce a well-organized code Easy to debug Easy to maintain Easy to evolve Separation of concerns Good modularity AOP - AspectJ © S. Bouchenak, V.Marangozova XML Parsing About Good Modularity ! red shows the code we are interested in ! all the code is in one module (class) " © S. Bouchenak, V.Marangozova AOP - AspectJ 2 URL Pattern Recognition About Good Modularity Parsing XML in org.apache.tomcat ! AOP - AspectJ ! URL pattern recognition in org.apache.tomcat ! 3 the code we are interested in is in two classes " © S. Bouchenak, V.Marangozova AOP - AspectJ 4 Non Modular Tracing Problems Sess on Term nat on Problems ApplicationSession /* * ==================================================================== * * 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 dérive * from this software without prior written permission. For written * permission, please contact [email protected]. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */ public void invalidate() { serverSession.removeApplicationSession(context); // remove everything in the session Enumeration enum = values.keys(); while (enum.hasMoreElements()) { String name = (String)enum.nextElement(); removeValue(name); } valid = false; } public boolean isNew() { if (! valid) { String msg = sm.getString("applicationSession.session.ise"); } if (thisAccessTime == creationTime) { return true; } else { return false; } } /** * @deprecated */ public void putValue(String name, Object value) { setAttribute(name, value); } public void setAttribute(String name, Object value) { if (! valid) { String msg = sm.getString("applicationSession.session.ise"); } } } } String[] valueNames = new String[names.size()]; names.copyInto(valueNames); public Enumeration getAttributeNames() { if (! valid) { String msg = sm.getString("applicationSession.session.ise"); } return (Enumeration)valuesClone.keys(); } /** * The session identifier of this Session. */ private String id = null; throw new IllegalArgumentException(msg); if (o instanceof HttpSessionBindingListener) { HttpSessionBindingEvent e = new HttpSessionBindingEvent(this,name); } } public long getCreationTime() { if (valid) { return creationTime; } else { String msg = sm.getString("applicationSession.session.ise"); ((HttpSessionBindingListener)o).valueUnbound(e); values.remove(name); public void setMaxInactiveInterval(int interval) { if (! valid) { String msg = sm.getString("applicationSession.session.ise"); } throw new IllegalStateException(msg); } /** * * @deprecated */ throw new IllegalStateException(msg); inactiveInterval = interval; public int getMaxInactiveInterval() { if (! valid) { String msg = sm.getString("applicationSession.session.ise"); public HttpSessionContext getSessionContext() { return new SessionContextImpl(); } } } } /** * Flag indicating whether this session is new or */ private boolean isNew = true; throw new IllegalStateException(msg); if (name == null) { String msg = sm.getString("applicationSession.value.iae"); Object o = values.get(name); throw new IllegalStateException(msg); return inactiveInterval; //----------------------------------------------------------------------- throw new IllegalStateException(msg); /** * Flag indicating whether this session is valid or not. */ private boolean isValid = false; return (this.isValid); } // ----------------------------------------------------Session Properties /** * Set the creation time for this session. This method is called by the * Manager when an existing Session instance is reused. * * @param time The new creation time */ public void setCreationTime(long time) { this.creationTime = time; this.lastAccessedTime = time; this.thisAccessedTime = time; } } /** * Set the <code>isValid</code> flag for this session. * * @param isValid The new value for the <code>isValid</code> this.isValid = isValid; /** * Return the time when this session was created, in milliseconds since * midnight, January 1, 1970 GMT. * * @exception IllegalStateException if this method is called * invalidated session */ public long getCreationTime() { /** * Return the session context with which this session is associated. * * @deprecated As of Version 2.1, this method is deprecated and has no * replacement. It will be removed in a future version of the * Java Servlet API. */ public HttpSessionContext getSessionContext() { // ----------------------------------------------HttpSession 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 IllegalStateException if this method is called on an * invalidated session */ public Object getAttribute(String name) { // Accumulate the names of serializable attributes Vector results = new Vector(); Enumeration attrs = getAttributeNames(); while (attrs.hasMoreElements()) { String attr = (String) attrs.nextElement(); Object value = attributes.get(attr); if (value instanceof Serializable) results.addElement(attr); } return (attributes.get(name)); /** * Return the session identifier for this session. */ public String getId() { return (this.id); } /** * Set the session identifier for this session. * * @param id The new session identifier */ public void setId(String id) { if ((this.id != null) && (manager != null) && (manager instanceof ManagerBase)) ((ManagerBase) manager).remove(this); this.id = id; if ((manager != null) && (manager instanceof ManagerBase)) ((ManagerBase) manager).add(this); } /** * Return descriptive information about this Session implementation and * the corresponding version number, in the format * <code><description>/<version></ code>. */ public String getInfo() { return (this.info); } /** * Return the last time the client sent a request associated with this * session, as the number of milliseconds since midnight, January 1, 1970 * GMT. Actions that your application takes, such as getting or setting * a value associated with the session, do not affect the access time. */ public long getLastAccessedTime() { } /** * Return an <code>Enumeration</code> of <code>String</code> objects * containing the names of the objects bound to this session. * * @exception IllegalStateException if this method is called on an * invalidated session */ public Enumeration getAttributeNames() { // Serialize the attribute count and the attribute values stream.writeObject(new Integer(results.size())); Enumeration names = results.elements(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); stream.writeObject(name); stream.writeObject(attributes.get(name)); } return (attributes.keys()); } /** * 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 IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * <code>getAttribute()</code> */ public Object getValue(String name) { } return (this.lastAccessedTime); /** * This class is a dummy implementation of the <code>HttpSessionContext</code> * interface, to conform to the requirement that such an object be returned * when <code>HttpSession.getSessionContext()</code> is called. * * @author Craig R. McClanahan * * @deprecated As of Java Servlet API 2.1 with no replacement. The * interface will be removed in a future version of this API. */ on final class StandardSessionContext implements HttpSessionContext { ! Tracing in org.apache.tomcat ! ! ! red lines are not in one module are almost everywhere © S. Bouchenak, V.Marangozova return (this.manager); } this.manager = manager; } while (enum.hasMoreElements()) { Object key = enum.nextElement(); ServerSession session = (ServerSession)sessions.get(key); } synchronized void removeSess } session.reap(); session.validate(); private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); private static ServerSessionManager manager; // = new ServerSessionManager(); return (dummy.elements()); * an invalidated session */ public void invalidate() { } /** * 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 IllegalStateException if this method is called on an * invalidated session */ public boolean isNew() { /** * Start the background thread that will periodically check for * session timeouts. */ private void threadStart() { * * @param ctx The context that is being shut down */ public void removeSessions(Context ctx) { // XXX XXX a manager may be shared by multiple // contexts, we just want to remove the sessions of ctx! // The manager will still run after that ( i.e. keep database // connection open if (manager instanceof Lifecycle) { try { ((Lifecycle) manager).stop(); } catch (LifecycleException e) { throw new IllegalStateException("" + e); } } } /** * Used by context to configure the session manager's inactivity timeout. * * The SessionManager may have some default session time out, the * Context on the other hand has it's timeout set by the deployment * descriptor (web.xml). This method lets the Context conforgure the * session manager according to this value. * * @param minutes The session inactivity timeout in minutes. */ public void setSessionTimeOut(int minutes) { if(-1 != minutes) { // The manager works with seconds... } } manager.setMaxInactiveInterval(minutes * 60); } if (thread != null) return; /** * Stop the background thread that is periodically checking for * session timeouts. */ private void threadStop() { if (thread == null) return; threadDone = true; thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { ; } thread = null; } // ------------------------------------------------------ Background Thread public void accessed( Context ctx, Request req, String id ) { ApplicationSession apS=(ApplicationSession)findSession( ctx, id); if( apS==null) return; /** * The background thread that checks for session timeouts and shutdown. */ public void run() { ServerSession servS=apS.getServerSession(); servS.accessed(); apS.accessed(); // Loop until the termination semaphore is set while (!threadDone) { threadSleep(); processExpires(); // cache it - no need to compute it again req.setSession( apS ); if(-1 != inactiveInterval) { session.setMaxInactiveInterval(inactiveInterval); public HttpSession createSession(Context ctx) { return manager.createSession().getSession(); } * The Manager implementation we are actually using. */ private Manager manager = null; } } public HttpSession createSession(Context ctx) { String sessionId = SessionIdGenerator.generateId(); ServerSession session = new ServerSession(sessionId); sessions.put(sessionId, session); } } } /** threadDone = false; thread = new Thread(this, threadName); thread.setDaemon(true); thread.start(); if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) throw new IllegalStateException (sm.getString("standardManager.createSession.ise")); return (super.createSession()); } private Hashtable sessions = new Hashtable(); private Reaper reaper; private ServerSessionManager() { reaper = Reaper.getReaper(); reaper.setServerSessionManager(this); reaper.start(); } } /** * Return the <code>HttpSession</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 HttpSession getSession(String id) { } } public static ServerSessionManager getManager() { return manager; } } catch (LifecycleException e) { throw new IllegalStateException("" + e); } } /** // ----------------------------------------------------- Instance * Remove all sessions because our associated Context is being shut Variables down. try { Thread.sleep(checkInterval * 1000L); } catch (InterruptedException e) { ; } // --------------------------------------------------------- Public Methods } 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 getIds() { * * @exception IllegalStateException if this method is called // Cause this session to expire expire(); /** * Set the Manager within which this Session is valid. * * @param manager The new Manager */ public void setManager(Manager manager) { synchronized void reap() { Enumeration enum = sessions.keys(); public class ServerSessionManager implements SessionManager { Session session = manager.findSession(id); if(session!=null) return session.getSession(); } catch (IOException e) { } return (null); /** * Sleep for the duration specified by the <code>checkInterval</code> * property. */ private void threadSleep() { this.maxActiveSessions = max; /** * * @author James Duncan Davidson [[email protected]] * @author Jason Hunter [[email protected]] * @author James Todd [[email protected]] */ // cache the HttpSession - avoid another find req.setSession( session ); ((Lifecycle) manager).configure(null); ((Lifecycle) manager).start(); for (int i = 0; i < sessions.length; i++) { StandardSession session = (StandardSession) sessions[i]; if (!session.isValid()) continue; int maxInactiveInterval = session.getMaxInactiveInterval(); if (maxInactiveInterval < 0) continue; int timeIdle = // Truncate, do not round up (int) ((timeNow - session.getLastAccessedTime()) / 1000L); if (timeIdle >= maxInactiveInterval) session.expire(); } /** * 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 getId() * method of the returned session. If a new session cannot be created * for any reason, return <code>null</code>. * * @exception IllegalStateException if a new session cannot be * instantiated for any reason */ public Session createSession() { } // -------------------------------------------------------------- Private Class /** * Invalidates this session and unbinds any objects bound to } /** * Set the maximum number of actives Sessions allowed, or -1 for * no limit. * * @param max The new maximum number of sessions */ public void setMaxActiveSessions(int max) { static { manager = new ServerSessionManager(); } } return (this.maxActiveSessions); } This should be HttpSession session=findSession(ctx, id); if( session == null) return; if (session instanceof Session) ((Session) session).access(); // XXX should we throw exception or just return null ?? public HttpSession findSession( Context ctx, String id ) { try { manager = new StandardManager(); if (manager instanceof Lifecycle) { try { long timeNow = System.currentTimeMillis(); Session sessions[] = findSessions(); } protected int inactiveInterval = -1; Vector results = new Vector(); Enumeration attrs = getAttributeNames(); while (attrs.hasMoreElements()) { String attr = (String) attrs.nextElement(); results.addElement(attr); } String names[] = new String[results.size()]; for (int i = 0; i < names.length; i++) names[i] = (String) results.elementAt(i); return (names); * Mark the specified session's last accessed time. * called for each request by a RequestInterceptor. * * @param session The session to be marked */ public void accessed(Context ctx, Request req, String id) { */ public StandardSessionManager() { /** * Invalidate all sessions that have expired. */ private void processExpires() { return (this.info); // XXX // sync'd for safty -- no other thread should be getting something // from this while we are reaping. This isn't the most optimal // solution for this, but we'll determine something else later. /** * * @author Craig R. McClanahan */ public final class StandardSessionManager implements SessionManager { // ----------------------------------------------------------Constructors // -------------------------------------------------------- Private Methods /** * Return the maximum number of active Sessions allowed, or -1 for * no limit. */ public int getMaxActiveSessions() { ServerSessionManager * processing semantics of handling sessions. * <p> * XXX - At present, there is no way (via the SessionManager interface) for * 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. } } package org.apache.tomcat.session; static advice(StandardSession s): invalidate(s) { before { if (!s.isValid()) throw new IllegalStateException (s.sm.getString("standardSession." + thisJoinPoint.methodName + ".ise")); } return (getAttribute(name)); } /** * Return the Manager within which this Session is valid. */ public Manager getManager() { this.checkInterval = checkInterval; import org.apache.tomcat.util.*; import org.apache.tomcat.core.*; import java.io.*; import java.net.*; import java.util.*; import javax.servlet.http.*; * and lifecycle configuration is not supported. * <p> * <b>IMPLEMENTATION NOTE</b>: Once we commit to the new Manager/Session * paradigm, I would suggest moving the logic implemented here back into * the core level. The Tomcat.Next "Manager" interface acts more like a * collection class, and has minimal knowledge of the detailed request // Expire all active sessions Session sessions[] = findSessions(); for (int i = 0; i < sessions.length; i++) { StandardSession session = (StandardSession) sessions[i]; if (!session.isValid()) continue; session.expire(); /** * Return descriptive information about this Manager implementation and * the corresponding version number, in the format * <code><description>/<version></code>. */ public String getInfo() { crosscut invalidate(StandardSession s): s & (int getMaxInactiveInterval() | long getCreationTime() | Object getAttribute(String) | Enumeration getAttributeNames() | String[] getValueNames() | void invalidate() | boolean isNew() | void removeAttribute(String) | void setAttribute(String, Object)); * Specialized implementation of org.apache.tomcat.core.SessionManager * that adapts to the new component-based Manager implementation. * <p> * XXX - At present, use of <code>StandardManager</code> is hard coded, } } } } /** * Return the set of names of objects bound to this session. If there * are no such objects, a zero-length array is returned. * * @exception IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * <code>getAttributeNames()</code> */ public String[] getValueNames() { it. } // Write the scalar instance variables (except Manager) stream.writeObject(new Long(creationTime)); stream.writeObject(id); stream.writeObject(new Long(lastAccessedTime)); stream.writeObject(new Integer(maxInactiveInterval)); stream.writeObject(new Boolean(isNew)); stream.writeObject(new Boolean(isValid)); /** // Stop the background reaper thread threadStop(); /** * Set the check interval (in seconds) for this Manager. * * @param checkInterval The new check interval */ public void setCheckInterval(int checkInterval) { /** * 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>readObject()</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 writeObject(ObjectOutputStream stream) throws IOException { // --------------------------------------------------------- Public Methods import javax.servlet.http.HttpSession; import org.apache.tomcat.catalina.*; import org.apache.tomcat.core.Context; import org.apache.tomcat.core.Request; import org.apache.tomcat.core.Response; import org.apache.tomcat.core.SessionManager; import org.apache.tomcat.util.SessionUtil; // Validate and update our current component state if (!started) throw new LifecycleException (sm.getString("standardManager.notStarted")); started = false; return (this.checkInterval); } if (sessionContext == null) sessionContext = new StandardSessionContext(); return (sessionContext); /** * 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 IllegalStateException if this component has not been started * @exception IllegalStateException if this component has already * been stopped * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ public void stop() throws LifecycleException { /** * Return the check interval (in seconds) for this Manager. */ public int getCheckInterval() { } } // Start the background reaper thread threadStart(); } /** * Name to register for the background thread. */ private String threadName = "StandardManager"; // ------------------------------------------------------------- Properties // Deserialize the attribute count and attribute values int n = ((Integer) stream.readObject()).intValue(); for (int i = 0; i < n; i++) { String name = (String) stream.readObject(); Object value = (Object) stream.readObject(); attributes.put(name, value); return (this.creationTime); } package org.apache.tomcat.session; import java.io.IOException; import javax.servlet.http.Cookie; * Create a new SessionManager that adapts to the corresponding Manager } * implementation. // Validate and update our current component state if (!configured) throw new LifecycleException (sm.getString("standardManager.notConfigured")); if (started) throw new LifecycleException (sm.getString("standardManager.alreadyStarted")); started = true; /** * The background thread. */ private Thread thread = null; /** * The background thread completion semaphore. */ private boolean threadDone = false; // Deserialize the scalar instance variables (except Manager) creationTime = ((Long) stream.readObject()).longValue(); id = (String) stream.readObject(); lastAccessedTime = ((Long) stream.readObject()).longValue(); maxInactiveInterval = ((Integer) stream.readObject()).intValue(); isNew = ((Boolean) stream.readObject()).booleanValue(); isValid = ((Boolean) stream.readObject()).booleanValue(); on an StandardSessionManager /** * 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 IllegalStateException if this component has not yet been * configured (if required for this component) * @exception IllegalStateException if this component has already been * started * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ public void start() throws LifecycleException { /** * Has this component been started yet? */ private boolean started = false; // -------------------------------------------- HttpSession Private Methods /** * Read a serialized version of this session object from the specified * object input stream. * <p> * <b>IMPLEMENTATION NOTE</b>: The reference to the owning Manager * is not restored by this method, and must be set explicitly. * * @param stream The input stream to read from * * @exception ClassNotFoundException if an unknown class is specified * @exception IOException if an input/output error occurs */ private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { */ void setValid(boolean isValid) { } // ------------------------------------------------HttpSession Properties node = attributes.getNamedItem("maxInactiveInterval"); if (node != null) { try { setMaxInactiveInterval(Integer.parseInt(node.getNodeValue())); } catch (Throwable t) { ; // XXX - Throw exception? } } /** /** * The string manager for this package. */ private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); } flag node = attributes.getNamedItem("maxActiveSessions"); if (node != null) { try { setMaxActiveSessions(Integer.parseInt(node.getNodeValue())); } catch (Throwable t) { ; // XXX - Throw exception? } } } /** * The descriptive information about this implementation. */ private static final String info = "StandardManager/1.0"; /** * The maximum number of active Sessions allowed, or -1 for no limit. */ protected int maxActiveSessions = -1; synchronized (attributes) { removeAttribute(name); attributes.put(name, value); if (value instanceof HttpSessionBindingListener) ((HttpSessionBindingListener) value).valueBound (new HttpSessionBindingEvent((HttpSession) this, name)); this.isNew = isNew; node = attributes.getNamedItem("checkInterval"); if (node != null) { try { setCheckInterval(Integer.parseInt(node.getNodeValue())); } catch (Throwable t) { ; // XXX - Throw exception? } } /** * The interval (in seconds) between checks for expired sessions. */ private int checkInterval = 60; /** * Has this component been configured yet? */ private boolean configured = false; if ((manager != null) && manager.getDistributable() && !(value instanceof Serializable)) throw new IllegalArgumentException (sm.getString("standardSession.setAttribute.iae")); /** * Set the <code>isNew</code> flag for this session. * * @param isNew The new value for the <code>isNew</code> flag */ void setNew(boolean isNew) { // Parse and process our configuration parameters if (!("Manager".equals(parameters.getNodeName()))) return; NamedNodeMap attributes = parameters.getAttributes(); Node node = null; // ----------------------------------------------------- Instance Variables /** * 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>HttpSessionBindingListener</code>, the container calls * <code>valueBound()</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 IllegalArgumentException if an attempt is made to add a * non-serializable object in an environment marked distributable. * @exception IllegalStateException if this method is called on an * invalidated session */ public void setAttribute(String name, Object value) { /** * Return the <code>isValid</code> flag for this session. */ boolean isValid() { } // Validate and update our current component state if (configured) throw new LifecycleException (sm.getString("standardManager.alreadyConfigured")); configured = true; if (parameters == null) return; public final class StandardManager extends ManagerBase implements Lifecycle, Runnable { removeAttribute(name); } } /** * The string manager for this package. */ private StringManager sm = /** * The current accessed time for this session. */ private long thisAccessedTime = creationTime; // Reset the instance variables associated with this attributes.clear(); creationTime = 0L; id = null; lastAccessedTime = 0L; manager = null; maxInactiveInterval = -1; isNew = true; isValid = false; // Tell our Manager that this Session has been recycled if ((manager != null) && (manager instanceof ManagerBase)) ((ManagerBase) manager).recycle(this); // ------------------------------------------------ Session Package Methods StringManager.getManager("org.apache.tomcat.session"); /** * The HTTP session context associated with this session. */ private static HttpSessionContext sessionContext = null; /** * 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>HttpSessionBindingListener</code>, the container calls * <code>valueUnbound()</code> on the object. * * @param name Name of the object to remove from this session. * * @exception IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * <code>removeAttribute()</code> */ public void removeValue(String name) { // Mark this session as invalid setValid(false); /** * Release all object references, and initialize instance variables, in * preparation for reuse of this object. */ public void recycle() { // ------------------------------------------------------ Lifecycle Methods /** * 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. * * @param parameters Configuration parameters for this component * (<B>FIXME: What object type should this really be?) * * @exception IllegalStateException if this component has already been * configured and/or started * @exception LifecycleException if this component detects a fatal error * in the configuration parameters it was given */ public void configure(Node parameters) throws LifecycleException { /** * 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> * <Manager className="org.apache.tomcat.session.StandardManager" * checkInterval="60" maxActiveSessions="-1" * maxInactiveInterval="-1" /> * </code> * where you can adjust the following parameters, with default values * in square brackets: * <ul> * <li><b>checkInterval</b> - The interval (in seconds) between background * thread checks for expired sessions. [60] * <li><b>maxActiveSessions</b> - The maximum number of sessions allowed to * be active at once, or -1 for no limit. [-1] * <li><b>maxInactiveInterval</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. McClanahan * @version $Revision: 1.1.1.1 $ $Date: 2000/05/02 21:28:30 $ */ } } Session 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.HttpSession; import org.apache.tomcat.util.StringManager; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; synchronized (attributes) { Object object = attributes.get(name); if (object == null) return; attributes.remove(name); // System.out.println( "Removing attribute " + name ); if (object instanceof HttpSessionBindingListener) { ((HttpSessionBindingListener) object).valueUnbound (new HttpSessionBindingEvent((HttpSession) this, name)); } } // Unbind any objects associated with this session Vector results = new Vector(); Enumeration attrs = getAttributeNames(); while (attrs.hasMoreElements()) { String attr = (String) attrs.nextElement(); results.addElement(attr); } Enumeration names = results.elements(); while (names.hasMoreElements()) { String name = (String) names.nextElement(); removeAttribute(name); } /** * The Manager with which this Session is associated. */ private Manager manager = null; not. } } throw new IllegalStateException(msg); /** * 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>HttpSessionBindingListener</code>, the container calls * <code>valueUnbound()</code> on the object. * * @param name Name of the object to remove from this session. * * @exception IllegalStateException if this method is called on an * invalidated session */ public void removeAttribute(String name) { // Remove this session from our manager's active sessions if ((manager != null) && (manager instanceof ManagerBase)) ((ManagerBase) manager).remove(this); /** * The last accessed time for this Session. */ private long lastAccessedTime = creationTime; /** * The maximum time interval, in seconds, between client requests before * the servlet container may invalidate this session. A negative time * indicates that the session should never time out. */ private int maxInactiveInterval = -1; * @deprecated */ public String getId() { if (valid) { return id; } else { String msg = sm.getString("applicationSession.session.ise"); } StandardManager setAttribute(name, value); } this.lastAccessedTime = this.thisAccessedTime; this.thisAccessedTime = System.currentTimeMillis(); this.isNew=false; /** * Perform the internal processing required to invalidate this session, * without triggering an exception if the session has already expired. */ public void expire() { /** * Descriptive information describing this Session implementation. */ private static final String info = "StandardSession/1.0"; public void removeValue(String name) { removeAttribute(name); } if (thisInterval > inactiveInterval) { invalidate(); } // HTTP SESSION IMPLEMENTATION METHODS } /** * 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 creationTime = 0L; * 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>HttpSessionBindingListener</code>, the container calls * <code>valueBound()</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 IllegalStateException if this method is called on an * invalidated session * * @deprecated As of Version 2.2, this method is replaced by * <code>setAttribute()</code> */ public void putValue(String name, Object value) { return ((HttpSession) this); // ---------------------------------------------------------- Constructors // ----------------------------------------------------Instance Variables /** /** * Return the <code>HttpSession</code> for which this object * is the facade. */ public HttpSession getSession() { } // ------------------------------------------------- Session Public Methods /** * 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() { /** * Construct a new Session associated with the specified Manager. * * @param manager The manager with which this Session is associated */ public StandardSession(Manager manager) { public void removeAttribute(String name) { if (! valid) { String msg = sm.getString("applicationSession.session.ise"); /** validate(); void validate() { // if we have an inactive interval, check to see if we've exceeded it if (inactiveInterval != -1) { int thisInterval = (int)(System.currentTimeMillis() - lastAccessed) / 1000; } throw new IllegalStateException(msg); Hashtable valuesClone = (Hashtable)values.clone(); /** * Called by context when request comes in so that accesses and * inactivities can be dealt with accordingly. */ void accessed() { // set last accessed to thisAccessTime as it will be left over // from the previous access lastAccessed = thisAccessTime; thisAccessTime = System.currentTimeMillis(); public long getLastAccessedTime() { if (valid) { return lastAccessed; } else { String msg = sm.getString("applicationSession.session.ise"); final class StandardSession implements HttpSession, Session { } if (this.inactiveInterval != -1) { this.inactiveInterval *= 60; } ServerSession getServerSession() { return serverSession; } /** * 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 (HttpSession) 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 * HttpSession view of this instance back to a Session view. * * @author Craig R. McClanahan * @version $Revision: 1.2 $ $Date: 2000/05/15 17:54:10 $ */ return valueNames; } } throw new IllegalArgumentException(msg); return values.get(name); while (e.hasMoreElements()) { names.addElement(e.nextElement()); } this.inactiveInterval = context.getSessionTimeOut(); } throw new IllegalStateException(msg); if (name == null) { String msg = sm.getString("applicationSession.value.iae"); } } import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import javax.servlet.ServletException; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import javax.servlet.http.HttpSessionContext; import org.apache.tomcat.catalina.*; import org.apache.tomcat.util.StringManager; super(); this.manager = manager; /** * @deprecated */ public String[] getValueNames() { Enumeration e = getAttributeNames(); Vector names = new Vector(); ApplicationSession(String id, ServerSession serverSession, Context context) { this.serverSession = serverSession; this.context = context; this.id = id; StandardSession package org.apache.tomcat.session; } public Object getAttribute(String name) { if (! valid) { String msg = sm.getString("applicationSession.session.ise"); private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); private Hashtable values = new Hashtable(); private String id; private ServerSession serverSession; private Context context; private long creationTime = System.currentTimeMillis();; private long thisAccessTime = creationTime; private long lastAccessed = creationTime; private int inactiveInterval = -1; private boolean valid = true; } ((HttpSessionBindingListener)value).valueBound(e); /** * @deprecated */ public Object getValue(String name) { return getAttribute(name); } public class ApplicationSession implements HttpSession { } // remove any existing binding values.put(name, value); } import org.apache.tomcat.core.*; import org.apache.tomcat.util.StringManager; import java.io.*; import java.net.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; } throw new IllegalArgumentException(msg); removeValue(name); if (value != null && value instanceof HttpSessionBindingListener) { HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, name); /** * Core implementation of an application level session * * @author James Duncan Davidson [[email protected]] * @author Jason Hunter [[email protected]] * @author James Todd [[email protected]] */ } throw new IllegalStateException(msg); if (name == null) { String msg = sm.getString("applicationSession.value.iae"); package org.apache.tomcat.session; } throw new IllegalStateException(msg); } } return session.getApplicationSession( ctx, true ); public HttpSession findSession(Context ctx, String id) { ServerSession sSession=(ServerSession)sessions.get(id); if(sSession==null) return null; } return sSession.getApplicationSession(ctx, false); return (null); } } return (this.isNew); } /** * Return the maximum time interval, in seconds, between client requests * before the servlet container will invalidate the session. A negative * time indicates that the session should never time out. * * @exception IllegalStateException if this method is called on * an invalidated session */ public int getMaxInactiveInterval() { return (this.maxInactiveInterval); } /** * 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 setMaxInactiveInterval(int interval) { this.maxInactiveInterval = interval; } # AOP - AspectJ 5 © S. Bouchenak, V.Marangozova AOP - AspectJ 6 org apache tomcat Conslusion about the Code ! Loca zed treatments ! Con gura on About Scattered Code ! es XML pars ng In most cases, we can d fferent ate two types of code ! ! Treatments mp emented w th few c asses ! ! HTTP reques s regu ar express ons ! ! Treatments that are scattered everywhere ! © rac ng ana ys s o prob ems accoun o encoun ered prob ems dur ng reques rea men M O © Bas c unc ona y app ca on code Managemen code code ha makes he bas c unc ona y code o rea y work The organ za on o he code o ows he bas c unc ona y code og c ! n consequence he managemen code s usua y sca ered ! Th s s why managemen code s d cu o wr e M O What are the problems with non modular code? ! ! ! Separate tangled code ! Minimize inter-code dependancies ! All treatments should have Same treatments repeated throughout the application code Obscure code ! ! AOP Principles Redundancy ! ! Aspect-Oriented Programming Code structure is not explicit Global code architecture difficult to understand ! Difficult to change/maintain code ! ! ! We need to found the fragments that concern the feature we want to change We need to make sure that changes are consistent i.e that a change in one place does not “hurt” a change in another place No tools to help... © S. Bouchenak, V.Marangozova AOP - AspectJ 9 Outline $ a clear objective a well-defined modular structure Aspects ! Modular treatments that can be “mixed”/composed/ tangled/organized together © S. Bouchenak, V.Marangozova AOP - AspectJ 10 AOP Definition 1. Introduction to AOP 2. Introduction to AspectJ 3. Syntax of AspectJ 4. Software Development with AspectJ 5. Conclusion and References © S. Bouchenak, V.Marangozova ! AOP - AspectJ 11 ! AOP = Aspect-Oriented Programming ! "Aspect-oriented programming allows the factorization of treatments whose implementation is scattered through a system” © S. Bouchenak, V.Marangozova AOP - AspectJ 12 Types of Aspects AOP Methodology A software system comprises: ! ! ! Applicational aspects that correspond to core concerns. These are the software modules that implement the basic functionality of a system.. Orthogonal aspects : cross-cutting concerns. Software modules that implement system code to be used by several other softwrae modules.. © S. Bouchenak, V.Marangozova AOP - AspectJ 13 AOP Methodology : 1. Decompose in aspects ! ! Application aspects. Example of a banking system : clients, accounts, transfers, etc. Management aspects. Examples : data persistancy, authentification, tracing, ressource sharing, performance, etc. © S. Bouchenak, V.Marangozova AOP - AspectJ 1. Decompose a system into aspects 2. Implement the aspects 3. Recompose the aspects © S. Bouchenak, V.Marangozova AOP - AspectJ 14 AOP Methodology : 2. Aspect Implementation Separate the software treatments into : ! How do we do AOP? ! 15 Implementatio of aspects in an independent way i.e each aspect alone ! Implementation techniques ! ! ! procedural languages OO Techniques © S. Bouchenak, V.Marangozova AOP - AspectJ 16 AOP Methodology : 3. Aspects Composition (Weaving) ! ! ! ! Rules for composing aspects These rules are used in order to produce the final system Composition process: integration or weaving Example : before each operation on the banking system, the client must be authentified. composition rule How to AOP? AOP is a methodologie, how do we put it into practice? ! applicational aspect ! Aspect languages : C, C++, Java, etc. ! Languages for speifying the rules for asepct weaving : AspectC, AspectJ, etc. ! Aspect integration tool : aspect weaver, AOP compiler (AspectC, AspectJ, etc.) management aspect © S. Bouchenak, V.Marangozova AOP - AspectJ 17 © S. Bouchenak, V.Marangozova AOP in Java 18 Outline AOP Introduction 1. aspects aspects fonctionnels functional fonctionnels aspects Java Introduction to AspectJ 2. ! Java ! composition rules AOP compiler AspectJ compilo AspectJ ! ! Java AOP - AspectJ 19 AspectJ Composition join point, pointcut, advice, introduction, declaration, aspect Programming Examples 3. AspectJ syntax 4. Development with AspectJ 5. Conclusion and Refs final system aspects aspects fonctionnels system fonctionnels aspects © S. Bouchenak, V.Marangozova AOP - AspectJ © S. Bouchenak, V.Marangozova AOP - AspectJ 20 Composition elements in AspectJ Composition in AspectJ Static composition ! ! ! ! ! ! Composition in AspectJ ! Join point Pointcut Advice Introduction Declaration (at compile-time) Aspect ! We cans add new behaviour to the normal behaviour of the program We can extend or replace an operation We can operate before or after the execution of some operations s ! is an extension of Java for definig rules for dynamic and static composition ! Dynamic composition ! AspectJ ! We can change the structure of the system : classes and interfaces We cans add methods and attributes We can declare warnings or compile-time errors ! ! ! ! ! ! © S. Bouchenak, V.Marangozova AOP - AspectJ 21 Join point ! ! Example ! execution (void Account.credit(float)) public class Account { float balance; void credit(float amount) { this.balance += amount; } ! ! The Account join points include ! ! Pointcut ! } ! A pointcut is used to select a join point and get the execution context of this join point ! Example ! 22 Definition ! An well-identified point in the execution af a program Can be a method call or the access of an attribute ! AOP - AspectJ Pointcut Definition ! © S. Bouchenak, V.Marangozova select the join point correspondint to the call of the credit method of the Account class get the execution context for this method : the object on which the method is called, the method’s parameters the execution of the credit method the access to the balance attribute © S. Bouchenak, V.Marangozova AOP - AspectJ 23 © S. Bouchenak, V.Marangozova AOP - AspectJ 24 Advice Introduction Definition ! ! Definition ! The code associated to a pointcut i.e the code to be executed when the pointcut happens during the execution of a program Execution before, after or in replacement of a pointcut ! ! Example ! Example ! declare parents : Account implements BankingEntity; before() : execution (void Account.credit(float)) { System.out.println("About to perform credit operation"); } private float Account._minimalBalance; ! ! ! AOP - AspectJ 25 Compile-time declaration ! © S. Bouchenak, V.Marangozova ! ! ! declare warning : call (void Persistence.save(Object)) : "Deprecated method Persistence.save(), Consider using Persistence.saveOptimized()"; ! Example de fichier ExampleAspect.java public aspect ExampleAspect { declare parents : Account implements BankingEntity; Declaration ! ! ! 26 A code module containing the rules for static and dynamic composition Introductions + declarations + pointcuts + advices = aspect An aspect in AspectJ is equivalent to a Java class ! Example ! AOP - AspectJ Definition ! Add instructions to be composed statically Add warnings or errors for the compilation process ! extension of the class hierarchy from now on (actually, after weaving...) Account will implement the BankingAccount interface add a new attribute _minimalBalance to Account Aspect Definition ! ! message printing before the execution of the credit method of the Account class © S. Bouchenak, V.Marangozova Introduction ! Advice ! Static change of aclass or an interface Add a method or an attribute, extend inheritance relations ! before() : execution (void Account.credit(float)) { System.out.println("About to perform credit operation"); } declare a warning print a message of the save method of the Persistence call is called declare warning : call (void Persistence.save(Object)) : "Deprecated method Persistence.save(), Consider using Persistence.saveOptimized()"; } © S. Bouchenak, V.Marangozova AOP - AspectJ 27 © S. Bouchenak, V.Marangozova AOP - AspectJ 28 Programming Methodology Example Hello (1 / 4) Design ! 1. 2. ! 1. 2. 3. 4. Program an aspect containing the implementation of the above design Program the desired join points Program the advice to be associated to the above join pojnts i.e define the new behaviour to execute at these join points Add rules for static composition if necessary (introductions, declarations) © S. Bouchenak, V.Marangozova AOP - AspectJ 29 Example Hello (2 / 4) public class Test { public static void main(String[] args) { Communicator.print("Want to learn AspectJ?"); Communicator.print("Tom", "how are you?"); } } © S. Bouchenak, V.Marangozova AOP - AspectJ 30 Example Hello (3 / 4) Compilation Java ! Aspect public aspect HelloAspect { % javac Communicator.java Test.java ! public class Communicator { public static void print(String message) { System.out.println(message); } public static void print(String person, String message) { System.out.println(person + ", " + message); } } Implementation ! ! Application Identify the join points where the program behaviour should be changed/extended Design the new behaviour to be inserted at these join ponts & Declaration of an aspect pointcut printCall() : call (void Communicator.print(..)); ' Declaration of a pointcut Execution before() : printCall() { System.out.print("Hello! "); } % java Test Want to learn AspectJ? ( Declaration of an advice Tom, how are you? } © S. Bouchenak, V.Marangozova AOP - AspectJ 31 © S. Bouchenak, V.Marangozova AOP - AspectJ 32 Example Hello (4 / 4) ! Tracing Example (1/4) Compilation AspectJ ! Initial application package banking; % ajc Communicator.java Test.java HelloAspect.java public class Account { float balance; ! Execution void credit(float amount) { this.balance += amount; % java Test Hello! Want to learn AspectJ? } Hello! Tom, how are you? void debit(float amount) { this.balance -= amount; } } © S. Bouchenak, V.Marangozova AOP - AspectJ 33 Tracing Example (2 / 4) ! AOP - AspectJ 34 Tracing Example (3 / 4) “By hand” Modifications ! Another solution : Aspect for automatic tracing public aspect AutoLogAspect { package banking; pointcut methodExecution() : execution (* banking.Account.*(..)); public class Account { float balance; before() : methodExecution() { Signature sig = thisJoinPointStaticPart.getSignature(); String className = sig.getDeclaringType().getName(); String methodName = sig.getName(); Logger.entering(className, methodName); } void credit(float amount) { Logger.entering("banking.Account", "credit(float)"); this.balance += amount; Logger.exiting("banking.Account", "credit(float)"); } after() : methodExecution() { Signature sig = thisJoinPointStaticPart.getSignature(); String className = sig.getDeclaringType().getName(); String methodName = sig.getName(); Logger.exiting(className, methodName); }} void debit(float amount) { Logger.entering("banking.Account", "debit(float)"); this.balance -= amount; Logger.exiting("banking.Account", "debit(float)"); } } © S. Bouchenak, V.Marangozova © S. Bouchenak, V.Marangozova AOP - AspectJ 35 © S. Bouchenak, V.Marangozova AOP - AspectJ 36 Tracing Example (4 / 4) Outline initial application Account Java Java AutoLogAspect 1. Introduction to AOP 2. Introduction to AspectJ Syntaxe AspectJ 3. authomatic tracing aspect ! AOP compiler compilo AspectJ AspectJ ! ! application with tracing ! ! Logger Account + Logger tracing module Java © S. Bouchenak, V.Marangozova AOP - AspectJ 37 Pointcut ! Pointcut Call vs. Execution Pointcuts de flot de contrôle, de structure lexicale Advice Passage de paramètres entre pointcut et advice 4. Software Development with AspectJ 5. Conclusion and Refs © S. Bouchenak, V.Marangozova AOP - AspectJ 38 Signature of a pointcut pointcut syntax ! Example [mode_accès] pointcut nom_pointcut([args]) : definition_pointcut public pointcut printCall() : call ( void Communicator.print(..) ) ! Example pointcut type pointcut name keyword mode d’accès public pointcut printCall() : call ( void Communicator.print(..) ) pointcut type pointcut name ! signature Signature of a pointcut % keyword mode d’accès % % © S. Bouchenak, V.Marangozova AOP - AspectJ signature 39 Signature of a type Signature of methods/constructors Signature of an attribute © S. Bouchenak, V.Marangozova AOP - AspectJ 40 Pointcut : Method Signature Pointcut : Type Signature Signature Types associés Signature Account Type (classe / interface) called Account *Account Type whose name ends with Account, e.g SavingsAccount, CheckingAccount java.*.Date Type Date in a direct subpackage of the package java, e.g java.util.Date, java.sql.Date java..Date All types Date in the package java or in a subpackage (direct or indirect subpackage of the java package) java.util.List+ Type inheriting the java.util.List interface (implementing) © S. Bouchenak, V.Marangozova AOP - AspectJ 41 Pointcut : Constructor Signature Signature Methods associées public void Collection.clear() public method clear() of the Collection class, method with no parameters returning void public void Account.set*(*) Each public method of the Account class, whose name starts with set and returning void (no constraint on the parameters) * Account.*() Each method of the class Account, no parameters, whatever the returning type, whatever its access mode public void Account.*(..) All public methods of the class Account, returning void * *.*(..) throws RemoteException All methods raising exception of type RemoteException © S. Bouchenak, V.Marangozova Whatever the name, whatever the parameters AOP - AspectJ 42 Pointcut : Attribute Signature Constructors associés Signature Attributes associés public Account.new() public constructor of the class Account, no parameters private float Account.balance The private attribute balance of the class Account public Account.new(int) public constructor of the class Account, one int parameter * Account.* All Account attributes, whatever its type, name or access mode public Account.new(..) All constructors of the class Account, whatever the parameters public static * banking..*.* All public static attributes of a class in the banking package or in one of the subpackages public Account +.new(..) All constructors of the Account class or of one if its subclasses * *.* All attributes of all classes © S. Bouchenak, V.Marangozova AOP - AspectJ 43 © S. Bouchenak, V.Marangozova AOP - AspectJ 44 Pointcut Operators ! Unary Operator : ! ! public !final *.* All public and non final attributes !Vector All types different from Vector ! pointcut Type Example public pointcut printCall() : call ( void Communicator.print(..) ) Binary Operators : && (et) || (ou) Vector || Hashtable pointcut type pointcut name keyword access mode Type Vector or Hashtable ! java.util.RandomA All type implementing both interfaces ccess+ && java.util.List pointcut type % % % © S. Bouchenak, V.Marangozova AOP - AspectJ 45 Types de pointcuts method, constructor call method, constructor execution Access to an attribute (read/write) © S. Bouchenak, V.Marangozova AOP - AspectJ 46 Call vs. Execution (1 / 5) ! Pointcut Type signature Example Syntaxe method call call(signature_method) method execution execution(signature_method) constructor call call(signature_constructor) constructor execution execution(signature_constructor) classe initialization staticinitialization(signature_type) Read access of an attribute get(signature_attribute) write access of an attribute set(signature_attribute) Traitant d’exception handler(signature_type) public class Account { float balance; void credit(float amount) { execution this.balance += amount; } } public class Test { public static void main(String[] args) { Account account = new Account(); call accout.credit(100); } } © S. Bouchenak, V.Marangozova AOP - AspectJ 47 © S. Bouchenak, V.Marangozova AOP - AspectJ 48 Call vs. Execution (2 / 5) ! Call vs. Execution (3 / 5) Aspect using the call ! public class Account { float balance; public aspect AutoLogAspect_Call { pointcut creditMethodCall() : call (* Account.credit(..)); void credit(float amount) { before() : creditMethodCall() { … Logger.entering(className, methodName); } } this.balance += amount; } public class Test { public static void main(String[] args) { Account account = new Account(); Logger.entering("Account", "credit(float)"); accout.credit(100); } } } © S. Bouchenak, V.Marangozova AOP - AspectJ 49 Call vs. Execution (4 / 5) ! Application de l’AutoLogAspect_Call © S. Bouchenak, V.Marangozova AOP - AspectJ 50 Call vs. Execution (5 / 5) Aspect using execution ! Application de l’AutoLogAspect_Execution public class Account { float balance; public aspect AutoLogAspect_Execution { pointcut creditMethodExecution() : execution (* Account.credit(..)); void credit(float amount) { Logger.entering("Account", "credit(float)"); this.balance += amount; } before() : creditMethodExecution() { … Logger.entering(className, methodName); } } public class Test { public static void main(String[] args) { Account account = new Account(); } accout.credit(100); } } © S. Bouchenak, V.Marangozova AOP - AspectJ 51 © S. Bouchenak, V.Marangozova AOP - AspectJ 52 Control Flow Pointcuts Pointcut cflow / cflowbelow ! Description cflow(call (* Account.credit(..))) All join points in the control flow of the method credit of the Account class, including the call of the method cflowbelow(call (* Account.credit(..))) All join points in the control flow of the method credit of the Account class, without the call of the method cflow( creditMethodCall()) All join points in the control flow of the pointcut creditMethodCall cflowbelow(execution (* Account.new(..))) All join points in the control flow of a cnstructor of the class Account, without the execution of the constructor itself Example public class Test { public static void main(String[] args) { Account account = new Account(); accout.credit(100); © S. Bouchenak, V.Marangozova AOP - AspectJ 53 } } © S. Bouchenak, V.Marangozova AOP - AspectJ 54 cflow / cflowbelow : cflow / cflowbelow public class Account { int id; // account id Database database; // associated database public class Database { float getBalance() { float query(String sqlQuery) { return database.query("SELECT balance FROM accounts WHERE id=" + id); … lecture de la base de données } } void setBalance(float b) { void update(String sqlQuery) { database.update("UPDATE accounts SET balance="+b+" WHERE id=" + id); … écriture dans la base de données } } void credit(float amount) { } setBalance(getBalance() + amount); } } © S. Bouchenak, V.Marangozova AOP - AspectJ 55 © S. Bouchenak, V.Marangozova AOP - AspectJ 56 cflow / cflowbelow ! cflow Flot de contrôle à l’appel de la method credit ! Test.main Aspect utilisant le cflow public aspect AutoLogAspect_CallF { pointcut creditMethodCallF() : cflow( call (* Account.credit(..)) ); new Account Account.credit Account.getBalance before() : creditMethodCallF() { System.out.println("Hello!"); } Account.setBalance } Database.query © S. Bouchenak, V.Marangozova Database.update AOP - AspectJ 57 cflow : important… ! ! Test.main Account.setBalance Database.query © S. Bouchenak, V.Marangozova 58 Example public class Test { public static void main(String[] args) { Account account = new Account(); System.out.println("Hello!"); accout.credit(100); } } Account.credit Account.getBalance AOP - AspectJ cflow : mais encore… cflow( call(* Account.credit(..)) ) new Account © S. Bouchenak, V.Marangozova Database.update AOP - AspectJ 59 © S. Bouchenak, V.Marangozova AOP - AspectJ 60 cflow : mais encore… cflowbelow ! public class Account { int id; // account id Database database; // associated database float getBalance() { System.out.println("Hello!"); return database.query("SELECT balance FROM accounts WHERE id=" + id); Aspect utilisant le cflowbelow public aspect AutoLogAspect_CallFB { pointcut creditMethodCallFB() : cflowbelow( call (* Account.credit(..)) ); } before() : creditMethodCallFB() { System.out.println("Hello!"); } void setBalance(float b) { System.out.println("Hello!"); database.update("UPDATE accounts SET balance="+b+" WHERE id=" + id); } } void credit(float amount) { System.out.println("Hello!"); setBalance(getBalance() + amount); } } © S. Bouchenak, V.Marangozova AOP - AspectJ 61 cflowbelow : mais encore… ! ! Test.main Account.setBalance Database.query © S. Bouchenak, V.Marangozova 62 Example public class Test { public static void main(String[] args) { Account account = new Account(); System.out.println("Hello!"); accout.credit(100); } } Account.credit Account.getBalance AOP - AspectJ cflowbelow cflowbelow( call(* Account.credit(..)) ) new Account © S. Bouchenak, V.Marangozova Database.update AOP - AspectJ 63 © S. Bouchenak, V.Marangozova AOP - AspectJ 64 Pointcuts related to the lexical structure cflowbelow : mais encore… public class Account { int id; // account id Database database; // associated database Pointcut Description float getBalance() { System.out.println("Hello!"); return database.query("SELECT balance FROM accounts WHERE id=" + id); within(Account) All join point in the class Account } within(Account+) All join point in the class Account and in its subclasses withincode(* Account.credit(..)) All join points in the method credit of the class Account void setBalance(float b) { System.out.println("Hello!"); database.update("UPDATE accounts SET balance="+b+" WHERE id=" + id); } void credit(float amount) { System.out.println("Hello!"); setBalance(getBalance() + amount); } } © S. Bouchenak, V.Marangozova AOP - AspectJ 65 Aspect with execution Pointcut pointcut methodExecution() : execution (* Account.*(..)) && within(banking..*); target(Account) Every join point where the object on which the method is called is instance of Account or of one of its subclasses. Pointcut used in combination with call ! } ! 67 Description Every join point where this is instance of the Account class or of one of its subclasses ( during a method call or the access of appel de method ou accès à l’attribute d’un objet Account). This pointcut is used in combination with execution before() : methodExecution() { … Logger.entering(className, methodName); } AOP - AspectJ 66 this(Account) public aspect AutoLogAspect_Execution { © S. Bouchenak, V.Marangozova AOP - AspectJ Pointcuts related to the execution object Example with within ! © S. Bouchenak, V.Marangozova this(Type) or this(ObjectIdentifier) target(Type) or target(ObjectIdentifier) © S. Bouchenak, V.Marangozova AOP - AspectJ 68 Pointcuts arguments Advice ! Advice : ! Pointcut args(String,..,int) Description ! Syntax of an advice All join points of all the methods where the first argument is of type String and the last of type int. specification_advice([args]) : nom_pointcut([args}) { … advice body } ! ! Code to execute at a join point args(Type or ObjectIdentifier,..) Example before () : printCall () { … advice body } pointcut name specification d’advice © S. Bouchenak, V.Marangozova AOP - AspectJ 69 Advice : Syntax ! © S. Bouchenak, V.Marangozova 70 Types of advice Syntaxe d’un advice ! specification_advice([args]) : definition_pointcut { … advice body } ! AOP - AspectJ Advice before ! ! Example executes before the join point Advice after ! executes after join point before () : call ( void Communicator.print(..) ) { ! … corps de l’advice } Advice around ! signature surrounds the execution of the join point pointcut type specification d’advice © S. Bouchenak, V.Marangozova AOP - AspectJ 71 © S. Bouchenak, V.Marangozova AOP - AspectJ 72 Advice before ! Advice after Example ! Termination (normal or exception) after () : call ( * Account.*(..)) { before () : call ( * Account.*(..)) { } ! ! If the adfice raises an exception, the ethod is not executed Normal termination } ! Examples ! after() throwing () : call ( * Account.*(..)) { } AOP - AspectJ 73 Replace a treatment © S. Bouchenak, V.Marangozova ! around () : call ( void Account.credit(float)) { … new implementation of the method AOP - AspectJ 74 Parameter passing before (Account account , float amount ) : } ! … trace the exception Context Passing between a join point and the advice (1 / 3) Advice around ! … Termination with an exception Tracing, authentification, etc. © S. Bouchenak, V.Marangozova … trace all terminations after() returning () : call ( * Account.*(..)) { Particlular case ! ! } … authentify the user Surround a treatment call ( * Account.credit(float)) && target( account ) && args( amount ) { around (Account acount, float amount) : call ( * Account.credit(float)) && target(account) && args(amount) { System.out.println("Crediting from " + account + " value " + amount ); } … trace the beginning of the method execution proceed(account, amount); //go on with the method execution … trace the end of the method execution } © S. Bouchenak, V.Marangozova AOP - AspectJ 75 © S. Bouchenak, V.Marangozova AOP - AspectJ 76 Context Passing between a join point and the advice (2 / 3) ! Get the result Context Passing between a join point and the advice (3 / 3) ! after returning (Object object ) : Get the exception after throwing (RemoteException except ) : call ( Object Account.*(..)) { call ( * Account.*(..) throws RemoteException ) { System.out.println("Result " + object ); System.out.println("Exception " + except ); } } © S. Bouchenak, V.Marangozova AOP - AspectJ 77 Outline AOP - AspectJ 78 AspectJ Compiler 1. Introduction to l’AOP 2. Introduction to AspectJ 3. Syntax of AspectJ 4. Software Development with AspectJ 5. Conclusion and Refs © S. Bouchenak, V.Marangozova © S. Bouchenak, V.Marangozova ! ajc commande classes and aspects Java (.java) AOP - AspectJ compiler AspectJ (ajc) final system (.class ou .jar) library (.jar) 79 © S. Bouchenak, V.Marangozova AOP - AspectJ 80 Browser AspectJ (ajbrowser) AOP in few words ! © S. Bouchenak, V.Marangozova AOP - AspectJ 81 Web AOP : what for? ! EXtend an existing system so as to integrate new treatments ! Modular design of a system composed of multiple aspects (application and management) © S. Bouchenak, V.Marangozova AOP - AspectJ 82 Bibliography ! Aspect-Oriented Programming, Kiczales et. al., ECOOP’1997 ! An Overview of AspectJ, Kiczales et. al., ECOOP’2001 ! Getting Started with AspectJ, Kiczales et. al., CACM 44(10), Oct. 2001 AOP in C, C++ http://www.aspectc.org/ ! Aspect-Oriented Programming with AspectJ, Ivan Kiselev, SAMS 2002 Google is your friend :) ! Mastering AspectJ: Aspect-Oriented Programming in Java, Joseph D. Gradecki, Nicholas Lesiecki, John Wiley & Sons 2003 ! AspectJ in Action, R. Laddad, Manning, 2003. ! AOP http://aosd.net ! AspectJ http://aspectj.org ! ! © S. Bouchenak, V.Marangozova AOP - AspectJ 83 © S. Bouchenak, V.Marangozova AOP - AspectJ 84