the fun has just begun

judgedrunkshipServers

Nov 17, 2013 (3 years and 10 months ago)

104 views

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003



the fun has just begun

Gregor Kiczales


University of British Columbia





© Copyright 2003, Gregor Kiczales, except for slides explicitly marked with a different copyright.

Permission is granted to use this presentation, in whole or in part for educational purposes, provided that
every slide used is used in its entirety, with no changes, deletions or additions; and that the copyright
notice is preserved on every slide used.

software modularity group

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

talk timeline
and level of abstraction

software
models

conclusion

tangle,
scatter,
crosscut

join point
mechanisms

another

view

© Copyright 2003, Gregor Kiczales. All rights reserved.

scatter

tangle

crosscut

and

all

that

exploring

some of the
terms we use

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

bad modularity

/*


* ====================================================================


*


* The Apache Software License, Version 1.1


*


* Copyright (c) 1999 The Apache Software Foundation. All rights


* reserved.


*


* Redistribution and use in source and binary forms, with or without


* modification, are permitted provided that the following conditions


* are met:


*


* 1. Redistributions of source code must retain the above copyright


* notice, this list of conditions and the following disclaimer.


*


* 2. Redistributions in binary form must reproduce the above copyright


* notice, this list of conditions and the following disclaimer in


* the documentation and/or other materials provided with the


* distribution.


*


* 3. The end
-
user documentation included with the redistribution, if


* any, must include the following acknowlegement:


* "This product includes software developed by the


* Apache Software Foundation (http://www.apache.org/)."


* Alternately, this acknowlegement may appear in the software

itself,


* if and wherever such third
-
party acknowlegements normally appear.


*


* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software


* Foundation" must not be used to endorse or promote products

derived


* from this software without prior written permission. For written


* permission, please contact apache@apache.org.


*


* 5. Products derived from this software may not be called "Apache"


* nor may "Apache" appear in their names without prior written


* permission of the Apache Group.


*


* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED


* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES


* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE


* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR


* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,


* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT


* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF


* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND


* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,


* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT


* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF


* SUCH DAMAGE.


* ====================================================================


*


* This software consists of voluntary contributions made by many


* individuals on behalf of the Apache Software Foundation. For more


* information on the Apache Software Foundation, please see


* <http://www.apache.org/>.


*


* [Additional notices, if required by prior licensing conditions]


*


*/




package org.apache.tomcat.session;


import org.apache.tomcat.core.*;

import org.apache.tomcat.util.StringManager;

import java.io.*;

import java.net.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;


/**


* Core implementation of an application level session


*


* @author James Duncan Davidson [duncan@eng.sun.com]


* @author Jason Hunter [jch@eng.sun.com]


* @author James Todd [gonzo@eng.sun.com]


*/


public class ApplicationSession implements HttpSession {



private StringManager sm =


StringManager.getManager("org.apache.tomcat.session");


private Hashtable values = new Hashtable();


private String id;


private ServerSession serverSession;


private Context context;


private long creationTime = System.currentTimeMillis();;


private long thisAccessTime = creationTime;


private long lastAccessed = creationTime;


private int inactiveInterval =
-
1;


private boolean valid = true;



ApplicationSession(String id, ServerSession serverSession,


Context context) {


this.serverSession = serverSession;


this.context = context;


this.id = id;



this.inactiveInterval = context.getSessionTimeOut();



if (this.inactiveInterval !=
-
1) {


this.inactiveInterval *= 60;


}


}



ServerSession getServerSession() {


return serverSession;


}



/**


* Called by context when request comes in so that accesses and


* inactivities can be dealt with accordingly.


*/



void accessed() {


// set last accessed to thisAccessTime as it will be left over


// from the previous access


lastAccessed = thisAccessTime;


thisAccessTime = System.currentTimeMillis();



validate();


}



void validate() {


// if we have an inactive interval, check to see if we've exceeded it


if (inactiveInterval !=
-
1) {


int thisInterval =


(int)(System.currentTimeMillis()
-

lastAccessed) / 1000;



if (thisInterval > inactiveInterval) {


invalidate();


}


}


}




// HTTP SESSION IMPLEMENTATION METHODS




public String getId() {


if (valid) {


return id;


} else {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}


}



public long getCreationTime() {


if (valid) {


return creationTime;


} else {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}


}




/**


*


* @deprecated


*/



public HttpSessionContext getSessionContext() {


return new SessionContextImpl();


}




public long getLastAccessedTime() {


if (valid) {


return lastAccessed;


} else {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}


}




public void invalidate() {


serverSession.removeApplicationSession(context);



// remove everything in the session



Enumeration enum = values.keys();


while (enum.hasMoreElements()) {


String name = (String)enum.nextElement();


removeValue(name);


}



valid = false;


}



public boolean isNew() {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (thisAccessTime == creationTime) {


return true;


} else {


return false;


}


}





/**


* @deprecated


*/



public void putValue(String name, Object value) {


setAttribute(name, value);


}



public void setAttribute(String name, Object value) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (name == null) {


String msg = sm.getString("applicationSession.value.iae");



throw new IllegalArgumentException(msg);


}



removeValue(name); // remove any existing binding



if (value != null && value instanceof HttpSessionBindingListener) {


HttpSessionBindingEvent e =


new HttpSessionBindingEvent(this, name);



((HttpSessionBindingListener)value).valueBound(e);


}



values.put(name, value);


}



/**


* @deprecated


*/


public Object getValue(String name) {


return getAttribute(name);


}



public Object getAttribute(String name) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (name == null) {


String msg = sm.getString("applicationSession.value.iae");



throw new IllegalArgumentException(msg);


}



return values.get(name);


}



/**


* @deprecated


*/


public String[] getValueNames() {


Enumeration e = getAttributeNames();


Vector names = new Vector();



while (e.hasMoreElements()) {


names.addElement(e.nextElement());


}



String[] valueNames = new String[names.size()];



names.copyInto(valueNames);



return valueNames;




}



public Enumeration getAttributeNames() {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



Hashtable valuesClone = (Hashtable)values.clone();



return (Enumeration)valuesClone.keys();


}




/**


* @deprecated


*/



public void removeValue(String name) {


removeAttribute(name);


}



public void removeAttribute(String name) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (name == null) {


String msg = sm.getString("applicationSession.value.iae");



throw new IllegalArgumentException(msg);


}



Object o = values.get(name);



if (o instanceof HttpSessionBindingListener) {


HttpSessionBindingEvent e =


new HttpSessionBindingEvent(this,name);



((HttpSessionBindingListener)o).valueUnbound(e);


}



values.remove(name);


}



public void setMaxInactiveInterval(int interval) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



inactiveInterval = interval;


}



public int getMaxInactiveInterval() {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



return inactiveInterval;


}

}



//
-----------------------------------------------------------------------





package org.apache.tomcat.session;


import org.apache.tomcat.core.*;

import org.apache.tomcat.util.StringManager;

import java.io.*;

import java.net.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;


/**


* Core implementation of a server session


*


* @author James Duncan Davidson [duncan@eng.sun.com]


* @author James Todd [gonzo@eng.sun.com]


*/


