Download presentation
Presentation is loading. Please wait.
Published byTrevor Taylor Modified over 9 years ago
1
An Approach for Supporting Aspect-Oriented Domain Modeling GPCE 2003 – Erfurt, Germany September 24, 2003 Jeff Gray, Ted Bapty, Sandeep Neema, Doug Schmidt, Andy Gokhale and Bala Natarajan gray (at) cis.uab.edu http://www.gray-area.org This research is funded by DARPA/IXO, under the PCES program. University of Alabama at Birmingham Vanderbilt University
2
Multiple Levels of Hierarchy Replicated Structures Context Sensitive Motivating Problem – Crossccuting Constraints in Real-Time/Embedded Models Base models become constrained to capture a particular design A B cde B cde F B cde Changeability??? Crosscutting Constraints Constraints that are related to some global property are dispersed across the model
3
Importance of Changeability in Modeling Modeling’s key advantage: Ability to rapidly explore “what-if” design alternatives Changeability a metric for modularity: “The way to evaluate a modular decomposition…is to ask what changes it accommodates.” David Weiss, chapter preface in Software Fundamentals Ensure benefit of model-driven approach: “Small changes in requirements entail large changes in the structure and configuration” Gerald Jay Sussman, “Robust Design through Diversity,” DARPA Amorphous Computing Workshop, 1999.
4
Motivation Summary Key Problems: Difficult to specify and manage cross-cutting concerns (e.g., constraints) in model-based systems Lack of tool support for automatically weaving concerns into models Our Solution: A meta framework that assists in the construction of model weavers, capable of rapidly dispersing global concerns across a design space; not just notational Constraint-Specification Aspect Weaver http://www.gray-area.org/Research/C-SAW
5
Modeling Context: MIC/GME META-MODEL Meta-Model of Stateflow using UML/OCL as meta-modeling language. DOMAIN-MODEL Model instance of Stateflow C++ Model interpreter 2 FPGA Model interpreter 3 Key focus of this paper: Weaving of high-level concerns into domain model Framework for creating new weavers for each meta-model Matlab Model interpreter 1
6
Process of Using a Model Weaver GME Domain-Specific Weaver bit1 bit1 Structural ProcessingCompound GatesPerBit 37,153 NomBits 205,76 MaxBits 128,76 Enhanced FOO.XML bit1 bit1 Structural ProcessingCompound GatesPerBit 37,153 NomBits 205,76 MaxBits 128,76 FOO.XML constraint FOOB2 { // apply a specific constraint to “B2” only in Structural models("ProcessingCompound")-> select(p | p.name() == "B2")->PowerStrategy(1, 100); } constraint FOOBStar { // apply a specific constraint to all nodes beginning with “B” - use wildcard in Structural models("ProcessingCompound")-> select(p | p.name() == "B*")->PowerStrategy(1, 100); } Modeling Pointcuts
7
Comp1 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(); } Quantification Over Base Code pointcut pubIntf(Object o): call(public * com.borland.*.*(..)) && target(o); after(Object o) throwing (Error e): pubIntf(o) { log.write(o, e); … } after(Object o) throwing (Error e): pubIntf(o) { log.write(o, e); … } Comp2 package org.apache.tomcat.session; import org.apache.tomcat.util.*; import org.apache.tomcat.core.*; import java.io.*; import java.net.*; import java.util.*; import javax.servlet.http.*; /** * * @author James Duncan Davidson [duncan@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] */ public class ServerSessionManager implements SessionManager { private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); private static ServerSessionManager manager; // = new ServerSessionManager(); protected int inactiveInterval = -1; static { manager = new ServerSessionManager(); } public static ServerSessionManager getManager() { return manager; } private Hashtable sessions = new Hashtable(); private Reaper reaper; private ServerSessionManager() { reaper = Reaper.getReaper(); reaper.setServerSessionManager(this); reaper.start(); } public void accessed( Context ctx, Request req, String id ) { ApplicationSession apS=(ApplicationSession)findSession( ctx, id); if( apS==null) return; ServerSession servS=apS.getServerSession(); servS.accessed(); apS.accessed(); // cache it - no need to compute it again req.setSession( apS ); } public HttpSession createSession(Context ctx) { String sessionId = SessionIdGenerator.generateId(); ServerSession session = new ServerSession(sessionId); sessions.put(sessionId, session); if(-1 != inactiveInterval) { session.setMaxInactiveInterval(inactiveInterval); } 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); } // XXX // sync'd for safty -- no other thread should be getting something // from this while we are reaping. This isn't the most optimal // solution for this, but we'll determine something else later. synchronized void reap() { Enumeration enum = sessions.keys(); while (enum.hasMoreElements()) { Object key = enum.nextElement(); ServerSession session = (ServerSession)sessions.get(key); session.reap(); session.validate(); } synchronized void removeSession(ServerSession session) { String id = session.getId(); session.invalidate(); sessions.remove(id); } public void removeSessions(Context context) { Enumeration enum = sessions.keys(); while (enum.hasMoreElements()) { Object key = enum.nextElement(); ServerSession session = (ServerSession)sessions.get(key); ApplicationSession appSession = session.getApplicationSession(context, false); if (appSession != null) { appSession.invalidate(); } /** * 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... inactiveInterval = (minutes * 60); } Comp1 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(); } Comp2 package org.apache.tomcat.session; import org.apache.tomcat.util.*; import org.apache.tomcat.core.*; import java.io.*; import java.net.*; import java.util.*; import javax.servlet.http.*; /** * * @author James Duncan Davidson [duncan@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] */ public class ServerSessionManager implements SessionManager { private StringManager sm = StringManager.getManager("org.apache.tomcat.session"); private static ServerSessionManager manager; // = new ServerSessionManager(); protected int inactiveInterval = -1; static { manager = new ServerSessionManager(); } public static ServerSessionManager getManager() { return manager; } private Hashtable sessions = new Hashtable(); private Reaper reaper; private ServerSessionManager() { reaper = Reaper.getReaper(); reaper.setServerSessionManager(this); reaper.start(); } public void accessed( Context ctx, Request req, String id ) { ApplicationSession apS=(ApplicationSession)findSession( ctx, id); if( apS==null) return; ServerSession servS=apS.getServerSession(); servS.accessed(); apS.accessed(); // cache it - no need to compute it again req.setSession( apS ); } public HttpSession createSession(Context ctx) { String sessionId = SessionIdGenerator.generateId(); ServerSession session = new ServerSession(sessionId); sessions.put(sessionId, session); if(-1 != inactiveInterval) { session.setMaxInactiveInterval(inactiveInterval); } 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); } // XXX // sync'd for safty -- no other thread should be getting something // from this while we are reaping. This isn't the most optimal // solution for this, but we'll determine something else later. synchronized void reap() { Enumeration enum = sessions.keys(); while (enum.hasMoreElements()) { Object key = enum.nextElement(); ServerSession session = (ServerSession)sessions.get(key); session.reap(); session.validate(); } synchronized void removeSession(ServerSession session) { String id = session.getId(); session.invalidate(); sessions.remove(id); } public void removeSessions(Context context) { Enumeration enum = sessions.keys(); while (enum.hasMoreElements()) { Object key = enum.nextElement(); ServerSession session = (ServerSession)sessions.get(key); ApplicationSession appSession = session.getApplicationSession(context, false); if (appSession != null) { appSession.invalidate(); } /** * 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... inactiveInterval = (minutes * 60); } An AspectJ example Advice Pointcut
8
Quantification Over a Domain Model Apply AO Weaving concepts to Model-based systems Weavers ‘Decorate’ Models with attributes & constraints Weavers compose new model constructs … select(p | p.name() == “Model*” && p.kind() == “StateFlow”)->Strategy3(); … Strategy1 Strategy2 Strategy3 StrategyN Modeling Pointcut Domain-specific Strategies Model
9
Constructing Model Weavers
10
Domain-Specific Weavers + General Motors Factory GM specific weaverDuPont specific weaver DuPont Chemical Factory Boeing Bold Stroke Bold Stroke specific weaver + + Example: Evidence of “meta” in the corresponding XML of each of the above models
11
The Metaweaver Framework Strategy Code Generator Strategies (C++) Strategies Modeling Pointcuts strategy ApplyConstraint(constraintName : string, expression : string) { addAtom("OCLConstraint", "Constraint", constraintName).addAttribute("Expression", expression); } strategy RemoveConstraint(constraintName : string) { findAtom(constraintName).removeChild(); } strategy ReplaceConstraint(constraintName : string, expression : string) { RemoveConstraint(constraintName); ApplyConstraint(constraintName, expression); } XML ( Model Hierarchy )
12
Embedded Constraint Language Arithmetic Operators +, -, *, /, =,, =, <> Logical Operators and, or, xor, not, implies, if/then/else Collection Operator -> Property Operator. Standard OCL Collection Operators collection->size() : integer collection->forAll( x | f(x) ) : Boolean collection->select( x | f(x) ) : collection collection->exists( x | f(x) ) : Boolean Included OCL Operators
13
Embedded Constraint Language Traditional OCL has been strictly a declarative query language New uses require an imperative procedural style Addition of side effects into model Examples: addAtom(…), findAtom(…) addAttribute(…), findAttribute(…) removeNode(…) Support for recursion Chaining of strategies (procedure calls) Inlined C++ code
14
List of ECL Operators Aggregates folders, models, atoms, attributes, connections Connections connpoint, target, refs, resolveRefeeredID, resolveIDReferred Transformation addAttribute, addAtom, addModel, addConnection, removeNode Selection findFolder, findModel, findAtom, findAttributeNode General id, parent, getID, getInt, getStr
15
Example: Processor Assignment Weapons deployment WCET=150ms Latency < 20ms Sensor Update Map MapDB Σ (x,y,z) Display (x,y,z) 100 Hz WCET=1ms Latency < 5ms WCET=2ms WCET=4ms Weapon Release Latency < 10msLatency < 2ms
16
Processor Assignment: Component Interaction Model
17
Processor Assignment: Component Internals
18
Processor Assignment: Modeling Pointcut aspect ProcessorAssignment { models("")->select(m | m.kind() == “Comp*")->Assign(10); }
19
Processor Assignment: Strategy strategy Assign(limit : integer){ declare static accumulateWCET, processNum : integer; declare currentWCET : integer; self.compute.WCET.getInt(currentWCET); accumulateWCET := accumulateWCET + currentWCET; if (limit < accumulateWCET) then accumulateWCET := currentWCET; processNum := processNum + 1; endif; <<CComBSTR aConstraint = "self.assignTo()=processor" + XMLParser::itos(processNum); >> AddConstraint("ProcessConstraint", aConstraint); }
20
Processor Assignment: Weaved Constraint self.assignTo() = processor0 strategy Assign(limit : integer){ declare static accumulateWCET, processNum : integer; declare currentWCET : integer; self.compute.WCET.getInt(currentWCET); accumulateWCET := accumulateWCET + currentWCET; if (limit < accumulateWCET) then accumulateWCET := currentWCET; processNum := processNum + 1; endif; <<CComBSTR aConstraint = "self.assignTo()=processor" + XMLParser::itos(processNum); >> AddConstraint("ProcessConstraint", aConstraint); }
21
Code Generation Example Consider the following, which appears in an EagerLazy strategy: … components.models()->select(c | c.id() == refID)->eagerLazy(…); …
22
Code Generation Example CComPtr models0 = XMLParser::models(components, ""); nodeTypeVector selectVec1 = XMLParser::ConvertDomList(models0); nodeTypeVector selectVecTrue1 = new std::vector ; vector ::iterator itrSelect1; for(itrSelect1 = selectVec1->begin(); itrSelect1 != selectVec1->end(); itrSelect1++) { nodeType selectNode1 = (*itrSelect1); nodeType c; c = selectNode1; CComBSTR id0 = XMLParser::id(c); ClData varforward1(id0); ClData varforward2(referredID); bool varforward3 = varforward1 == varforward2; if(varforward3) selectVecTrue1->push_back(*itrSelect1); } vector ::iterator itrCollCall1; for(itrCollCall1 = selectVecTrue1->begin(); itrCollCall1 != selectVecTrue1->end(); itrCollCall1++) eagerLazy::apply(…);
23
Sample XMLParser Methods nodeType XMLParser::addAtom(nodeType self, CComBSTR kind, CComBSTR role, CComBSTR name) { return addNode(self, "atom", kind, role, name); } nodeType XMLParser::findModel(nodeType aNode, CComBSTR name) { CComBSTR bstrFind(L"./model[name=\""); bstrFind.Append(name); bstrFind.Append("\"]"); return submitXPath(aNode, bstrFind); } CComBSTR XMLParser::id(nodeType aNode) { CComBSTR res; CComPtr attr = XMLParser::findAttribute (aNode, "id"); XMLParser::getStr(attr, res); return res; }
24
Summary Strategies (C++) Meta-weaver Framework Domain-Specific Strategies strategy ApplyConstraint(constraintName : string, expression : string) { addAtom("OCLConstraint", "Constraint", constraintName).addAttribute("Expression", expression); } strategy RemoveConstraint(constraintName : string) ApplyConstraint(constraintName, expression); } Domain-specific strategies (encoded in a DSL) are used to instantiate a new model weaver Modeling Pointcuts Domain-specific Models B c d e constraint FOOB2 { // apply a specific constraint to “B2” only in Structural models("ProcessingCompound")-> // apply a specific constraint to all nodes beginning with “B” - use wildcard in Structural models("ProcessingCompound")-> select(p | p.name() == "B*")->PowerStrategy(1, 100); } Specification aspects and base model are sent through the weaver Constrained Models B c d e 1 3 2 The weaver distributes constraints across the base model New Two-level aspect weaving (see upcoming AOSD book)
25
Summary Benefits of this Approach The modeler can now perform various “what-if” scenarios using modeling constraints Impossible in previous approach Constraints can be plugged/unplugged in model Because much of the redundancy of constraint application is removed, the effect of each constraint on the global system can be better understood. This localization of constraints improves modular reasoning. Allows for the rapid construction of new domain- specific weavers Strategies are specified using a DSL Generated code is at a much lower level
26
For more information Please give us another week to upgrade site: gray (at) cis.uab.edu http://www.gray-area.org/Research/C-SAW GME (freely available): http://www.isis.vanderbilt.edu/Projects/gme/ http://www.isis.vanderbilt.edu/Projects/gme/ OMG MIC PSIG: http://mic.omg.org
27
A Concluding Quote “Even for this let us divided live…That by this separation I may give that due to thee which thou deservest alone.” William Shakespeare, Sonnet XXXIX
28
Extra slides
29
Tool Independence Requires an exposed API for accessing internal model data structures Tool-specific adapters written for each new supported tool Cadena GME MetaEdit Rose
30
Adaptive Core Weaving Engine
31
Not unlike AspectJ AJDT JBuilder Eclipse emacs Netbeans/FORTE AJDT
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.