public class ServerSession {



private StringManager sm =


StringManager.getManager("org.apache.tomcat.session");


private Hashtable values = new Hashtable();


private Hashtable appSessions = new Hashtable();


private String id;


private long creationTime = System.currentTimeMillis();;


private long thisAccessTime = creationTime;


private long lastAccessed = creationTime;


private int inactiveInterval =
-
1;




ServerSession(String id) {


this.id = id;


}



public String getId() {


return id;


}



public long getCreationTime() {


return creationTime;


}



public long getLastAccessedTime() {


return lastAccessed;


}




public ApplicationSession getApplicationSession(Context context,


boolean create) {


ApplicationSession appSession =


(ApplicationSession)appSessions.get(context);



if (appSession == null && create) {



// XXX


// sync to ensure valid?




appSession = new ApplicationSession(id, this, context);


appSessions.put(context, appSession);


}



// XXX


// make sure that we haven't gone over the end of our


// inactive interval
--

if so, invalidate and create


// a new appSession




return appSession;


}




void removeApplicationSession(Context context) {


appSessions.remove(context);


}



/**


* Called by context when request comes in so that accesses and


* inactivities can be dealt with accordingly.


*/



void accessed() {


// set last accessed to thisAccessTime as it will be left over


// from the previous access



lastAccessed = thisAccessTime;


thisAccessTime = System.currentTimeMillis();




}



void validate()

void validate() {


// if we have an inactive interval, check to see if


// we've exceeded it



if (inactiveInterval !=
-
1) {


int thisInterval =


(int)(System.currentTimeMillis()
-

lastAccessed) / 1000;



if (thisInterval > inactiveInterval) {


invalidate();



ServerSessionManager ssm =


ServerSessionManager.getManager();



ssm.removeSession(this);


}


}


}



synchronized void invalidate() {


Enumeration enum = appSessions.keys();



while (enum.hasMoreElements()) {


Object key = enum.nextElement();


ApplicationSession appSession =


(ApplicationSession)appSessions.get(key);



appSession.invalidate();


}


}




public void putValue(String name, Object value) {


if (name == null) {


String msg = sm.getString("serverSession.value.iae");



throw new IllegalArgumentException(msg);


}



removeValue(name); // remove any existing binding


values.put(name, value);


}



public Object getValue(String name) {


if (name == null) {


String msg = sm.getString("serverSession.value.iae");



throw new IllegalArgumentException(msg);


}



return values.get(name);


}



public Enumeration getValueNames() {


return values.keys();


}



public void removeValue(String name) {


values.remove(name);


}



public void setMaxInactiveInterval(int interval) {


inactiveInterval = interval;


}



public int getMaxInactiveInterval() {


return inactiveInterval;


}



// XXX


// sync'd for safty
--

no other thread should be getting something


// from this while we are reaping. This isn't the most optimal


// solution for this, but we'll determine something else later.




synchronized void reap() {


Enumeration enum = appSessions.keys();



while (enum.hasMoreElements()) {


Object key = enum.nextElement();


ApplicationSession appSession =


(ApplicationSession)appSessions.get(key);



appSession.validate();


}


}

}



scattering


spread around


tangling


code in one region
addresses multiple concerns


scattering and tangling (S&T)
tend to appear together; they
describe different facets of
the same problem

;



/**


* Standard implementation of the <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 $


*/


final class StandardSession


implements HttpSession, Session {




//
----------------------------------------------
-------------

Constructors




/**


* Construct a new Session associated with the
specified Manager.


*


* @param manager The manager with which this
Session is associated


*/


public StandardSession(Manager manager) {



super();


this.manager = manager;



}



/**


* The last accessed time for this Session.


*/


private long lastAccessedTime = creationTime;




/**


* The Manager with which this Session is
associated.


*/


private Manager manager = null;




/**


* The maximum time interval, in seconds, between
client requests before


* the servlet container may invalidate this
session. A negative time


* indicates that the session should never time
out.


*/


private int maxInactiveInterval =
-
1;




/**


* Flag indicating whether this session is new or
not.


*/


private boolean isNew = true;




/**


* Flag indicating whether this session is valid
or not.


*/


private boolean isValid = false;




/**


* The string manager for this package.


*/


private StringManager sm =


StringManager.getManager("org.apache.tomcat.session")
;




/**


* The HTTP session context associated with this
session.


*/


private static HttpSessionContext sessionContext
= null;




/**


* The current accessed time for this session.


*/


private long thisAccessedTime = creationTime;







//
----------------------------------------------
-------

Session Properties




/**


* Set the creation time for this session. This
method is called by the


* Manager when an existing Session instance is
reused.


*


* @param time The new creation time


*/


public void setCreationTime(long time) {



this.creationTime = time;


this.lastAccessedTime = time;


this.thisAccessedTime = time;



}




/**


* Return the session identifier for this
session.


*/


public String getId() {



return (this.id);



}




/**


* Set the session identifier for this session.


*


* @param id The new session identifier


*/


public void setId(String id) {



if ((this.id != null) && (manager != null) &&


(manager instanceof ManagerBase))


((ManagerBase) manager).remove(this);



this.id = id;



if ((manager != null) && (manager instanceof
ManagerBase))


((ManagerBase) manager).add(this);



}




/**


* Return descriptive information about this
Session implementation and


* the corresponding version number, in the
format


*
<code>&lt;description&gt;/&lt;version&gt;</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 (this.lastAccessedTime);



}




/**


* Return the Manager within which this Session
is valid.


*/


public Manager getManager() {



return (this.manager);



}




/**


* Set the Manager within which this Session is
valid.


*


* @param manager The new Manager


*/


public void setManager(Manager manager) {



this.manager = manager;



}




/**


* Return the maximum time interval, in seconds,
between client requests


* before the servlet container will invalidate
the session. A negative


* time indicates that the session should never
time out.


*


* @exception IllegalStateException if this
method is called on


* an invalidated session


*/


public int getMaxInactiveInterval() {



return (this.maxInactiveInterval);






/**


* Update the accessed time information for this session.
This method


* should be called by the context when a request comes in
for a particular


* session, even if the application does not reference it.


*/


public void access() {



this.lastAccessedTime = this.thisAccessedTime;


this.thisAccessedTime = System.currentTimeMillis();


this.isNew=false;


}




/**


* Perform the internal processing required to invalidate
this session,


* without triggering an exception if the session has
already expired.


*/


public void expire() {



// Remove this session from our manager's active
sessions


if ((manager != null) && (manager instanceof
ManagerBase))


((ManagerBase) manager).remove(this);



// Unbind any objects associated with this session


Vector results = new Vector();


Enumeration attrs = getAttributeNames();


while (attrs.hasMoreElements()) {


String attr = (String) attrs.nextElement();


results.addElement(attr);


}


Enumeration names = results.elements();


while (names.hasMoreElements()) {


String name = (String) names.nextElement();


removeAttribute(name);


}



// Mark this session as invalid


setValid(false);



}




/**



}




/**


* Set the <code>isNew</code> flag for this session.


*


* @param isNew The new value for the <code>isNew</code>
flag


*/


void setNew(boolean isNew) {



this.isNew = isNew;



}




/**


* Set the <code>isValid</code> flag for this session.


*


* @param isValid The new value for the
<code>isValid</code> flag


*/


void setValid(boolean isValid) {



this.isValid = isValid;


}




//
-------------------------------------------------

HttpSession Properties




/**


* Return the time when this session was created, in
milliseconds since


* midnight, January 1, 1970 GMT.


*


* @exception IllegalStateException if this method is
called on an


* invalidated session


*/


public long getCreationTime() {



return (this.creationTime);



}




/**


* Return the session context with which this session is
associated.


*


* @deprecated As of Version 2.1, this method is deprecated
and has no


* replacement. It will be removed in a future version of
the


* Java Servlet API.


*/


public HttpSessionContext getSessionContext() {



if (sessionContext == null)


sessionContext = new StandardSessionContext();


return (sessionContext);



}




//
----------------------------------------------
HttpSession Public Methods




/**


* Return the object bound with the specified name in this
session, or


* <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) {



return (attributes.get(name));



}




/**


* 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() {



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 (getAttribute(name));



}




/**


* Return the set of names of objects bound to this
session. If there


* are no such objects, a zero
-
length array is returned.


*


* @exception IllegalStateException if this method is
called on an


* invalidated session


*


* @deprecated As of Version 2.2, this method is replaced
by


* <code>getAttributeNames()</code>


*/


public String[] getValueNames() {



Vector results = new Vector();


Enumeration attrs = getAttributeNames();


while (attrs.hasMoreElements()) {


String attr = (String) attrs.nextElement();


results.addElement(attr);


}


String names[] = new String[results.size()];


for (int i = 0; i < names.length; i++)


names[i] = (String) results.elementAt(i);


return (names);



}




/**


* Invalidates this session and unbinds any objects bound
to it.


*


* @exception IllegalStateException if this method is
called on


* an invalidated session


*/


public void invalidate() {



// Cause this session to expire


expire();



}




/**


* Return <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() {



return (this.isNew);



}



* Remove the object bound with the specified name from this session. If


* the session does not have an object bound with this name, this method


* does nothing.


* <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) {



synchronized (attributes) {


Object object = attributes.get(name);


if (object == null)


return;


attributes.remove(name);


// System.out.println( "Removing attribute " + name );


if (object instanceof HttpSessionBindingListener) {


((HttpSessionBindingListener) object).valueUnbound


(new HttpSessionBindingEvent((HttpSession) this, name));


}


}



}


* Bind an object to this session, using the specified name. If an object


* of the same name is already bound to this session, the object is


* replaced.


* <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) {



if ((manager != null) && manager.getDistributable() &&


!(value instanceof Serializable))


throw new IllegalArgumentException


(sm.getString("standardSession.setAttribute.iae"));



synchronized (attributes) {


removeAttribute(name);


attributes.put(name, value);


if (value instanceof HttpSessionBindingListener)


((HttpSessionBindingListener) value).valueBound


(new HttpSessionBindingEvent((HttpSession) this, name));


}



}




//
--------------------------------------------

HttpSession Private Methods




/**


* Read a serialized version of this session object from the specified


* object input stream.


* <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 {



// Deserialize the scalar instance variables (except Manager)


creationTime = ((Long) stream.readObject()).longValue();


id = (String) stream.readObject();


lastAccessedTime = ((Long) stream.readObject()).longValue();


maxInactiveInterval = ((Integer) stream.readObject()).intValue();


isNew = ((Boolean) stream.readObject()).booleanValue();


isValid = ((Boolean) stream.readObject()).booleanValue();



// Deserialize the attribute count and attribute values


int n = ((Integer) stream.readObject()).intValue();


for (int i = 0; i < n; i++) {


String name = (String) stream.readObject();


Object value = (Object) stream.readObject();


attributes.put(name, value);


}



}




/**


* Write a serialized version of this session object to the specified


* object output stream.


* <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 {



// Write the scalar instance variables (except Manager)


stream.writeObject(new Long(creationTime));


stream.writeObject(id);


stream.writeObject(new Long(lastAccessedTime));


stream.writeObject(new Integer(maxInactiveInterval));


stream.writeObject(new Boolean(isNew));


stream.writeObject(new Boolean(isValid));



// Accumulate the names of serializable attributes


Vector results = new Vector();


Enumeration attrs = getAttributeNames();


while (attrs.hasMoreElements()) {


String attr = (String) attrs.nextElement();


Object value = attributes.get(attr);


if (value instanceof Serializable)


results.addElement(attr);


}



// Serialize the attribute count and the attribute values


stream.writeObject(new Integer(results.size()));


Enumeration names = results.elements();


while (names.hasMoreElements()) {


String name = (String) names.nextElement();


stream.writeObject(name);


stream.writeObject(attributes.get(name));


}




}




crosscut invalidate(StandardSession s): s & (int getMaxInactiveInterval() |


long getCreationTime() |


Object getAttribute(String) |


Enumeration getAttributeNames() |


String[] getValueNames() |


void invalidate() |


boolean isNew() |


void removeAttribute(String) |


void setAttribute(String, Object));




static advice(StandardSession s): invalidate(s) {


before {


if (!s.isValid())


throw new IllegalStateException


(s.sm.getString("standardSession."


+ thisJoinPoint.methodName


+ ".ise"));


}


}









}



//
--------------------------------------------------------------

Private Class



/**


* This class is a dummy implementation of the <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.


*/


final class StandardSessionContext implements HttpSessionContext {




private Vector dummy = new Vector();



/**


* Return the session identifiers of all sessions defined


* within this context.


*


* @deprecated As of Java Servlet API 2.1 with no replacement.


* This method must return an empty <code>Enumeration</code>


* and will be removed in a future version of the API.


*/


public Enumeration getIds() {



return (dummy.elements());



}




/**


* 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) {



return (null);



}



}




© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

good modularity


private long lastAccessed = creationTime;


private int inactiveInterval =
-
1;



void accessed() {


// set last accessed to thisAccessTime as it will be left over


// from the previous access


lastAccessed = thisAccessTime;


thisAccessTime = System.currentTimeMillis();



validate();


}



void validate() {


// if we have an inactive interval, check to see if we've exceeded
it


if (inactiveInterval !=
-
1) {


int thisInterval =


(int)(System.currentTimeMillis()
-

lastAccessed) / 1000;



if (thisInterval > inactiveInterval) {


invalidate();


}


}


}



public long getLastAccessedTime() {


if (valid) {


return lastAccessed;


} else {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}


}




public long getLastAccessedTime() {


return lastAccessed;


}




private long lastAccessed = creationTime;



void accessed() {


// set last accessed to thisAccessTime as it will be left over


// from the previous access



lastAccessed = thisAccessTime;


thisAccessTime = System.currentTimeMillis();




}

if (inactiveInterval !=
-
1) {


int thisInterval =


(int)(System.currentTimeMillis()
-

lastAccessed) / 1000;



if (thisInterval > inactiveInterval) {


invalidate();



ServerSessionManager ssm =


ServerSessionManager.getManager();



ssm.removeSession(this);


}


}


}



private long lastAccessedTime = creationTime;





/**


* Return the last time the client sent a request
associated with this


* session, as the number of milliseconds since midnight,
January 1, 1970


* GMT. Actions that your application takes, such as
getting or setting


* a value associated with the session, do not affect the
access time.


*/


public long getLastAccessedTime() {



return (this.lastAccessedTime);



}




this.lastAccessedTime = time;

/*


* ====================================================================


*


* The Apache Software License, Version 1.1


*


* Copyright (c) 1999 The Apache Software Foundation. All rights


* reserved.


*


* Redistribution and use in source and binary forms, with or without


* modification, are permitted provided that the following conditions


* are met:


*


* 1. Redistributions of source code must retain the above copyright


* notice, this list of conditions and the following disclaimer.


*


* 2. Redistributions in binary form must reproduce the above copyright


* notice, this list of conditions and the following disclaimer in


* the documentation and/or other materials provided with the


* distribution.


*


* 3. The end
-
user documentation included with the redistribution, if


* any, must include the following acknowlegement:


* "This product includes software developed by the


* Apache Software Foundation (http://www.apache.org/)."


* Alternately, this acknowlegement may appear in the software

itself,


* if and wherever such third
-
party acknowlegements normally appear.


*


* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software


* Foundation" must not be used to endorse or promote products

derived


* from this software without prior written permission. For written


* permission, please contact apache@apache.org.


*


* 5. Products derived from this software may not be called "Apache"


* nor may "Apache" appear in their names without prior written


* permission of the Apache Group.


*


* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED


* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES


* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE


* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR


* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,


* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT


* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF


* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND


* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,


* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT


* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF


* SUCH DAMAGE.


* ====================================================================


*


* This software consists of voluntary contributions made by many


* individuals on behalf of the Apache Software Foundation. For more


* information on the Apache Software Foundation, please see


* <http://www.apache.org/>.


*


* [Additional notices, if required by prior licensing conditions]


*


*/




package org.apache.tomcat.session;


import org.apache.tomcat.core.*;

import org.apache.tomcat.util.StringManager;

import java.io.*;

import java.net.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;


/**


* Core implementation of an application level session


*


* @author James Duncan Davidson [duncan@eng.sun.com]


* @author Jason Hunter [jch@eng.sun.com]


* @author James Todd [gonzo@eng.sun.com]


*/


public class ApplicationSession implements HttpSession {



private StringManager sm =


StringManager.getManager("org.apache.tomcat.session");


private Hashtable values = new Hashtable();


private String id;


private ServerSession serverSession;


private Context context;


private long creationTime = System.currentTimeMillis();;


private long thisAccessTime = creationTime;

private boolean valid = true;



ApplicationSession(String id, ServerSession serverSession,


Context context) {


this.serverSession = serverSession;


this.context = context;


this.id = id;



this.inactiveInterval = context.getSessionTimeOut();



if (this.inactiveInterval !=
-
1) {


this.inactiveInterval *= 60;


}


}



ServerSession getServerSession() {


return serverSession;


}



/**


* Called by context when request comes in so that accesses and


* inactivities can be dealt with accordingly.


*/





// HTTP SESSION IMPLEMENTATION METHODS




public String getId() {


if (valid) {


return id;


} else {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}


}



public long getCreationTime() {


if (valid) {


return creationTime;


} else {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}


}




/**


*


* @deprecated


*/



public HttpSessionContext getSessionContext() {


return new SessionContextImpl();


}



public void invalidate() {


serverSession.removeApplicationSession(context);



// remove everything in the session



Enumeration enum = values.keys();


while (enum.hasMoreElements()) {


String name = (String)enum.nextElement();


removeValue(name);


}



valid = false;


}



public boolean isNew() {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (thisAccessTime == creationTime) {


return true;


} else {


return false;


}


}





/**


* @deprecated


*/



public void putValue(String name, Object value) {


setAttribute(name, value);


}



public void setAttribute(String name, Object value) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (name == null) {


String msg = sm.getString("applicationSession.value.iae");



throw new IllegalArgumentException(msg);


}



removeValue(name); // remove any existing binding



if (value != null && value instanceof HttpSessionBindingListener) {


HttpSessionBindingEvent e =


new HttpSessionBindingEvent(this, name);



((HttpSessionBindingListener)value).valueBound(e);


}



values.put(name, value);


}



/**


* @deprecated


*/


public Object getValue(String name) {


return getAttribute(name);


}



public Object getAttribute(String name) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (name == null) {


String msg = sm.getString("applicationSession.value.iae");



throw new IllegalArgumentException(msg);


}



return values.get(name);


}



/**


* @deprecated


*/


public String[] getValueNames() {


Enumeration e = getAttributeNames();


Vector names = new Vector();



while (e.hasMoreElements()) {


names.addElement(e.nextElement());


}



String[] valueNames = new String[names.size()];



names.copyInto(valueNames);



return valueNames;




}



public Enumeration getAttributeNames() {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



Hashtable valuesClone = (Hashtable)values.clone();



return (Enumeration)valuesClone.keys();


}




/**


* @deprecated


*/



public void removeValue(String name) {


removeAttribute(name);


}



public void removeAttribute(String name) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



if (name == null) {


String msg = sm.getString("applicationSession.value.iae");



throw new IllegalArgumentException(msg);


}



Object o = values.get(name);



if (o instanceof HttpSessionBindingListener) {


HttpSessionBindingEvent e =


new HttpSessionBindingEvent(this,name);



((HttpSessionBindingListener)o).valueUnbound(e);


}



values.remove(name);


}



public void setMaxInactiveInterval(int interval) {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



inactiveInterval = interval;


}



public int getMaxInactiveInterval() {


if (! valid) {


String msg = sm.getString("applicationSession.session.ise");



throw new IllegalStateException(msg);


}



return inactiveInterval;


}

}



//
-----------------------------------------------------------------------





package org.apache.tomcat.session;


import org.apache.tomcat.core.*;

import org.apache.tomcat.util.StringManager;

import java.io.*;

import java.net.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;


/**


* Core implementation of a server session


*


* @author James Duncan Davidson [duncan@eng.sun.com]


* @author James Todd [gonzo@eng.sun.com]


*/


public class ServerSession {



private StringManager sm =


StringManager.getManager("org.apache.tomcat.session");


private Hashtable values = new Hashtable();


private Hashtable appSessions = new Hashtable();


private String id;


private long creationTime = System.currentTimeMillis();;


private long thisAccessTime = creationTime;


private long lastAccessed = creationTime;


private int inactiveInterval =
-
1;




ServerSession(String id) {


this.id = id;


}



public String getId() {


return id;


}



public long getCreationTime() {


return creationTime;


}



public long getLastAccessedTime() {


return lastAccessed;


}




public ApplicationSession getApplicationSession(Context context,


boolean create) {


ApplicationSession appSession =


(ApplicationSession)appSessions.get(context);



if (appSession == null && create) {



// XXX


// sync to ensure valid?




appSession = new ApplicationSession(id, this, context);


appSessions.put(context, appSession);


}



// XXX


// make sure that we haven't gone over the end of our


// inactive interval
--

if so, invalidate and create


// a new appSession




return appSession;


}




void removeApplicationSession(Context context) {


appSessions.remove(context);


}



/**


* Called by context when request comes in so that accesses and


* inactivities can be dealt with accordingly.


*/




void validate()

ynchronized void invalidate() {


Enumeration enum = appSessions.keys();



while (enum.hasMoreElements()) {


Object key = enum.nextElement();


ApplicationSession appSession =


(ApplicationSession)appSessions.get(key);



appSession.invalidate();


}


}




public void putValue(String name, Object value) {


if (name == null) {


String msg = sm.getString("serverSession.value.iae");



throw new IllegalArgumentException(msg);


}



removeValue(name); // remove any existing binding


values.put(name, value);


}



public Object getValue(String name) {


if (name == null) {


String msg = sm.getString("serverSession.value.iae");



throw new IllegalArgumentException(msg);


}



return values.get(name);


}



public Enumeration getValueNames() {


return values.keys();


}



public void removeValue(String name) {


values.remove(name);


}



public void setMaxInactiveInterval(int interval) {


inactiveInterval = interval;


}



public int getMaxInactiveInterval() {


return inactiveInterval;


}



// XXX


// sync'd for safty
--

no other thread should be getting something


// from this while we are reaping. This isn't the most optimal


// solution for this, but we'll determine something else later.




synchronized void reap() {


Enumeration enum = appSessions.keys();



while (enum.hasMoreElements()) {


Object key = enum.nextElement();


ApplicationSession appSession =


(ApplicationSession)appSessions.get(key);



appSession.validate();


}


}

}



;



/**


* Standard implementation of the <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 $


*/


final class StandardSession


implements HttpSession, Session {




//
----------------------------------------------
-------------

Constructors




/**


* Construct a new Session associated with the
specified Manager.


*


* @param manager The manager with which this
Session is associated


*/


public StandardSession(Manager manager) {



super();


this.manager = manager;



}



/**


* The last accessed time for this Session.


*/


private long lastAccessedTime = creationTime;




/**


* The Manager with which this Session is
associated.


*/


private Manager manager = null;




/**


* The maximum time interval, in seconds, between
client requests before


* the servlet container may invalidate this
session. A negative time


* indicates that the session should never time
out.


*/


private int maxInactiveInterval =
-
1;




/**


* Flag indicating whether this session is new or
not.


*/


private boolean isNew = true;




/**


* Flag indicating whether this session is valid
or not.


*/


private boolean isValid = false;




/**


* The string manager for this package.


*/


private StringManager sm =


StringManager.getManager("org.apache.tomcat.session")
;




/**


* The HTTP session context associated with this
session.


*/


private static HttpSessionContext sessionContext
= null;




/**


* The current accessed time for this session.


*/


private long thisAccessedTime = creationTime;







//
----------------------------------------------
-------

Session Properties




/**


* Set the creation time for this session. This
method is called by the


* Manager when an existing Session instance is
reused.


*


* @param time The new creation time


*/


public void setCreationTime(long time) {



this.creationTime = time;


this.lastAccessedTime = time;


this.thisAccessedTime = time;



}




/**


* Return the session identifier for this
session.


*/


public String getId() {



return (this.id);



}




/**


* Set the session identifier for this session.


*


* @param id The new session identifier


*/


public void setId(String id) {



if ((this.id != null) && (manager != null) &&


(manager instanceof ManagerBase))


((ManagerBase) manager).remove(this);



this.id = id;



if ((manager != null) && (manager instanceof
ManagerBase))


((ManagerBase) manager).add(this);



}




/**


* Return descriptive information about this
Session implementation and


* the corresponding version number, in the
format


*
<code>&lt;description&gt;/&lt;version&gt;</code>.


*/


public String getInfo() {



return (this.info);



}


/**


* Return the Manager within which this Session
is valid.


*/


public Manager getManager() {



return (this.manager);



}




/**


* Set the Manager within which this Session is
valid.


*


* @param manager The new Manager


*/


public void setManager(Manager manager) {



this.manager = manager;



}




/**


* Return the maximum time interval, in seconds,
between client requests


* before the servlet container will invalidate
the session. A negative


* time indicates that the session should never
time out.


*


* @exception IllegalStateException if this
method is called on


* an invalidated session


*/


public int getMaxInactiveInterval() {



return (this.maxInactiveInterval);






/**


* Perform the internal processing required to invalidate
this session,


* without triggering an exception if the session has
already expired.


*/


public void expire() {



// Remove this session from our manager's active
sessions


if ((manager != null) && (manager instanceof
ManagerBase))


((ManagerBase) manager).remove(this);



// Unbind any objects associated with this session


Vector results = new Vector();


Enumeration attrs = getAttributeNames();


while (attrs.hasMoreElements()) {


String attr = (String) attrs.nextElement();


results.addElement(attr);


}


Enumeration names = results.elements();


while (names.hasMoreElements()) {


String name = (String) names.nextElement();


removeAttribute(name);


}



// Mark this session as invalid


setValid(false);



}




/**



}




/**


* Set the <code>isNew</code> flag for this session.


*


* @param isNew The new value for the <code>isNew</code>
flag


*/


void setNew(boolean isNew) {



this.isNew = isNew;



}




/**


* Set the <code>isValid</code> flag for this session.


*


* @param isValid The new value for the
<code>isValid</code> flag


*/


void setValid(boolean isValid) {



this.isValid = isValid;


}




//
-------------------------------------------------

HttpSession Properties




/**


* Return the time when this session was created, in
milliseconds since


* midnight, January 1, 1970 GMT.


*


* @exception IllegalStateException if this method is
called on an


* invalidated session


*/


public long getCreationTime() {



return (this.creationTime);



}




/**


* Return the session context with which this session is
associated.


*


* @deprecated As of Version 2.1, this method is deprecated
and has no


* replacement. It will be removed in a future version of
the


* Java Servlet API.


*/


public HttpSessionContext getSessionContext() {



if (sessionContext == null)


sessionContext = new StandardSessionContext();


return (sessionContext);



}




//
----------------------------------------------
HttpSession Public Methods




/**


* Return the object bound with the specified name in this
session, or


* <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) {



return (attributes.get(name));



}




/**


* 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() {



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 (getAttribute(name));



}




/**


* Return the set of names of objects bound to this
session. If there


* are no such objects, a zero
-
length array is returned.


*


* @exception IllegalStateException if this method is
called on an


* invalidated session


*


* @deprecated As of Version 2.2, this method is replaced
by


* <code>getAttributeNames()</code>


*/


public String[] getValueNames() {



Vector results = new Vector();


Enumeration attrs = getAttributeNames();


while (attrs.hasMoreElements()) {


String attr = (String) attrs.nextElement();


results.addElement(attr);


}


String names[] = new String[results.size()];


for (int i = 0; i < names.length; i++)


names[i] = (String) results.elementAt(i);


return (names);



}




/**


* Invalidates this session and unbinds any objects bound
to it.


*


* @exception IllegalStateException if this method is
called on


* an invalidated session


*/


public void invalidate() {



// Cause this session to expire


expire();



}




/**


* Return <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() {



return (this.isNew);



}



* Remove the object bound with the specified name from this session. If


* the session does not have an object bound with this name, this method


* does nothing.


* <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) {



synchronized (attributes) {


Object object = attributes.get(name);


if (object == null)


return;


attributes.remove(name);


// System.out.println( "Removing attribute " + name );


if (object instanceof HttpSessionBindingListener) {


((HttpSessionBindingListener) object).valueUnbound


(new HttpSessionBindingEvent((HttpSession) this, name));


}


}



}


* Bind an object to this session, using the specified name. If an object


* of the same name is already bound to this session, the object is


* replaced.


* <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) {



if ((manager != null) && manager.getDistributable() &&


!(value instanceof Serializable))


throw new IllegalArgumentException


(sm.getString("standardSession.setAttribute.iae"));



synchronized (attributes) {


removeAttribute(name);


attributes.put(name, value);


if (value instanceof HttpSessionBindingListener)


((HttpSessionBindingListener) value).valueBound


(new HttpSessionBindingEvent((HttpSession) this, name));


}



}




//
--------------------------------------------

HttpSession Private Methods




/**


* Read a serialized version of this session object from the specified


* object input stream.


* <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 {



// Deserialize the scalar instance variables (except Manager)


creationTime = ((Long) stream.readObject()).


isValid = ((Boolean) stream.readObject()).booleanValue();



// Deserialize the attribute count and attribute values


int n = ((Integer) stream.readObject()).intValue();


for (int i = 0; i < n; i++) {


String name = (String) stream.readObject();


Object value = (Object) stream.readObject();


attributes.put(name, value);


}



}




/**


* Write a serialized version of this session object to the specified


* object output stream.


* <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 {



// Write the scalar instance variables (except Manager)


stream.writeObject(new Long(creationTime));


stream.writeObject(id);


stream.writeObject(new Long(lastAccessedTime));


stream.writeObject(new Integer(maxInactiveInterval));


stream.writeObject(new Boolean(isNew));


stream.writeObject(new Boolean(isValid));



// Accumulate the names of serializable attributes


Vector results = new Vector();


Enumeration attrs = getAttributeNames();


while (attrs.hasMoreElements()) {


String attr = (String) attrs.nextElement();


Object value = attributes.get(attr);


if (value instanceof Serializable)


results.addElement(attr);


}



// Serialize the attribute count and the attribute values


stream.writeObject(new Integer(results.size()));


Enumeration names = results.elements();


while (names.hasMoreElements()) {


String name = (String) names.nextElement();


stream.writeObject(name);


stream.writeObject(attributes.get(name));


}




}




crosscut invalidate(StandardSession s): s & (int getMaxInactiveInterval() |


long getCreationTime() |


Object getAttribute(String) |


Enumeration getAttributeNames() |


String[] getValueNames() |


void invalidate() |


boolean isNew() |


void removeAttribute(String) |


void setAttribute(String, Object));




static advice(StandardSession s): invalidate(s) {


before {


if (!s.isValid())


throw new IllegalStateException


(s.sm.getString("standardSession."


+ thisJoinPoint.methodName


+ ".ise"));


}


}









}



//
--------------------------------------------------------------

Private Class



/**


* This class is a dummy implementation of the <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.


*/


final class StandardSessionContext implements HttpSessionContext {




private Vector dummy = new Vector();



/**


* Return the session identifiers of all sessions defined


* within this context.


*


* @deprecated As of Java Servlet API 2.1 with no replacement.


* This method must return an empty <code>Enumeration</code>


* and will be removed in a future version of the API.


*/


public Enumeration getIds() {



return (dummy.elements());



}




/**


* 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) {



return (null);



}



}




separated


implementation
of a concern can be treated
as relatively separate entity

localized


implementation
of a concern appears in one
part of program

modular


above + has a
clear, well defined interface
to rest of system

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

do we help with this problem?


:


System.out.println("foo called");


Helper.foo(n/3);


:




:


System.out.println("foo called");


Helper.foo(i+j+k);


:




:


System.out.println("foo called");


Helper.foo(x);


:



class Helper {


:


public static void foo(int n) {







}


:

}

every call to foo

is preceded by a log call

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

not necessarily


:


System.out.println("foo called");


Helper.foo(…);


:




:


System.out.println("foo called");


Helper.foo(…);


:




:


System.out.println("foo called");


Helper.foo(…);


:



class Helper {


:


public static void foo(int n) {







}


:

}

class Helper {


:


public static void foo(int n) {


System.out.println("foo called.");





}


:

}


:


Helper.foo(n/3);


:





:


Helper.foo(i+j+k);


:





:


Helper.foo(x);


:




procedures can

modularize this case

unless logs use calling
context, we don’t control
source of Helper…

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

do we help with this problem?

2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()

refresh()

Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()

refresh()

FigureElement

moveBy(int, int)


all subclasses have an
identical method

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

not necessarily

2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()

refresh()

Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()

refresh()

FigureElement

moveBy(int, int)


2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()



Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()



FigureElement

moveBy(int, int)

refresh()

inheritance can

modularize this

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

do we help with this problem?

2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()



Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()



FigureElement

moveBy(int, int)

refresh()

these methods all end with

call to:



Display.update();

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

yes!


this is AspectJ’s fact(n)

DisplayUpdating

2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()



Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()



FigureElement

moveBy(int, int)

refresh()

after(): call(void FigureElement+.set*(..))


|| call(void FigureElement.moveBy(int, int))

{


Display.update();

}

after(): call(void FigureElement+.set*(..))


|| call(void
FigureElement.moveBy(int, int))

{


Display.update();

}

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

observations and questions


modularity (aka SOC) techniques


S&T


principle, mechanism


modular
structure


may apply across range of software artifacts


many kinds of S&T, principles, structure



S&T is not specific to AO



AO is just one modularity technique


questions to answer include:


what particular modularity problems do we address?


our particular kind of S&T?


what’s our particular principle?


procedure, object…


what’s our particular kind of structure?


block, classification hierarchy…

[Yvonne Coady AOSD 2003]

vm_fault

vm_pager_getpages

vnode_pager_getpages

ffs_getpages



ufs_bmap

path specific customization

ffs_valid

ffs_calc_size

[Coady AOSD’03]

CLASSIFYING BY

CLASSIFICATION SIBLINGS

nontree

tree

hardwood

softwood

object

plant

nestable

predator

insect

plant

nectar

plant

dandelion

dandelion

bird

bird

woodsman

woodsman

locust

maple

maple

cherry

cherry

pine

pine

object

Copyright © 1993 IBM Corporation

[Harrison, Ossher OOPSLA’93]

UBC software modularity group

[Jan Hanneman OOPSLA 2002]

observer pattern in AspectJ

FigureElement

getColor(): Color

setColor(Color)

Point

getX(): int

getY(): int

getColor():Color

setX(int)

setY(int)

setColor(Color)

Line

getP1():Point

getP2():Point

getColor():Color

setP1(Point)

setP2(Point)

setColor(Color)

Screen

display()

A Figure Element System

Observer Design Pattern

Subject

addObserver(Observer)

removeObserver(Observer)

notify()

Observer

update()

ConcreteSubject

getState()

setState()

notify()

subjectState

ConcreteObserver

update(Subject)

observerState

For all o in observers {


o.update();

}

observers

subject

observerState =


subject.getState();

[Hanneman OOPSLA’02]




setX(int)

setY(int)

setColor(Color)




setP1(Point)

setP2(Point)

setColor(Color)

Example of AOP with Composition Filters


Add synchronization constraint (mutual exclusion)

to a given list of classes


Synchronization (assertions, dispatch, ..) is expressed by

a filter of type
Wait
(
Error, Dispatch, ..
):


if the condition
NoActiveThreads

does not hold for an object,


a received message can not pass the filter,


and will be queued until it
can

pass.


filtermodule (
declarations +
filter definition) is unit of superimposition

concern
ConcurrentDocumentProcessing

// ‘concern’ unifies ‘aspect’ & ‘class’


filtermodule
MutExSync

// unit of superimposition


conditions


NoActiveThreads;

// is true when no thread is executing ‘within’ this object


inputfilters



buffer:Wait={ NoActiveThreads=>*};

// implements synchronization


end
;


... cont’d

[Aksit, Bergmans CACM AOP issue]

Copyright © 2003 Mehmet Aksit, Lodewijk Bergmans

traversals and class graphs

Copyright © 2003 MiraMezini, David Lorenz, Karl Lieberherr

[Mezini, Lorenz, Lieberherr c.'98]

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

analysis of
some

of our
accounts


tyranny of the dominant decomposition


crosscutting structure


aspect


weaving

an attempt to classify and evaluate
some of the accounts


what do they
address, strengths, weaknesses

by "account" I mean a story we tell to
explain part or all of AOSD

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

tyrannny…


describes


the problem


sometimes a single decomposition can’t localize all concerns


want
multiple decompositions


but…


exactly when does a single decomposition fail?


two decompositions? two decomposition paradigms?...

where do you file
Sacred Hoops?


fitting Line in
to
FigureElement
and Point

fitting
DisplayUpdating
in to
FigureElement,
Point and Line

vs.

DisplayUpdating

#

change

after change()

2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()



Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()



FigureElement

moveBy(int, int)

refresh()

2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()



Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()



FigureElement

moveBy(int, int)

refresh()

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

aspect


describes


entities that become local in the alternate decomposition


aspect
-
of

is different than part
-
of


wheel is a part of a car


wind resistance is an aspect of a car


DisplayUpdating is an aspect of Point & Line


when setX is called, updating happens


the prefetching optimization is an aspect of virtual memory


runs as integral part of vnode access


but…


what is the nature of the relationship exactly?


how does the alternate decomposition localize the aspect?


litmus test for a definition: discriminate between aspect and object?


how does this fit with symmetric AOP

each player vs. “great ball movement”

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

crosscutting


describes


nature of relation between decompositions


cases where a single decomposition fails


but…


what crosscuts?


concern? structure? natural structure?


crosscutting concern


concern for which natural structures
crosscut


precise definition of crosscutting?


1 to many and many to 1 correspondence (in general)


DisplayUpdating

#

change

after change()

2

Point

getX()

getY()

setX(int)

setY(int)

moveBy(int, int)

draw()



Line

getP1()

getP2()

setP1(Point)

setP2(Point)

moveBy(int, int)

draw()



FigureElement

moveBy(int, int)

refresh()

nontree

tree

hardwood

softwood

object

plant

nestable

predator

insect

plant

nectar

plant

dandelion

dandelion

bird

bird

woodsman

woodsman

locust

maple

maple

cherry

cherry

pine

pine

object

like a Fourier transform

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

join point mechanisms


describes


mechanism


coordinates (weaves) different semantic effects together at join
points


quantification and ob*** (transparency)


these accounts are the most solid


but…


“weaving” connotes source code pre
-
processing?


interleaving?


quantification connotes meta
-
programing


applicability of a technique doesn’t work to define an approach


I tried to downplay weaving, but…

systematically propagate and coordinate effects

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

summary so far

current accounts of aspect
-
orientation


problem: tyranny of single decomposition


cannot, in a single decomposition, modularize all concerns


bad modularity


brittle (non
-
adaptive), fragile, buggy mess


principle: aspects …


concerns that are local in the alternate decomposition


aspect of is different than part of


structure: crosscutting


relationship between decompositions such that


some concerns are localized (aspects)


and others are potentially spread out


mechanism: join point mechanisms


coordinates effect of programs from different decompositions

© Copyright 2003, Gregor Kiczales. All rights reserved.

the

join

point

mechanism

the claim

that this is the
community’s
main
contribution

to date

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

join point mechanisms


one ontology for JP mechanisms


the join points


a means of identifying join points


a means of semantic effect at join points

after(): call(void FigureElement+.set*(..))


|| call(void FigureElement.moveBy(int, int)) {


Display.update();

}

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003



join points

means of

identifying JPs

means of

semantic effect at JPS

AJ
dyn

points in
runtime
control flow
graph

by declaration
signature including
wildcards, lexical and
dynamic properties

execute before, after or around

AJ
static

member
signatures

by signature including
wildcards and lexical
properties

warn, error



add member

HJ

member
signatures

by signature including
wildcards and lexical
properties


extract to slice



compose


in numerous ways

DJ

CF



diversity of JP mechanisms

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003



join points

means of

identifying JPs

means of

semantic effect at JPS

AJ
dyn

points in
runtime
control flow
graph

by declaration
signature including
wildcards, lexical and
dynamic properties

execute before, after or around

AJ
static

member
signatures

by signature including
wildcards and lexical
properties

warn, error



add member

HJ

member
signatures

by signature including
wildcards and lexical
properties


extract to slice



compose


in numerous ways

DJ

diversity of JP mechanisms

AJdyn

HJ

DJ

fine

dynamic

static

coarse

???

AJstatic

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

community’s key contributions to date


have discovered the space of join point mechanisms


different kinds of join points


different kinds of means of identifying join points


different kinds of means of specifying semantics



have used this to program from multiple
decompositions


bearing a variety of simultaneous structural relationships


block, hierarchical, crosscutting

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

pointcut entry():


!within(com.acme.product..*)


&& call(public * com.acme.product..*(..));



pointcut initialEntry():


entry() && !cflowbelow(entry());



around(): initialEntry() {


<setup expensive dynamic context>


proceed();


<tear down expensive dynamic context>

}

compositional crosscutting

package structure

wrt control flow

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

join point mechanisms


but


if you add a new field color


you have to extend this pointcut


so…



after(): call(void Point.setX(int))


|| call(void Point.setY(int))


|| call(void Line.setP1(Point))


|| call(void Line.setP2(Point))


|| call(void FigureElement.moveBy(int, int)) {


Display.update();

}

it is still it is better than without AOP

the dependence is explicit, localized, modular clear
declarative interface

(the structure of the crosscutting concern is explicit)

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

a more precise means of identifying JPs


robust against some edits


the abstraction of the pointcut is now more clear


but


if you add a field that doesn’t have a set method


you still have to update the pointcut


so…


you could solve this problem by prohibiting wildcards?


you could solve this problem by requiring tags on methods?


NO! solve it by making the means of identifying JPs more precise

after(): call(void FigureElement+.set*(..))


|| call(void FigureElement.moveBy(int, int)) {


Display.update();

}

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

idea for a more precise mechanism

predict the control flow
of FigureElement.draw()

consider HOW the dependencies are stated,

not just WHAT is depended on

sets to such fields
require display update

find fields referenced
in that control flow

pointcut* displayState():


pcflow(execution(void FigureElement+.draw())


&& get(* FigElt+.*);

after set(<displayState()>) (): {


Display.update();

}

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

other ideas…


dflow(<pointcut>, <variable>)


did the value of the variable come in a dataflow
through <pointcut>


min(<predicted
-
cflow>, <predicted
-
cflow>)


the least common caller of the two cflows



JP mechanism opens a new design space


a language design for packaging such analyses


how to think about programming with them


how to limit to tractable cases


© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

summary so far


a number of accounts help describe the space


get at different aspects of our work


none is completely satisfactory


JP mechanisms are key contribution to date


discovery of the space of join point mechanisms


using them to program from multiple decompositions


we should
increase

the power of JP mechanisms


to make means of identifying JPs more precise


to make AOP more useful


and to make AOP more principled, more robust…

© Copyright 2003, Gregor Kiczales. All rights reserved.

another
perspective

on

join

point

mechanisms

the concepts

of registration,
effectiveness
and the

middle distance
between
connection and
disconnection

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

[Smith, On the Origin of Objects
1
]


how is it that we can see the world in different ways?



registration is


process of ‘parsing’ objects out of fog of undifferentiated stuff


constantly registering and re
-
registering the world


mediates different perspectives on a changing world


enables moving in and out of connection with the world



critical properties of registration


multiple routes to reference (aliasing is inherent)


morning star, evening star


ability to exceed causal reach


person closest to average height in Gorbachev's office now


indexical reference


the one in front of him



1. On this slide, object means in the real
-
world.

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

some
program

stream of
instructions

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

pick out some of
the points and
register them into
this structure

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

and add to the
instruction
stream there

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

and add to the
instruction
stream there

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

how JP mechanisms enable crosscutting

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

JP mechanisms reconsidered


how to decompose software in different ways



register aspects out of fog of undifferentiated points


means of identifying JPs (aka pointcut) registers


aspects/slices/concerns… group over that


connect and have effect through that registration


means of semantic effect (aka advice)



critical properties of registration


multiple routes to reference


void setX(int nx) { … }, call(void setX(int)), cflow(…)


exceed causal reach


within(com.sun..*), !within(com.mycompany.mysystem)


indexical reference


cflow(…)

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

a simple bridge

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

models programs and systems

system

model

effective

abstract

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

models programs and systems

i = 1

while (i < 4) {


print(i)


i = i + 1

}

system

model

abstract

effective

programs live in
this magic space

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

models programs and systems

i = 1

while (i < 4) {


print(i)


i = i + 1

}

system

model

Brian’s account talks

(in part) about this space

abstract

effective

programs live in
this magic space

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

models programs and systems

i = 1

while (i < 4) {


print(i)


i = i + 1

}

system

model

abstract

effective

programs live in
this magic space

cc

Brian’s account talks

(in part) about this space

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

models programs and systems

i = 1

while (i < 4) {


print(i)


i = i + 1

}

system

model

abstract

effective

programs live in
this magic space

cc

Brian’s account talks

(in part) about this space

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

summary


account of JP mechanism in terms of registration


possible basis for better foundational account of AO


more interesting than objects? harder than objects?


relation among


problems, decompositions, structures, mechanisms


read On the Origin of Objects


(except it is not written in computer science vocabulary)



JP mechanism seen as


means of connecting via different decompositions


means of switching between connected and disconnected

© Copyright 2003, Gregor Kiczales. All rights reserved.

join point
mechanisms
and

software
models

what can we
do for models,
model based
development,
fluid AO

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

impact of JP mechanism on sw models


models that abstract


simple UML class diagrams


models that crosscut


patterns


UML sequence, state…


models that connect and disconnect


fluid aspect
-
orientation

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

use cases


what is the system supposed to do
for each user


the use cases crosscut the components


JP mechanism provides principled support to
organize modeling, implementation, testing…


multiple effects at a JP


identifies an interaction in the design


means for resolving the issue


traceability in the code


reasoning about composition of use cases =
reasoning about composition of aspects



Solid Palette

Gradient Palette I

Gradient Palette II

APPLYING THESE COLORS

1
.

2
.

3
.

Click on the
desired color

Click on the
paintbrush tool
located on your
toolbar

Click on the
object you
want to
colorize

Helpful tip:

Double click the
paintbrush tool
to apply color to
more than one
object at a time.

To use or remove

these color palettes, go to

View/Master/Slide Master

Optional logo for your

notes/handouts slides

Do not use Gradient fills for slides

to be used for Webinars

Use cases


use case realizations
--

components


Each use case is realized by a collaboration
-

a set of classes


A class plays different roles in different use case realizations


The total responsibility of a class is the composition of these roles

Withdraw

Cash

Deposit Funds

Transfer Funds

Cash

Withdrawal

Cash

Interface

Cash

Interface

Deposit

Funds

Transfer

Funds

Interface

Interface

Funds

Deposit

Cash

Transfer

Funds



Cash

Withdrawal

Use case

Specification

Use case

design

Component design &

implementation

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

Observer


Subject


Observer:
Display


change


update: {...}

class Point {



int x; Getter/Setter


int y;




void draw() {


Graphics.drawOval(…);


}


...

}

patterns and classes


pattern must be effective (connect to code)


‘wizards’ might weave the pattern in


brittle, hard to understand, hard to maintain


would rather preserve a structure like this

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

Observer


Subject


Observer:
Display


change


update: {...}

class Point {



int x; Getter/Setter


int y;




void draw() {


Graphics.drawOval(…);


}


...

}

patterns and classes


Observer refers to expansion of Getter/Setter


clearly, reliably, stably


alternate reference, beyond causal reach, indexical



multiple routes to reference



beyond causal reach



indexical

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

fluid AO


static aspects


crosscut, but structures themselves are fixed




fluid aspects


fluid connection and disconnection of models


models are used to edit code


non
-
effective models and domain transform idea


connect model


edit code via model


disconnect model

Extracting Latent Concerns

Regular

Tracked

name()

check()

print()

Employee

Research

CorePersonnel

name()

check()

print()

name()

check()

print()

name()

check()

print()

Regular

Tracked

tax()

pay()

Employee

Research

Payroll

tax()

pay()

tax()

pay()

tax()

pay()

package Personnel

Concern Mapping

Feature.CorePersonnel

operation tax

Feature.Payroll

operation pay

Feature.Payroll

class Employee {


String name() {...}


boolean check() {…}


void print() {…}


float tax() {...}


void pay() {…}

… }

Feature

Class

Employee

Research

Regular

Tracked



merge by name

Copyright © 2000 IBM Corporation

1.
use pointcut to identify
scattered aspect

2.
shows up below

3.
delete them all

4.
rewrite with advice

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

connected non
-
effective models


models that are not sufficiently complete to yield code


but can be used to analyze code


connect such models using JP mechanism


edit code through the model



feature analysis? [robillard, murphy]


remove features that are mixed at finer granularity


compose features


verification? testing?...



© Copyright 2003, Gregor Kiczales. All rights reserved.

summary

© Copyright 2003, Gregor Kiczales. All rights reserved.

AOSD 2003

the fun has just begun


JP mechanism is incredibly powerful and deep


connects programs/models/… with different decompositions



current
accounts

of AO are intuitively useful


more work is needed for them to be foundational


that’s not surprising, see [Smith] for some ideas on this



more fun with programming languages/tools


increase power of JP mechanisms to make languages/tools


more practical, more useful, more principled


more fun with models


patterns, use cases, more abstract models



it’s a technology of connection across different perspectives


can bridge across software development process???