AspectJ

advertisement
Aspect-Oriented Programming
with AspectJ™
AspectJ.org
Xerox PARC
Erik Hilsdale
Gregor Kiczales
with
Bill Griswold, Wes Isberg, Mik Kersten, Jeffrey Palm
partially funded by DARPA under contract F30602-97-C0246
this tutorial is about...
• using AOP and AspectJ to:
– improve the modularity of crosscutting concerns
• design modularity
• source code modularity
• development process
• aspects are two things:
– concerns that crosscut
– a programming construct
[design level]
[implementation level]
• enables crosscutting concerns
to be captured in modular units
• AspectJ is:
– is an aspect-oriented extension to Java™ that supports
general-purpose aspect-oriented programming
2
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
good modularity
XML parsing
• XML parsing in org.apache.tomcat
– red shows relevant lines of code
– nicely fits in one box
3
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
good modularity
URL pattern matching
• URL pattern matching in org.apache.tomcat
– red shows relevant lines of code
– nicely fits in two boxes (using inheritance)
4
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
problems like…
logging is not modularized
• where is logging in org.apache.tomcat
– red shows lines of code that handle logging
– not in just one place
– not even in a small number of places
5
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
problems like…
session expiration is not modularized
ApplicationSession
/*
* ==== ===== ==== ===== ===== ===== ===== ==== ===== ===== ===== ===== ==== ===== ==
*
* The Apach e So ftwar e Lic ense, Vers ion 1.1
*
* Copy right (c) 1999 The Apach e Sof twar e Fou ndati on. All r ight s
* rese rved.
*
* Redi strib utio n and use in so urce and binar y for ms, w ith o r wi thout
* modi ficat ion, are permi tted provi ded that the f ollow ing c ondi tions
* are met:
*
* 1. R edist ribu tions of s ource code mus t ret ain t he ab ove c opyr ight
*
n otice , th is li st of cond ition s an d the foll owing disc laim er.
*
* 2. R edist ribu tions in b inary form mus t rep roduc e the abov e co pyrig ht
*
n otice , th is li st of cond ition s an d the foll owing disc laim er in
*
t he do cume ntati on an d/or other mat erial s pro vided with the
*
d istri buti on.
*
* 3. T he en d-us er do cumen tatio n inc lude d wit h the redi strib utio n, if
*
a ny, m ust inclu de th e fol lowin g ac knowl egeme nt:
*
"Th is p roduc t inc ludes soft ware deve loped by t he
*
Ap ache Soft ware Found ation (ht tp:// www.a pache .org/ )."
*
A ltern atel y, th is ac knowl egeme nt m ay ap pear in th e sof twar e
itself,
*
i f and whe rever such thir d-par ty a cknow legem ents norma lly appea r.
*
* 4. T he na mes "The Jakar ta Pr oject ", " Tomca t", a nd "A pache Sof tware
*
F ounda tion " mus t not be u sed t o en dorse or p romot e pro duct s
derived
*
f rom t his softw are w ithou t pri or w ritte n per missi on. F or w ritte n
*
p ermis sion , ple ase c ontac t apa che@ apach e.org .
*
* 5. P roduc ts d erive d fro m thi s sof twar e may not be ca lled "Apa che"
*
n or ma y "A pache " app ear i n the ir n ames witho ut pr ior w ritt en
*
p ermis sion of t he Ap ache Group .
*
* THIS SOFT WARE IS P ROVID ED `` AS IS '' A ND AN Y EXP RESSE D OR IMPL IED
* WARR ANTIE S, I NCLUD ING, BUT N OT LI MITE D TO, THE IMPLI ED WA RRAN TIES
* OF M ERCHA NTAB ILITY AND FITNE SS FO R A PARTI CULAR PURP OSE A RE
* DISC LAIME D. IN NO EVEN T SHA LL TH E AP ACHE SOFTW ARE F OUNDA TION OR
* ITS CONTR IBUT ORS B E LIA BLE F OR AN Y DI RECT, INDI RECT, INCI DENT AL,
* SPEC IAL, EXEM PLARY , OR CONSE QUENT IAL DAMAG ES (I NCLUD ING, BUT NOT
* LIMI TED T O, P ROCUR EMENT OF S UBSTI TUTE GOOD S OR SERVI CES; LOSS OF
* USE, DATA , OR PROF ITS; OR BU SINES S IN TERRU PTION ) HOW EVER CAUS ED AN D
* ON A NY TH EORY OF L IABIL ITY, WHETH ER I N CON TRACT , STR ICT L IABI LITY,
* OR T ORT ( INCL UDING NEGL IGENC E OR OTHE RWISE ) ARI SING IN AN Y WA Y OUT
* OF T HE US E OF THIS SOFT WARE, EVEN IF ADVIS ED OF THE POSSI BILI TY OF
* SUCH DAMA GE.
* ==== ===== ==== ===== ===== ===== ===== ==== ===== ===== ===== ===== ==== ===== ==
*
* This soft ware cons ists of vo lunta ry c ontri butio ns ma de by man y
* indi vidua ls o n beh alf o f the Apac he S oftwa re Fo undat ion. For more
* info rmati on o n the Apac he So ftwar e Fo undat ion, pleas e see
* <htt p://w ww.a pache .org/ >.
*
* [Add ition al n otice s, if requ ired by p rior licen sing condi tion s]
*
*/
public void inva lidat e() {
serv erSe ssion .remo veApp licat ionS essio n(con text) ;
// r emov e eve rythi ng in the sess ion
Enum erat ion e num = valu es.ke ys() ;
whil e (e num.h asMor eElem ents( )) {
Stri ng na me = (Stri ng)en um.n extEl ement ();
remo veVal ue(na me);
}
vali d = false ;
}
pub lic b oole an is New() {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
StandardSession
package org. apac he.to mcat. sessi on;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
java. io.I OExce ption ;
java. io.O bject Input Strea m;
java. io.O bject Outpu tStre am;
java. io.S erial izabl e;
java. util .Enum erati on;
java. util .Hash table ;
java. util .Vect or;
javax .ser vlet. Servl etExc eptio n;
javax .ser vlet. http. HttpS essio n;
javax .ser vlet. http. HttpS essio nBin dingE vent;
javax .ser vlet. http. HttpS essio nBin dingL isten er;
javax .ser vlet. http. HttpS essio nCon text;
org.a pach e.tom cat.c atali na.*;
org.a pach e.tom cat.u til.S tring Mana ger;
thro w new Ille galSt ateEx cept ion(m sg);
}
if ( this Acces sTime == c reati onTi me) {
retu rn tr ue;
} el se {
retu rn fa lse;
}
}
/**
* @depr ecat ed
*/
pub lic v oid putVa lue(S tring name , Ob ject value ) {
setA ttri bute( name, valu e);
}
pub lic v oid setAt tribu te(St ring name , Obj ect v alue) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
thro w new Ille galSt ateEx cept ion(m sg);
/**
* Stan dard impl ement ation of t he <b >Ses sion< /b>
interfa ce. This obje ct is
* seri aliza ble, so t hat i t can be s tore d in
persist ent s tora ge or tran sferr ed
* to a diff eren t JVM for distr ibuta ble sessi on
support .
* <p>
* <b>I MPLEM ENTA TION NOTE< /b>: An i nsta nce o f thi s
class r epres ents both the
* inte rnal (Ses sion) and appli catio n le vel
(HttpSe ssion ) vi ew of the sessi on.
* Howe ver, beca use t he cl ass i tself is not d eclar ed
public, Java log ic ou tside
* of t he <c ode> org.a pache .tomc at.se ssio n</co de>
package cann ot c ast a n
* Http Sessi on v iew o f thi s ins tance bac k to a
Session view .
*
* @aut hor C raig R. M cClan ahan
* @ver sion $Rev ision : 1.2 $ $D ate: 2000 /05/1 5
17:54:1 0 $
*/
}
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.va lue. iae") ;
thro w new Ille galAr gumen tExc eptio n(msg );
}
remo veVa lue(n ame);
final c lass Stan dardS essio n
imp lemen ts H ttpSe ssion , Ses sion {
/**
/**
* Retur n th e <co de>Ht tpSes sion< /cod e> fo r whi ch th is
object
* is th e fa cade.
*/
pub lic H ttpS essio n get Sessi on() {
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- Session Publ ic M ethod s
/**
* Updat e th e acc essed time info rmat ion f or th is se ssion .
This me thod
* shoul d be call ed by the conte xt w hen a requ est c omes in
for a p artic ular
* sessi on, even if th e app licat ion does not r efere nce i t.
*/
pub lic v oid acces s() {
((Ht tpSes sionB indin gList ener )valu e).va lueBo und(e );
}
// R emov e thi s ses sion from our manag er's activ e
session s
// U nbin d any obje cts a ssoci ated with this sess ion
Vect or r esult s = n ew Ve ctor( );
Enum erat ion a ttrs = get Attri bute Names ();
whil e (a ttrs. hasMo reEle ments ()) {
Stri ng at tr = (Stri ng) a ttrs .next Eleme nt();
resu lts.a ddEle ment( attr) ;
}
Enum erat ion n ames = res ults. elem ents( );
whil e (n ames. hasMo reEle ments ()) {
Stri ng na me = (Stri ng) n ames .next Eleme nt();
remo veAtt ribut e(nam e);
}
thro w new Ille galSt ateEx cept ion(m sg);
}
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.va lue. iae") ;
thro w new Ille galAr gumen tExc eptio n(msg );
}
public class App licat ionSe ssion impl emen ts Ht tpSes sion {
retu rn v alues .get( name) ;
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
pri vate Hash table valu es = new H asht able( );
pri vate Stri ng id ;
pri vate Serv erSes sion serve rSess ion;
pri vate Cont ext c ontex t;
pri vate long crea tionT ime = Syst em.c urren tTime Milli s();;
pri vate long this Acces sTime = cr eati onTim e;
pri vate long last Acces sed = crea tion Time;
pri vate int inact iveIn terva l = - 1;
pri vate bool ean v alid = tru e;
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --------- Inst ance Vari ables
/**
* The c olle ction of u ser d ata a ttri butes
associa ted w ith this Sessi on.
*/
pri vate Hash table attr ibute s = n ew H ashta ble() ;
Stri ng[] valu eName s = n ew St ring [name s.siz e()];
/**
* Relea se a ll ob ject refer ences , an d ini tiali ze in stanc e
variabl es, i n
* prepa rati on fo r reu se of this obj ect.
*/
pub lic v oid recyc le() {
// R eset the insta nce v ariab les assoc iated with this
Session
attr ibut es.cl ear() ;
crea tion Time = 0L;
id = nul l;
last Acce ssedT ime = 0L;
mana ger = nul l;
maxI nact iveIn terva l = - 1;
isNe w = true;
isVa lid = fal se;
/**
* The t ime this sessi on wa s cre ated , in
millise conds sin ce mi dnigh t,
* Janua ry 1 , 197 0 GMT .
*/
pri vate long crea tionT ime = 0L;
/**
* The s essi on id entif ier o f thi s Se ssion .
*/
pri vate Stri ng id = nu ll;
/**
* @depr ecat ed
*/
pub lic S trin g[] g etVal ueNam es() {
Enum erat ion e = ge tAttr ibute Name s();
Vect or n ames = new Vect or();
App licat ionS essio n(Str ing i d, Se rver Sessi on se rverS essio n,
Cont ext conte xt) {
this .ser verSe ssion = se rverS essi on;
this .con text = con text;
this .id = id;
/**
* Descr ipti ve in forma tion descr ibin g thi s
Session impl emen tatio n.
*/
pri vate stat ic fi nal S tring info =
"Standa rdSes sion /1.0" ;
if ( this .inac tiveI nterv al != -1) {
this .inac tiveI nterv al *= 60;
pub lic E nume ratio n get Attri buteN ames () {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
}
Ser verSe ssio n get Serve rSess ion() {
retu rn s erver Sessi on;
}
thro w new Ille galSt ateEx cept ion(m sg);
}
/**
* The M anag er wi th wh ich t his S essi on is
associa ted.
*/
pri vate Mana ger m anage r = n ull;
}
/**
* Retur n th e <co de>is Valid </cod e> f lag f or th is se ssion .
*/
boo lean isVa lid() {
retu rn ( Enume ratio n)val uesCl one. keys( );
}
voi d acc esse d() {
// s et l ast a ccess ed to this Acce ssTim e as it wi ll be lef t ove r
// f rom the p revio us ac cess
last Acce ssed = thi sAcce ssTim e;
this Acce ssTim e = S ystem .curr entT imeMi llis( );
/**
* @depr ecat ed
*/
/**
* The m axim um ti me in terva l, in sec onds, betw een
client reque sts befor e
* the s ervl et co ntain er ma y inv alid ate t his
session . A nega tive time
* indic ates that the sessi on sh ould neve r tim e
out.
*/
pri vate int maxIn activ eInte rval = -1 ;
pub lic v oid remov eValu e(Str ing n ame) {
remo veAt tribu te(na me);
}
vali date ();
/**
* Flag indi catin g whe ther this sess ion i s new or
}
pub lic v oid remov eAttr ibute (Stri ng n ame) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
voi d val idat e() {
// i f we have an i nacti ve in terv al, c heck to se e if we'v e exc eeded it
if ( inac tiveI nterv al != -1) {
int thisI nterv al =
(int) (Syst em.cu rrent Time Milli s() - last Acces sed) / 10 00;
if ( (man ager != nu ll) & & man ager .getD istri butab le() &&
!( valu e ins tance of Se riali zabl e))
thro w new Ille galAr gumen tExc eptio n
(sm.g etStr ing(" stand ardS essio n.set Attri bute. iae" ));
retu rn ( this. isVal id);
}
sync hron ized (attr ibute s) {
remo veAtt ribut e(nam e);
attr ibute s.put (name , val ue);
if ( value inst anceo f Htt pSes sionB indin gList ener)
((Htt pSess ionBi nding List ener) valu e).va lueBo und
( new H ttpSe ssion Bind ingEv ent(( HttpS essio n) t his, name) );
}
/**
* Set t he < code> isNew </cod e> fl ag f or th is se ssion .
*
* @para m is New T he ne w val ue fo r th e <co de>is New</ code>
flag
*/
voi d set New( boole an is New) {
Hash tabl e val uesCl one = (Has htab le)va lues. clone ();
/**
* Calle d by cont ext w hen r eques t co mes i n so that acces ses and
* inact ivit ies c an be deal t wit h ac cordi ngly.
*/
/**
* Bind an o bject to t his s essio n, u sing the s pecif ied n ame. If an ob ject
* of th e sa me na me is alre ady b ound to t his s essio n, th e ob ject is
* repla ced.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueBou nd()< /code > on the objec t.
*
* @para m na me Na me to whic h the obj ect i s bou nd, c annot be null
* @para m va lue O bject to b e bou nd, canno t be null
*
* @exce ptio n Ill egalA rgume ntExc epti on if an a ttemp t is made to a dd a
* non- seri aliza ble o bject in a n en viron ment marke d dis trib utabl e.
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*/
pub lic v oid setAt tribu te(St ring name , Obj ect v alue) {
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- Sess ion
Package Meth ods
/**
* The l ast acces sed t ime f or th is S essio n.
*/
pri vate long last Acces sedTi me = crea tionT ime;
retu rn v alueN ames;
}
remo veAt tribu te(na me);
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.va lue. iae") ;
// ----- ---- ----- ----- ----- ----- ---- ----- ----- - Htt pSess ion Priva te Me thods
/**
* Read a se riali zed v ersio n of this sess ion o bject from the spec ified
* objec t in put s tream .
* <p>
* <b>IM PLEM ENTAT ION N OTE</ b>: The refer ence to th e own ing Manag er
* is no t re store d by this metho d, a nd mu st be set expli citl y.
*
* @para m st ream The i nput strea m to read from
*
* @exce ptio n Cla ssNot Found Excep tion if a n unk nown class is speci fied
* @exce ptio n IOE xcept ion i f an inpu t/out put e rror occur s
*/
pri vate void read Objec t(Obj ectIn putS tream stre am)
thro ws C lassN otFou ndExc eptio n, I OExce ption {
not.
*/
pri vate bool ean i sNew = tru e;
/**
* Flag indi catin g whe ther this sess ion i s val id
or not.
*/
pri vate bool ean i sVali d = f alse;
thro w new Ille galAr gumen tExc eptio n(msg );
}
// HTTP SESS ION I MPLEM ENTAT ION M ETHO DS
Obje ct o = va lues. get(n ame);
pub lic S trin g get Id() {
if ( vali d) {
retu rn id ;
} el se {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
if ( o in stanc eof H ttpSe ssion Bind ingLi stene r) {
Http Sessi onBin dingE vent e =
new H ttpSe ssion Bindi ngEv ent(t his,n ame);
/**
* The s trin g man ager for t his p acka ge.
*/
pri vate Stri ngMan ager sm =
this .isV alid = isV alid;
}
StringM anage r.ge tMana ger(" org.a pache .tom cat.s essio n")
;
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- HttpSes sion Prop ertie s
retu rn ( this. creat ionTi me);
pub lic v oid setMa xInac tiveI nterv al(i nt in terva l) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
thro w new Ille galSt ateEx cept ion(m sg);
}
thro w new Ille galSt ateEx cept ion(m sg);
}
inac tive Inter val = inte rval;
}
/**
* The H TTP sessi on co ntext asso ciat ed wi th th is
session .
*/
pri vate stat ic Ht tpSes sionC ontex t se ssion Conte xt
= null;
/**
* The c urre nt ac cesse d tim e for thi s ses sion.
*/
pri vate long this Acces sedTi me = crea tionT ime;
}
/**
*
* @depr ecat ed
*/
pub lic i nt g etMax Inact iveIn terva l() {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --------- Sess ion Prope rties
/**
* Write a s erial ized versi on of thi s ses sion objec t to the speci fied
* objec t ou tput strea m.
* <p>
* <b>IM PLEM ENTAT ION N OTE</ b>: The ownin g Man ager will not be st ored
* in th e se riali zed r epres entat ion of th is Se ssion . Af ter calli ng
* <code >rea dObje ct()< /code >, yo u mu st se t the asso ciate d Ma nager
* expli citl y.
* <p>
* <b>IM PLEM ENTAT ION N OTE</ b>: Any attri bute that is no t Se riali zable
* will be s ilent ly ig nored . If you do n ot wa nt an y suc h at tribu tes,
* be su re t he <c ode>d istri butab le</ code> prop erty of ou r as socia ted
* Manag er i s set to < code> true< /cod e>.
*
* @para m st ream The o utput stre am t o wri te to
*
* @exce ptio n IOE xcept ion i f an inpu t/out put e rror occur s
*/
pri vate void writ eObje ct(Ob jectO utpu tStre am st ream) thro ws I OExce ption {
if ( sess ionCo ntext == n ull)
sess ionCo ntext = ne w Sta ndar dSess ionCo ntext ();
retu rn ( sessi onCon text) ;
}
retu rn i nacti veInt erval ;
}
pub lic l ong getLa stAcc essed Time( ) {
if ( vali d) {
retu rn la stAcc essed ;
} el se {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
}
//----- ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- ----- ----
/**
* Set t he c reati on ti me fo r thi s se ssion . Th is
method is ca lled by t he
* Manag er w hen a n exi sting Sess ion insta nce i s
reused.
*
* @para m ti me Th e new crea tion time
*/
pub lic v oid setCr eatio nTime (long tim e) {
thro w new Ille galSt ateEx cept ion(m sg);
this .cre ation Time = tim e;
this .las tAcce ssedT ime = time ;
this .thi sAcce ssedT ime = time ;
}
}
}
/**
* Retur n th e ses sion ident ifier for this
session .
*/
pub lic S trin g get Id() {
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --HttpSes sion Publ ic Me thods
/**
* Retur n th e obj ect b ound with the speci fied name in th is
session , or
* <code >nul l</co de> i f no objec t is boun d wit h tha t nam e.
*
* @para m na me Na me of the attri bute to b e ret urned
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic O bjec t get Attri bute( Strin g na me) {
/**
* Set t he s essio n ide ntifi er fo r th is se ssion .
*
* @para m id The new s essio n ide ntif ier
*/
pub lic v oid setId (Stri ng id ) {
if ( (thi s.id != nu ll) & & (ma nage r != null) &&
(m anag er in stanc eof M anage rBas e))
((Ma nager Base) mana ger). remo ve(th is);
this .id = id;
ServerSession
package org. apac he.to mcat. sessi on;
import org.a pach e.tom cat.c ore.* ;
import org.a pach e.tom cat.u til.S tring Mana ger;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. *;
import javax .ser vlet. http. *;
void va lidat e() {
// i f we have an i nacti ve in terv al, c heck to se e if
// w e've exce eded it
if ( inac tiveI nterv al != -1) {
int thisI nterv al =
(int) (Syst em.cu rrent Time Milli s() - last Acces sed) / 10 00;
if ( (man ager != nu ll) & & (ma nage r ins tance of
Manager Base) )
((Ma nager Base) mana ger). add( this) ;
}
/**
* Retur n de scrip tive infor matio n ab out t his
Session impl emen tatio n and
* the c orre spond ing v ersio n num ber, in t he
format
*
<code>& lt;de scri ption >/ <v ersio n&gt ;</co de>.
*/
pub lic S trin g get Info( ) {
retu rn 0 ;
pub lic i nt r eques tMap( Reque st re ques t ) {
Stri ng s essio nId = null ;
}
Cook ie c ookie s[]=r eques t.get Cook ies() ; // asser t !=n ull
/** Noti fica tion of co ntext shut down
*/
pub lic v oid conte xtShu tdown ( Con text ctx )
thro ws T omcat Excep tion
{
if( ctx. getDe bug() > 0 ) ctx .log ("Rem oving sess ions from " + ctx ) ;
ctx. getS essio nMana ger() .remo veSe ssion s(ctx );
}
for( int i=0; i<co okies .leng th; i++ ) {
Cook ie co okie = coo kies[ i];
if ( cooki e.get Name( ).equ als( "JSES SIONI D")) {
sessi onId = coo kie.g etVa lue() ;
sessi onId= valid ateSe ssio nId(r eques t, se ssion Id);
if (s essio nId!= null) {
r eques t.set Reque sted Sessi onIdF romCo okie( true );
}
}
Serve rSess ionMa nager ssm =
S erver Sessi onMan ager .getM anage r();
ssm.r emove Sessi on(th is);
}
}
public class Ser verSe ssion {
}
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
pri vate Hash table valu es = new H asht able( );
pri vate Hash table appS essio ns = new Hasht able( );
pri vate Stri ng id ;
pri vate long crea tionT ime = Syst em.c urren tTime Milli s();;
pri vate long this Acces sTime = cr eati onTim e;
pri vate long last Acces sed = crea tion Time;
pri vate int inact iveIn terva l = - 1;
syn chron ized void inva lidat e() {
Enum erat ion e num = appS essio ns.k eys() ;
Ser verSe ssio n(Str ing i d) {
this .id = id;
}
}
appS essio n.inv alida te();
}
}
/** Vali date and fix t he se ssion id. If t he se ssion is n ot v alid retur n nul l.
* It w ill also clean up t he se ssio n fro m loa d-bal ancin g st rings .
* @retu rn s essio nId, or nu ll if not vali d
*/
pri vate Stri ng va lidat eSess ionId (Req uest reque st, S tring ses sionI d){
// G S, W e pig gybac k the JVM id o n top of t he se ssion coo kie
// S epar ate t hem . ..
sta tic a dvic e(Sta ndard Sessi on s) : in valid ate(s ) {
befo re {
if ( !s.is Valid ())
throw new Illeg alSta teEx cepti on
( s.sm. getSt ring( "sta ndard Sessi on."
+ th isJoi nPoin t.met hodNa me
+ ". ise") );
}
}
/**
* This clas s is a du mmy i mplem entat ion of th e <co de>Ht tpSes sion Conte xt</c ode>
* inte rface , to conf orm t o the requ irem ent t hat s uch a n obj ect be re turne d
* when <cod e>Ht tpSes sion. getSe ssion Cont ext() </cod e> is call ed.
*
* @aut hor C raig R. M cClan ahan
*
* @dep recat ed A s of Java Servl et AP I 2. 1 wit h no repla cemen t. The
* int erfac e wi ll be remo ved i n a f utur e ver sion of th is AP I.
*/
final c lass Stan dardS essio nCont ext i mple ments Http Sessi onCon text {
pri vate Vect or du mmy = new Vecto r();
/**
* Retur n th e ses sion ident ifier s of all sessi ons d efine d
* withi n th is co ntext .
*
* @depr ecat ed As of J ava S ervle t AP I 2.1 with no r eplac emen t.
* This met hod m ust r eturn an e mpty <cod e>Enu merat ion</ code >
* and will be r emove d in a fut ure versi on of the API.
*/
pub lic E nume ratio n get Ids() {
}
remo veVa lue(n ame); // remov e an y exi sting bind ing
valu es.p ut(na me, v alue) ;
}
pub lic l ong getLa stAcc essed Time( ) {
retu rn l astAc cesse d;
}
pub lic O bjec t get Value (Stri ng na me) {
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("s erver Sessi on.va lue.i ae") ;
/**
* Set t he M anage r wit hin w hich this Sess ion i s
valid.
*
* @para m ma nager The new M anage r
*/
pub lic v oid setMa nager (Mana ger m anag er) {
this .man ager = man ager;
pub lic A ppli catio nSess ion g etApp lica tionS essio n(Con text cont ext,
bool ean creat e) {
Appl icat ionSe ssion appS essio n =
(App licat ionSe ssion )appS essi ons.g et(co ntext );
thro w new Ille galAr gumen tExc eptio n(msg );
}
}
retu rn ( dummy .elem ents( ));
/**
* Inval idat es th is se ssion and unbi nds a ny ob jects boun d
to it.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on
* an i nval idate d ses sion
*/
pub lic v oid inval idate () {
/**
* The s trin g man ager for t his p acka ge.
*/
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
}
// X XX
// s ync t o ens ure v alid?
pub lic E nume ratio n get Value Names () {
retu rn v alues .keys ();
}
appS essio n = n ew Ap plica tion Sessi on(id , thi s, co ntex t);
appS essio ns.pu t(con text, app Sessi on);
pub lic v oid remov eValu e(Str ing n ame) {
valu es.r emove (name );
}
}
// X XX
// m ake sure that we ha ven't gon e ove r the end of ou r
// i nact ive i nterv al -- if s o, i nvali date and c reate
// a new appS essio n
pub lic v oid setMa xInac tiveI nterv al(i nt in terva l) {
inac tive Inter val = inte rval;
}
retu rn a ppSes sion;
/**
* Retur n th e max imum time inter val, in s econd s,
between clie nt r eques ts
* befor e th e ser vlet conta iner will inva lidat e
the ses sion. A negat ive
* time indi cates that the sessi on s hould neve r
time ou t.
*
* @exce ptio n Ill egalS tateE xcept ion if th is
method is ca lled on
* an i nval idate d ses sion
*/
pub lic i nt g etMax Inact iveIn terva l() {
retu rn ( this. maxIn activ eInte rval );
pub lic i nt g etMax Inact iveIn terva l() {
retu rn i nacti veInt erval ;
}
}
}
voi d rem oveA pplic ation Sessi on(Co ntex t con text) {
appS essi ons.r emove (cont ext);
// XXX
// sync' d fo r saf ty -- no o ther thre ad sh ould be ge tting som ethin g
// from this whil e we are r eapin g. T his i sn't the m ost o ptim al
// solut ion for t his, but w e'll dete rmine some thing else lat er.
}
/**
* Calle d by cont ext w hen r eques t co mes i n so that acces ses and
* inact ivit ies c an be deal t wit h ac cordi ngly.
*/
syn chron ized void reap () {
Enum erat ion e num = appS essio ns.k eys() ;
voi d acc esse d() {
// s et l ast a ccess ed to this Acce ssTim e as it wi ll be lef t ove r
// f rom the p revio us ac cess
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Appl icati onSes sion appSe ssio n =
(Appl icati onSes sion) appS essio ns.ge t(key );
last Acce ssed = thi sAcce ssTim e;
this Acce ssTim e = S ystem .curr entT imeMi llis( );
/**
* Set t he m aximu m tim e int erval , in seco nds,
between clie nt r eques ts
* befor e th e ser vlet conta iner will inva lidat e
the ses sion. A negat ive
* time indi cates that the sessi on s hould neve r
time ou t.
*
* @para m in terva l The new maxim um i nterv al
*/
pub lic v oid setMa xInac tiveI nterv al(i nt in terva l)
{
/**
* Retur n th e <co de>Ht tpSes sion< /cod e> as socia ted w ith t he
* speci fied sess ion i denti fier.
*
* @para m id Sess ion i denti fier for which to l ook u p a s essi on
*
* @depr ecat ed As of J ava S ervle t AP I 2.1 with no r eplac emen t.
* This met hod m ust r eturn null and will be r emove d in a
* futu re v ersio n of the A PI.
*/
pub lic H ttpS essio n get Sessi on(St ring id) {
}
retu rn ( null) ;
/**
* Retur n <c ode>t rue</ code> if t he c lient does not yet k now
about t he
* sessi on, or if the clien t cho oses not to jo in th e
session . Fo r
* examp le, if th e ser ver u sed o nly cooki e-bas ed se ssion s,
and the clie nt
* has d isab led t he us e of cooki es, then a ses sion would be
new on each
* reque st.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic b oole an is New() {
/**
* The b ackg round thre ad.
*/
pri vate Thre ad th read = nul l;
req. setS essio n( se ssion );
}
* and lifec ycle conf igura tion is no t su pport ed.
* <p>
// XXX s houl d we throw exce ption or just retur n nul l ??
Once we commi t to the n ew
pub lic H ttpS essio n fin dSess ion( Cont ext c tx, S tring id ) {
* para digm, I w ould sugge st mo ving the logic impl ement ed he re b ack i nto
// S tart the backg round reap er t hread
thre adSt art() ;
T he To mcat. Next "Man ager" inte rface acts mor e lik e a
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- ---- Prope rties
// V alid ate a nd up date our c urre nt co mpone nt st ate
if ( !sta rted)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.not Start ed")) ;
star ted = fal se;
/**
* Retur n th e che ck in terva l (in sec onds) for this Manag er.
*/
pub lic i nt g etChe ckInt erval () {
// S top the b ackgr ound reape r th read
thre adSt op();
retu rn ( this. check Inter val);
}
// E xpir e all acti ve se ssion s
Sess ion sessi ons[] = fi ndSes sion s();
for (int i = 0; i < ses sions .len gth; i++) {
Stan dardS essio n ses sion = (S tanda rdSes sion) sess ions [i];
if ( !sess ion.i sVali d())
conti nue;
sess ion.e xpire ();
}
/**
* Set t he c heck inter val ( in se cond s) fo r thi s Man ager.
*
* @para m ch eckIn terva l The new chec k int erval
*/
pub lic v oid setCh eckIn terva l(int che ckInt erval ) {
ServerSessionManager
package org. apac he.to mcat. sessi on;
import org.a pach e.tom cat.u til.* ;
import org.a pach e.tom cat.c ore.* ;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. http. *;
// XXX
// sync' d fo r saf ty -- no o ther thre ad sh ould be ge tting som ethin g
// from this whil e we are r eapin g. T his i sn't the m ost o ptim al
// solut ion for t his, but w e'll dete rmine some thing else lat er.
syn chron ized void reap () {
Enum erat ion e num = sess ions. keys ();
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Serv erSes sion sessi on = (Ser verSe ssion )sess ions. get( key);
/**
*
* @aut hor J ames Dunc an Da vidso n [du ncan @eng. sun.c om]
* @aut hor J ason Hunt er [j ch@en g.sun .com ]
* @aut hor J ames Todd [gon zo@en g.sun .com ]
*/
sess ion.r eap() ;
sess ion.v alida te();
}
this .che ckInt erval = ch eckIn terv al;
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- --- Priva te Me thods
/**
* Retur n de scrip tive infor matio n ab out t his M anage r imp leme ntati on an d
* the c orre spond ing v ersio n num ber, in t he fo rmat
* <code >&lt ;desc ripti on&gt ;/&lt ;ver sion& gt;</ code> .
*/
pub lic S trin g get Info( ) {
/**
* Inval idat e all sess ions that have expi red.
*/
pri vate void proc essEx pires () {
long tim eNow = Sys tem.c urren tTim eMill is();
Sess ion sessi ons[] = fi ndSes sion s();
for (int i = 0; i < ses sions .len gth; i++) {
Stan dardS essio n ses sion = (S tanda rdSes sion) sess ions [i];
if ( !sess ion.i sVali d())
conti nue;
int maxIn activ eInte rval = se ssion .getM axIna ctive Inte rval( );
if ( maxIn activ eInte rval < 0)
conti nue;
int timeI dle = // T runca te, do no t rou nd up
(int) ((ti meNow - se ssio n.get LastA ccess edTim e()) / 10 00L);
if ( timeI dle > = max Inact iveI nterv al)
sessi on.ex pire( );
}
}
/**
* Retur n th e max imum numbe r of acti ve Se ssion s all owed, or -1 fo r
* no li mit.
*/
pub lic i nt g etMax Activ eSess ions( ) {
retu rn ( this. maxAc tiveS essio ns);
}
}
}
}
public class Ser verSe ssion Manag er im plem ents Sessi onMan ager {
syn chron ized void remo veSes sion( Serv erSes sion sessi on) {
Stri ng i d = s essio n.get Id();
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
pri vate stat ic Se rverS essio nMana ger manag er; / / = n ew Se rver Sessi onMan ager( );
sess ion. inval idate ();
sess ions .remo ve(id );
/**
* Set t he m aximu m num ber o f act ives Sess ions allow ed, o r -1 for
* no li mit.
*
* @para m ma x The new maxim um nu mber of s essio ns
*/
pub lic v oid setMa xActi veSes sions (int max) {
/**
* Sleep for the durat ion s pecif ied by th e <co de>ch eckIn terv al</c ode>
* prope rty.
*/
pri vate void thre adSle ep() {
try {
Thre ad.sl eep(c heckI nterv al * 1000 L);
} ca tch (Inte rrupt edExc eptio n e) {
;
}
}
pro tecte d in t ina ctive Inter val = -1;
this .max Activ eSess ions = max ;
pub lic v oid remov eSess ions( Conte xt c ontex t) {
Enum erat ion e num = sess ions. keys ();
sta tic {
mana ger = new Serv erSes sionM anag er();
}
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Serv erSes sion sessi on = (Ser verSe ssion )sess ions. get( key);
Appl icati onSes sion appSe ssio n =
sessi on.ge tAppl icati onSe ssion (cont ext, false );
pri vate Hash table sess ions = new Has htabl e();
pri vate Reap er re aper;
if ( appSe ssion != n ull) {
appSe ssion .inva lidat e();
}
pri vate Serv erSes sionM anage r() {
reap er = Reap er.ge tReap er();
reap er.s etSer verSe ssion Manag er(t his);
reap er.s tart( );
}
}
}
/**
* Used by c ontex t to confi gure the sessi on ma nager 's in acti vity timeo ut.
*
* The S essi onMan ager may h ave s ome defau lt se ssion time out , the
* Conte xt o n the othe r han d has it' s tim eout set b y the dep loyme nt
* descr ipto r (we b.xml ). Th is me thod lets the Conte xt co nfor gure the
* sessi on m anage r acc ordin g to this valu e.
*
* @para m mi nutes The sessi on in acti vity timeo ut in minu tes.
*/
pub lic v oid setSe ssion TimeO ut(in t mi nutes ) {
if(- 1 != minu tes) {
// T he ma nager work s wit h se conds ...
inac tiveI nterv al = (minu tes * 60) ;
}
}
pub lic v oid acces sed( Conte xt ct x, R eques t req , Str ing i d ) {
Appl icat ionSe ssion apS= (Appl icat ionSe ssion )find Sessi on( ctx, id);
if( apS= =null ) ret urn;
Serv erSe ssion serv S=apS .getS erve rSess ion() ;
serv S.ac cesse d();
apS. acce ssed( );
}
// c ache it - no n eed t o com pute it a gain
req. setS essio n( ap S );
}
pub lic H ttpS essio n cre ateSe ssion (Con text ctx) {
Stri ng s essio nId = Sess ionId Gene rator .gene rateI d();
Serv erSe ssion sess ion = new Serv erSes sion( sessi onId) ;
sess ions .put( sessi onId, sess ion) ;
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- Publ ic Me thods
}
/**
* Const ruct and retur n a n ew se ssio n obj ect, based on t he d efaul t
* setti ngs speci fied by th is Ma nage r's p roper ties. The ses sion
* id wi ll b e ass igned by t his m etho d, an d ava ilabl e via the getI d()
* metho d of the retur ned s essio n. If a new s essio n can not be cr eated
* for a ny r eason , ret urn < code> null </cod e>.
*
* @exce ptio n Ill egalS tateE xcept ion if a new s essio n can not be
* inst anti ated for a ny re ason
*/
pub lic S essi on cr eateS essio n() {
/**
* Start the back groun d thr ead t hat will perio dical ly ch eck for
* sessi on t imeou ts.
*/
pri vate void thre adSta rt() {
if ( thre ad != null )
retu rn;
thre adDo ne = false ;
thre ad = new Threa d(thi s, th read Name) ;
thre ad.s etDae mon(t rue);
thre ad.s tart( );
if ( (max Activ eSess ions >= 0) &&
(s essi ons.s ize() >= m axAct iveS essio ns))
thro w new Ille galSt ateEx cept ion
(sm.g etStr ing(" stand ardM anage r.cre ateSe ssion .ise "));
}
/**
* Stop the backg round thre ad th at i s per iodic ally check ing for
* sessi on t imeou ts.
*/
pri vate void thre adSto p() {
retu rn ( super .crea teSes sion( ));
}
if ( thre ad == null )
retu rn;
}
thre adDo ne = true;
thre ad.i nterr upt() ;
try {
thre ad.jo in();
} ca tch (Inte rrupt edExc eptio n e) {
;
}
if(- 1 != inac tiveI nterv al) {
sess ion. setMa xInac tiveI nterv al(i nacti veInt erval );
}
retu rn s essio n.get Appli catio nSes sion( ctx, true );
retu rn ( this. isNew );
}
}
thre ad = null ;
pub lic H ttpS essio n fin dSess ion(C onte xt ct x, St ring id) {
Serv erSe ssion sSes sion= (Serv erSe ssion )sess ions. get(i d);
if(s Sess ion== null) retu rn nu ll;
}
retu rn s Sessi on.ge tAppl icati onSe ssion (ctx, fals e);
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- - Ba ckgro und T hread
}
this .max Inact iveIn terva l = i nter val;
/**
* The b ackg round thre ad th at ch ecks for sessi on ti meout s an d shu tdown .
*/
pub lic v oid run() {
}
voi d val idat e()
// L oop until the termi natio n se mapho re is set
whil e (! threa dDone ) {
thre adSle ep();
proc essEx pires ();
}
}
}
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Sess ion s essio n = m anage r.fi ndSes sion( id);
* coll ectio n cl ass, and h as mi nimal kno wledg e of the d etail ed r eques t
if(s essio n!=nu ll)
* proc essin g se manti cs of hand ling sess ions.
retur n ses sion. getSe ssio n();
* <p>
} ca tch (IOEx cepti on e) {
}
retu rn ( null) ;
* a Co ntext to tell the M anage r tha t we crea te wh at th e def ault sess ion
}
* time out f or t his w eb ap plica tion (spe cifie d in the d eploy ment
descrip tor)
pub lic H ttpS essio n cre ateSe ssion (Con text ctx) {
* shou ld be .
retu rn
*
manag er.cr eateS essio n(). getSe ssion ();
}
* @aut hor C raig R. M cClan ahan
*/
public final cla ss St andar dSess ionMa nage r
* Remov e al l ses sions beca use o ur a ssoci ated Conte xt is bei ng sh ut
down.
imp lemen ts S essio nMana ger {
*
* @para m ct x The cont ext t hat i s be ing s hut d own
*/
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- -Constru ctors
pub lic v oid remov eSess ions( Conte xt c tx) {
// c onte xts, we ju st wa nt to rem ove t he se ssion s of ctx!
// T he m anage r wil l sti ll ru n af ter t hat ( i.e. keep dat abase
* Creat e a new S essio nMana ger t hat adapt s to the c orres pond ing
Manager
// c onne ction open
* imple ment ation .
if ( mana ger i nstan ceof Lifec ycle ) {
*/
try {
pub lic S tand ardSe ssion Manag er() {
((Lif ecycl e) ma nager ).st op();
} ca tch ( Lifec ycleE xcept ion e) {
mana ger = new Stan dardM anage r();
throw new Illeg alSta teEx cepti on("" + e) ;
if ( mana ger i nstan ceof Lifec ycle ) {
}
try {
}
((Lif ecycl e) ma nager ).st art() ;
}
} ca tch ( Lifec ycleE xcept ion e) {
throw new Illeg alSta teEx cepti on("" + e) ;
}
}
/**
* Used by c ontex t to confi gure the sessi on ma nager 's in acti vity
timeout .
*
* The S essi onMan ager may h ave s ome defau lt se ssion time out , the
}
* Conte xt o n the othe r han d has it' s tim eout set b y the dep loyme nt
* descr ipto r (we b.xml ). Th is me thod lets the Conte xt co nfor gure the
/**
* Grace full y ter minat e the acti ve u se of the publi c met hods of t his
* compo nent . Th is me thod shoul d be the last one c alled on a giv en
* insta nce of th is co mpone nt.
*
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s no t bee n sta rted
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s al ready
* been sto pped
* @exce ptio n Lif ecycl eExce ption if this compo nent detec ts a fata l err or
* that nee ds to be r eport ed
*/
pub lic v oid stop( ) thr ows L ifecy cleE xcept ion {
/**
* Name to r egist er fo r the back grou nd th read.
*/
pri vate Stri ng th readN ame = "Sta ndar dMana ger";
}
6
try {
* XXX - At pres ent, there is n o way (vi a the Sess ionMa nager int erfac e)
for
}
/**
* The b ackg round thre ad co mplet ion semap hore.
*/
pri vate bool ean t hread Done = fal se;
}
}
// c ache the HttpS essio n - a void anot her f ind
* <p>
* XXX - At pres ent, use o f <co de>St anda rdMan ager< /code > is hard code d,
((Lif ecycl e) ma nager ).co nfigu re(nu ll);
appS essio n.val idate ();
}
}
((Se ssion ) ses sion) .acce ss() ;
* Spec ializ ed i mplem entat ion o f org .apa che.t omcat .core .Sess ionM anage r
* that adap ts t o the new compo nent- base d Man ager imple menta tion .
* <b>I MPLEM ENTA TION NOTE< /b>:
Manager /Sess ion
// V alid ate a nd up date our c urre nt co mpone nt st ate
if ( !con figur ed)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.not Confi gured "));
if ( star ted)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.alr eadyS tarte d")) ;
star ted = tru e;
/**
* Has t his compo nent been start ed y et?
*/
pri vate bool ean s tarte d = f alse;
if ( sess ionId != n ull & & ses sion Id.le ngth( )!=0) {
// G S, We are in a probl em h ere, we ma y act ually get
// m ultip le Se ssion cook ies (one for t he ro ot
// c ontex t and one for t he r eal c ontex t... or ol d se ssion
// c ookie . We must check for vali dity in th e cur rent cont ext.
Cont ext c tx=re quest .getC onte xt();
Sess ionMa nager sM = ctx. getS essio nMana ger() ;
if(n ull ! = sM. findS essio n(ct x, se ssion Id)) {
sM.ac cesse d(ctx , req uest , ses sionI d );
reque st.se tRequ ested Sess ionId (sess ionId );
if( d ebug> 0 ) c m.log (" F inal sessi on id " + sess ionId );
retur n ses sionI d;
}
}
retu rn n ull;
pub lic s tati c Ser verSe ssion Manag er g etMan ager( ) {
retu rn m anage r;
}
}
// C ause this sess ion t o exp ire
expi re() ;
retu rn v alues .get( name) ;
if ( appS essio n == null && cr eate ) {
* Prepa re f or th e beg innin g of acti ve us e of the p ublic met hods of th is
* compo nent . Th is me thod shoul d be call ed af ter < code> conf igure ()</c ode>,
* and b efor e any of t he pu blic meth ods o f the comp onent are util ized.
*
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s no t yet been
* conf igur ed (i f req uired for this comp onent )
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s al ready been
* star ted
* @exce ptio n Lif ecycl eExce ption if this compo nent detec ts a fata l err or
* that pre vents this comp onent fro m bei ng us ed
*/
pub lic v oid start () th rows Lifec ycle Excep tion {
/**
* The m axim um nu mber of ac tive Sess ions allow ed, o r -1 for no li mit.
*/
pro tecte d in t max Activ eSess ions = -1 ;
if( debu g>0 ) cm.l og(" Orig sess ionId " + sess ionId );
if ( null != s essio nId) {
int idex = ses sionI d.las tInd exOf( SESSI ONID_ ROUTE _SEP );
if(i dex > 0) {
sessi onId = ses sionI d.su bstri ng(0, idex );
}
}
}
Vect or r esult s = n ew Ve ctor( );
Enum erat ion a ttrs = get Attri bute Names ();
whil e (a ttrs. hasMo reEle ments ()) {
Stri ng at tr = (Stri ng) a ttrs .next Eleme nt();
resu lts.a ddEle ment( attr) ;
}
Stri ng n ames[ ] = n ew St ring[ resu lts.s ize() ];
for (int i = 0; i < nam es.le ngth ; i++ )
name s[i] = (St ring) resu lts. eleme ntAt( i);
retu rn ( names );
retu rn ( this. manag er);
if( sess ion = = nul l) re turn;
if ( sess ion i nstan ceof Sessi on)
// X XX X XX a manag er ma y be shar ed by mult iple
/**
retu rn ( this. info) ;
}
Http Sess ion s essio n=fin dSess ion( ctx, id);
/**
// ---- ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- - Pri vate Class
/**
* Retur n th e Man ager withi n whi ch t his S essio n
is vali d.
*/
pub lic M anag er ge tMana ger() {
* @para m se ssion The sessi on to be marke d
pub lic v oid acces sed(C ontex t ctx , Re quest req, Stri ng id ) {
/**
/**
node = a ttrib utes. getNa medIt em(" maxIn activ eInte rval" );
if ( node != n ull) {
try {
setMa xInac tiveI nterv al(I ntege r.par seInt (node .get NodeV alue( )));
} ca tch ( Throw able t) {
;
// XXX - Thr ow e xcept ion?
}
}
/**
* The d escr iptiv e inf ormat ion a bout this impl ement ation .
*/
pri vate stat ic fi nal S tring info = " Stand ardMa nager /1.0" ;
// XXX w hat is th e cor rect behav ior if th e ses sion is in vali d ?
// We ma y st ill s et it and just retu rn se ssion inva lid.
cro sscut inv alida te(St andar dSess ion s): s & (i nt ge tMaxI nact iveIn terva l() |
l ong g etCre atio nTime () |
O bject getA ttri bute( Strin g) |
E numer ation get Attri buteN ames( ) |
S tring [] ge tVal ueNam es() |
v oid i nvali date () |
b oolea n isN ew() |
v oid r emove Attr ibute (Stri ng) |
v oid s etAtt ribu te(St ring, Obje ct));
/**
* Retur n th e obj ect b ound with the speci fied name in th is
session , or
* <code >nul l</co de> i f no objec t is boun d wit h tha t nam e.
*
* @para m na me Na me of the value to be re turne d
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d
by
* <cod e>ge tAttr ibute ()</c ode>
*/
pub lic O bjec t get Value (Stri ng na me) {
Thi s sh ould be
*
*/
import org.a pach e.tom cat.c ore.S essio nMan ager;
import org.a pach e.tom cat.u til.S essio nUti l;
}
}
retu rn ( attri butes .keys ());
/**
* Retur n th e set of n ames of ob ject s bou nd to this
session . If the re
* are n o su ch ob jects , a z ero-l engt h arr ay is retu rned.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d
by
* <cod e>ge tAttr ibute Names ()</c ode>
*/
pub lic S trin g[] g etVal ueNam es() {
* Mark the speci fied sessi on's last acce ssed time.
* calle d fo r eac h req uest by a Requ estIn terce ptor.
import org.a pach e.tom cat.c ore.R eques t;
import org.a pach e.tom cat.c ore.R espon se;
* sessi on m anage r acc ordin g to this valu e.
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- Ins tance
Variabl es
*
* @para m mi nutes The sessi on in acti vity timeo ut in minu tes.
*/
/**
pub lic v oid setSe ssion TimeO ut(in t mi nutes ) {
* The M anag er im pleme ntati on we are actu ally using .
if(- 1 != minu tes) {
*/
// T he ma nager work s wit h se conds ...
pri vate Mana ger m anage r = n ull;
mana ger.s etMax Inact iveIn terv al(mi nutes * 60 );
}
}
thro w new Ille galAr gumen tExc eptio n(msg );
pub lic l ong getCr eatio nTime () {
retu rn c reati onTim e;
node = a ttrib utes. getNa medIt em(" maxAc tiveS essio ns");
if ( node != n ull) {
try {
setMa xActi veSes sions (Int eger. parse Int(n ode.g etNo deVal ue()) );
} ca tch ( Throw able t) {
;
// XXX - Thr ow e xcept ion?
}
}
/**
import org.a pach e.tom cat.c atali na.*;
import org.a pach e.tom cat.c ore.C ontex t;
* the core leve l.
node = a ttrib utes. getNa medIt em(" check Inter val") ;
if ( node != n ull) {
try {
setCh eckIn terva l(Int eger .pars eInt( node. getNo deVa lue() ));
} ca tch ( Throw able t) {
;
// XXX - Thr ow e xcept ion?
}
}
/**
* Has t his compo nent been confi gure d yet ?
*/
pri vate bool ean c onfig ured = fal se;
// S eria lize the a ttrib ute c ount and the attri bute valu es
stre am.w riteO bject (new Integ er(r esult s.siz e())) ;
Enum erat ion n ames = res ults. elem ents( );
whil e (n ames. hasMo reEle ments ()) {
Stri ng na me = (Stri ng) n ames .next Eleme nt();
stre am.wr iteOb ject( name) ;
stre am.wr iteOb ject( attri bute s.get (name ));
}
}
retu rn ( getAt tribu te(na me));
}
}
// P arse and proce ss ou r con figu ratio n par amete rs
if ( !("M anage r".eq uals( param eter s.get NodeN ame() )))
retu rn;
Name dNod eMap attri butes = pa rame ters. getAt tribu tes() ;
Node nod e = n ull;
/**
* The i nter val ( in se conds ) bet ween chec ks fo r exp ired sess ions.
*/
pri vate int check Inter val = 60;
retu rn ( this. info) ;
pub lic v oid putVa lue(S tring name , Ob ject value ) {
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("s erver Sessi on.va lue.i ae") ;
pub lic S trin g get Id() {
retu rn i d;
}
// V alid ate a nd up date our c urre nt co mpone nt st ate
if ( conf igure d)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.alr eadyC onfig ured "));
conf igur ed = true;
if ( para meter s == null)
retu rn;
import javax .ser vlet. http. Cooki e;
import javax .ser vlet. http. HttpS essio n;
}
}
/**
* Retur n th e las t tim e the clie nt s ent a requ est
associa ted w ith this
* sessi on, as th e num ber o f mil lise conds sinc e
midnigh t, Ja nuar y 1, 1970
* GMT. Act ions that your appli cati on ta kes,
such as gett ing or se tting
* a val ue a ssoci ated with the s essi on, d o not
affect the a cces s tim e.
*/
pub lic l ong getLa stAcc essed Time( ) {
retu rn ( this. lastA ccess edTim e);
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Appl icati onSes sion appSe ssio n =
(Appl icati onSes sion) appS essio ns.ge t(key );
/**
* Stan dard impl ement ation of t he <b >Man ager< /b> i nterf ace t hat provi des
* no s essio n pe rsist ence or di strib utab le ca pabil ities , but doe s sup port
* an o ption al, confi gurab le, m aximu m nu mber of ac tive sessi ons allow ed.
* <p>
* Life cycle con figur ation of t his c ompo nent assum es an XML node
* in t he fo llow ing f ormat :
* <cod e>
*
<M anag er cl assNa me="o rg.ap ache .tomc at.se ssion .Stan dard Manag er"
*
check Inter val=" 60" m axAc tiveS essio ns="- 1"
*
maxIn activ eInte rval= "-1" />
* </co de>
* wher e you can adju st th e fol lowin g pa ramet ers, with defau lt v alues
* in s quare bra ckets :
* <ul>
* <li> <b>ch eckI nterv al</b > - T he in terv al (i n sec onds) betw een backg round
*
threa d ch ecks for e xpire d ses sion s. [ 60]
* <li> <b>ma xAct iveSe ssion s</b> - Th e ma ximum numb er of sess ions allo wed t o
*
be ac tive at o nce, or -1 for no l imit. [-1 ]
* <li> <b>ma xIna ctive Inter val</ b> - The defau lt ma ximum numb er o f sec onds of
*
inact ivit y bef ore w hich the s ervl et co ntain er is allo wed to ti me ou t
*
a ses sion , or -1 fo r no limit . T his v alue shoul d be over ridde n fro m
*
the d efau lt se ssion time out s peci fied in th e web appl icat ion d eploy ment
*
descr ipto r, if any. [-1 ]
* </ul >
*
* @aut hor C raig R. M cClan ahan
* @ver sion $Rev ision : 1.1 .1.1 $ $Da te: 2000/ 05/02 21:2 8:30 $
*/
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- Ins tance Vari ables
Stri ng s ig="; jsess ionid =";
int foun dAt=- 1;
if( debu g>0 ) cm.l og(" XXX R URI= " + r eques t.get Reque stUR I());
if ( (fou ndAt= reque st.ge tRequ estU RI(). index Of(si g))!= -1){
sess ionId =requ est.g etReq uest URI() .subs tring (foun dAt+ sig.l ength ());
// r ewrit e URL , do I nee d to do a nythi ng mo re?
requ est.s etReq uestU RI(re ques t.get Reque stURI ().su bstr ing(0 , fou ndAt) );
sess ionId =vali dateS essio nId( reque st, s essio nId);
if ( sessi onId! =null ){
reque st.se tRequ ested Sess ionId FromU RL(tr ue);
}
}
retu rn 0 ;
// ---- ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- Pub lic
Methods
import java. io.I OExce ption ;
/**
* Confi gure this comp onent , bas ed o n the spec ified conf igur ation
* param eter s. T his m ethod shou ld b e cal led i mmedi ately aft er th e
* compo nent inst ance is cr eated , an d bef ore < code> start ()</ code>
* is ca lled .
*
* @para m pa ramet ers C onfig urati on p arame ters for t his c ompo nent
* (<B> FIXM E: Wh at ob ject type shou ld th is re ally be?)
*
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s al ready been
* conf igur ed an d/or start ed
* @exce ptio n Lif ecycl eExce ption if this compo nent detec ts a fata l err or
* in t he c onfig urati on pa ramet ers it wa s giv en
*/
pub lic v oid confi gure( Node param eter s)
thro ws L ifecy cleEx cepti on {
public final cla ss St andar dMana ger
ext ends Mana gerBa se
imp lemen ts L ifecy cle, Runna ble {
}
}
if ( thisI nterv al > inact iveI nterv al) {
inval idate ();
/**
* Core impl emen tatio n of a ser ver s essi on
*
* @aut hor J ames Dunc an Da vidso n [du ncan @eng. sun.c om]
* @aut hor J ames Todd [gon zo@en g.sun .com ]
*/
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- - Li fecyc le Me thods
java. io.I OExce ption ;
java. util .Enum erati on;
java. util .Hash table ;
java. util .Vect or;
org.a pach e.tom cat.c atali na.*;
javax .ser vlet. http. Cooki e;
javax .ser vlet. http. HttpS essio n;
org.a pach e.tom cat.u til.S tring Mana ger;
org.w 3c.d om.Na medNo deMap ;
org.w 3c.d om.No de;
}
/**
* Retur n an <cod e>Enu merat ion</ code > of
<code>S tring </co de> o bject s
* conta inin g the name s of the o bjec ts bo und t o thi s
session .
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic E nume ratio n get Attri buteN ames () {
StandardSessionManager
package org. apac he.to mcat. sessi on;
package org. apac he.to mcat. sessi on;
import
import
import
import
import
import
import
import
import
import
}
// A ccum ulate the names of s eria lizab le at tribu tes
Vect or r esult s = n ew Ve ctor( );
Enum erat ion a ttrs = get Attri bute Names ();
whil e (a ttrs. hasMo reEle ments ()) {
Stri ng at tr = (Stri ng) a ttrs .next Eleme nt();
Obje ct va lue = attr ibute s.ge t(att r);
if ( value inst anceo f Ser iali zable )
resul ts.ad dElem ent(a ttr) ;
}
retu rn ( attri butes .get( name) );
}
resp onse .addH eader ( Coo kieTo ols. getCo okieH eader Name( cook ie),
Coo kieTo ols. getCo okieH eader Value (coo kie)) ;
cook ie.s etVer sion( 0);
resp onse .addH eader ( Coo kieTo ols. getCo okieH eader Name( cook ie),
Coo kieTo ols. getCo okieH eader Value (coo kie)) ;
pub lic v oid setCo ntext Manag er( C onte xtMan ager cm ) {
this .cm= cm;
}
// W rite the scala r ins tance var iable s (ex cept Manag er)
stre am.w riteO bject (new Long( crea tionT ime)) ;
stre am.w riteO bject (id);
stre am.w riteO bject (new Long( last Acces sedTi me));
stre am.w riteO bject (new Integ er(m axIna ctive Inter val)) ;
stre am.w riteO bject (new Boole an(i sNew) );
stre am.w riteO bject (new Boole an(i sVali d));
retu rn ( this. id);
}
Cook ie c ookie = ne w Coo kie(" JSES SIONI D",
r eqSe ssion Id);
cook ie.s etMax Age(- 1);
cook ie.s etPat h(ses sionP ath);
cook ie.s etVer sion( 1);
pub lic v oid setDe bug( int i ) {
Syst em.o ut.pr intln ("Set debu g to " + i);
debu g=i;
}
}
/**
* Retur n th e ses sion conte xt wi th w hich this sessi on is
associa ted.
*
* @depr ecat ed As of V ersio n 2.1 , th is me thod is de preca ted
and has no
* repl acem ent. It w ill b e rem oved in a futu re ve rsion of
the
* Java Ser vlet API.
*/
pub lic H ttpS essio nCont ext g etSes sion Conte xt() {
thro w new Ille galSt ateEx cept ion(m sg);
pub lic H ttpS essio nCont ext g etSes sion Conte xt() {
retu rn n ew Se ssion Conte xtImp l();
}
// G S, p iggyb ack t he jv m rou te o n the sess ion i d.
if(! sess ionPa th.eq uals( "/")) {
Stri ng jv mRout e = r reque st.g etJvm Route ();
if(n ull ! = jvm Route ) {
reqSe ssion Id = reqSe ssio nId + SESS IONID _ROUT E_SE P + j vmRou te;
}
}
// GS, s epar ates the s essio n id from the jvm r oute
sta tic f inal char SESS IONID _ROUT E_SE P = ' .';
int debu g=0;
Con textM anag er cm ;
// D eser ializ e the attr ibute cou nt an d att ribut e val ues
int n = ((Int eger) stre am.re adOb ject( )).in tValu e();
for (int i = 0; i < n; i++) {
Stri ng na me = (Stri ng) s trea m.rea dObje ct();
Obje ct va lue = (Obj ect) stre am.re adObj ect() ;
attr ibute s.put (name , val ue);
}
((Ht tpSes sionB indin gList ener )o).v alueU nboun d(e);
valu es.r emove (name );
}
pub lic l ong getCr eatio nTime () {
if ( vali d) {
retu rn cr eatio nTime ;
} el se {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
// G S, s et th e pat h att ribut e to the cooki e. Th is wa y
// m ulti ple s essio n coo kies can be us ed, o ne fo r eac h
// c onte xt.
Stri ng s essio nPath = rr eques t.ge tCont ext() .getP ath() ;
if(s essi onPat h.len gth() == 0 ) {
sess ionPa th = "/";
}
/**
* Will proc ess the r eques t and dete rmin e the sess ion I d, an d se t it
* in t he Re ques t.
* It a lso m arks the sessi on as acce ssed .
*
* This impl emen tatio n onl y han dles Cook ies s essio ns, p lease ext end o r
* add new i nter cepto rs fo r oth er me thod s.
*
*/
public class Ses sionI nterc eptor exte nds Base Inter cepto r imp leme nts R eques tInte rcept or {
// D eser ializ e the scal ar in stan ce va riabl es (e xcept Man ager)
crea tion Time = ((L ong) strea m.re adObj ect() ).lon gValu e();
id = (St ring) stre am.re adObj ect( );
last Acce ssedT ime = ((Lo ng) s trea m.rea dObje ct()) .long Valu e();
maxI nact iveIn terva l = ( (Inte ger) stre am.re adObj ect() ).in tValu e();
isNe w = ((Boo lean) stre am.re adOb ject( )).bo olean Value ();
isVa lid = ((B oolea n) st ream. read Objec t()). boole anVal ue() ;
/**
* Retur n th e tim e whe n thi s ses sion was creat ed, i n
millise conds sin ce
* midni ght, Janu ary 1 , 197 0 GMT .
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic l ong getCr eatio nTime () {
}
thro w new Ille galSt ateEx cept ion(m sg);
}
}
pub lic i nt b efore Body( Requ est r requ est, Respo nse r espon se ) {
Stri ng r eqSes sionI d = r espon se.g etSes sionI d();
if( debu g>0 ) cm.l og("B efore Bod y " + reqS essio nId ) ;
if( reqS essio nId== null)
retu rn 0;
import org.a pach e.tom cat.c ore.* ;
import org.a pach e.tom cat.u til.* ;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. http. *;
pub lic S essi onInt ercep tor() {
}
}
StandardManager
package org. apac he.to mcat. reque st;
this .isN ew = isNew ;
}
/**
* Set t he < code> isVal id</c ode> flag for this sessi on.
*
* @para m is Valid The new v alue for the
<code>i sVali d</c ode> flag
*/
voi d set Vali d(boo lean isVal id) {
thro w new Ille galSt ateEx cept ion(m sg);
}
if ( thisI nterv al > inact iveI nterv al) {
inval idate ();
}
}
}
SessionInterceptor
}
// T ell our M anage r tha t thi s Se ssion has been recyc led
if ( (man ager != nu ll) & & (ma nage r ins tance of
Manager Base) )
((Ma nager Base) mana ger). recy cle(t his);
name s.co pyInt o(val ueNam es);
this .ina ctive Inter val = cont ext. getSe ssion TimeO ut();
}
/**
* Remov e th e obj ect b ound with the speci fied name from this sess ion. If
* the s essi on do es no t hav e an obje ct bo und w ith t his n ame, this meth od
* does noth ing.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueUnb ound( )</co de> o n th e obj ect.
*
* @para m na me Na me of the objec t to remo ve fr om th is se ssio n.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d by
* <cod e>re moveA ttrib ute() </cod e>
*/
pub lic v oid remov eValu e(Str ing n ame) {
}
}
}
whil e (e .hasM oreEl ement s()) {
name s.add Eleme nt(e. nextE leme nt()) ;
}
}
// M ark this sessi on as inva lid
setV alid (fals e);
supe r();
this .man ager = man ager;
pub lic O bjec t get Attri bute( Strin g na me) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
/**
* Core impl emen tatio n of an ap plica tion leve l ses sion
*
* @aut hor J ames Dunc an Da vidso n [du ncan @eng. sun.c om]
* @aut hor J ason Hunt er [j ch@en g.sun .com ]
* @aut hor J ames Todd [gon zo@en g.sun .com ]
*/
sync hron ized (attr ibute s) {
Obje ct ob ject = att ribut es.g et(na me);
if ( objec t == null)
retur n;
attr ibute s.rem ove(n ame);
//
S ystem .out. print ln( "Remo ving attri bute " + name );
if ( objec t ins tance of Ht tpSe ssion Bindi ngLis tener ) {
((Htt pSess ionBi nding List ener) obje ct).v alueU nbou nd
( new H ttpSe ssion Bind ingEv ent(( HttpS essio n) t his, name) );
}
}
if ( (man ager != nu ll) & & (ma nage r ins tance of
Manager Base) )
((Ma nager Base) mana ger). remo ve(th is);
/**
* Const ruct a ne w Ses sion assoc iate d wit h the
specifi ed Ma nage r.
*
* @para m ma nager The manag er wi th w hich this
Session is a ssoc iated
*/
pub lic S tand ardSe ssion (Mana ger m anag er) {
valu es.p ut(na me, v alue) ;
/**
* @depr ecat ed
*/
pub lic O bjec t get Value (Stri ng na me) {
retu rn g etAtt ribut e(nam e);
}
/**
* Remov e th e obj ect b ound with the speci fied name from this sess ion. If
* the s essi on do es no t hav e an obje ct bo und w ith t his n ame, this meth od
* does noth ing.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueUnb ound( )</co de> o n th e obj ect.
*
* @para m na me Na me of the objec t to remo ve fr om th is se ssio n.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*/
pub lic v oid remov eAttr ibute (Stri ng n ame) {
/**
* Perfo rm t he in terna l pro cessi ng r equir ed to inva lidat e
this se ssion ,
* witho ut t rigge ring an ex cepti on i f the sess ion h as
already expi red.
*/
pub lic v oid expir e() {
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --------- ----- - Co nstru ctors
}
package org. apac he.to mcat. sessi on;
import org.a pach e.tom cat.c ore.* ;
import org.a pach e.tom cat.u til.S tring Mana ger;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. *;
import javax .ser vlet. http. *;
setA ttri bute( name, valu e);
}
this .las tAcce ssedT ime = this .thi sAcce ssedT ime;
this .thi sAcce ssedT ime = Syst em.c urren tTime Milli s();
this .isN ew=fa lse;
}
// remov e an y exi sting bind ing
if ( valu e != null && va lue i nsta nceof Http Sessi onBin ding Liste ner) {
Http Sessi onBin dingE vent e =
new H ttpSe ssion Bindi ngEv ent(t his, name) ;
* Bind an o bject to t his s essio n, u sing the s pecif ied n ame. If an ob ject
* of th e sa me na me is alre ady b ound to t his s essio n, th e ob ject is
* repla ced.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueBou nd()< /code > on the objec t.
*
* @para m na me Na me to whic h the obj ect i s bou nd, c annot be null
* @para m va lue O bject to b e bou nd, canno t be null
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d by
* <cod e>se tAttr ibute ()</c ode>
*/
pub lic v oid putVa lue(S tring name , Ob ject value ) {
retu rn ( (Http Sessi on) t his);
}
}
problems like…
session tracking is not modularized
HTTPRequest
getCookies()
getRequestURI()(doc)
getSession()
getRequestedSessionId()
...
SessionInterceptor
requestMap(request)
beforeBody(req, resp)
...
Session
HTTPResponse
getAttribute(name)
setAttribute(name, val)
invalidate()
...
getRequest()
setContentType(contentType)
getOutptutStream()
setSessionId(id)
...
Servlet
7
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
the cost of tangled code
• redundant code
– same fragment of code in many places
• difficult to reason about
– non-explicit structure
– the big picture of the tangling isn’t clear
• difficult to change
– have to find all the code involved
– and be sure to change it consistently
– and be sure not to break it by accident
8
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
crosscutting concerns
HTTPRequest
getCookies()
getRequestURI()(doc)
getSession()
getRequestedSessionId()
...
SessionInterceptor
requestMap(request)
beforeBody(req, resp)
...
Session
HTTPResponse
getAttribute(name)
setAttribute(name, val)
invalidate()
...
getRequest()
setContentType(contentType)
getOutptutStream()
setSessionId(id)
...
Servlet
9
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
the AOP idea
aspect-oriented programming
• crosscutting is inherent in complex systems
• crosscutting concerns
– have a clear purpose
– have a natural structure
• defined set of methods, module boundary crossings,
points of resource utilization, lines of dataflow…
• so, let’s capture the structure of crosscutting
concerns explicitly...
– in a modular way
– with linguistic and tool support
• aspects are
– well-modularized crosscutting concerns
10
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
language support to…
ApplicationSession
App
ca onSess on
/*
* ==== ===== ==== ====
===== ===== ===== ===== ==== ===== ===== ===== ===== ==== ===== ==
*
* The Apach e So ftwar e Lic ense, Vers ion 1.1
*
* Copy right (c) 1999 The Apach e Sof twar e Fou ndati on. All r ight s
* rese rved.
*
* Redi strib utio n and use in so urce and binar y for ms, w ith o r wi thout
* modi ficat ion, are permi tted provi ded that the f ollow ing c ondi tions
* are met:
*
* 1. R edist ribu tions of s ource code mus t ret ain t he ab ove c opyr ight
*
n otice , th is li st of cond ition s an d the foll owing disc laim er.
*
* 2. R edist ribu tions in b inary form mus t rep roduc e the abov e co pyrig ht
*
n otice , th is li st of cond ition s an d the foll owing disc laim er in
*
t he do cume ntati on an d/or other mat erial s pro vided with the
*
d istri buti on.
*
* 3. T he en d-us er do cumen tatio n inc lude d wit h the redi strib utio n, if
*
a ny, m ust inclu de th e fol lowin g ac knowl egeme nt:
*
"Th is p roduc t inc ludes soft ware deve loped by t he
*
Ap ache Soft ware Found ation (ht tp:// www.a pache .org/ )."
*
A ltern atel y, th is ac knowl egeme nt m ay ap pear in th e sof twar e
itself,
*
i f and whe rever such thir d-par ty a cknow legem ents norma lly appea r.
*
* 4. T he na mes "The Jakar ta Pr oject ", " Tomca t", a nd "A pache Sof tware
*
F ounda tion " mus t not be u sed t o en dorse or p romot e pro duct s
derived
*
f rom t his softw are w ithou t pri or w ritte n per missi on. F or w ritte n
*
p ermis sion , ple ase c ontac t apa che@ apach e.org .
*
* 5. P roduc ts d erive d fro m thi s sof twar e may not be ca lled "Apa che"
*
n or ma y "A pache " app ear i n the ir n ames witho ut pr ior w ritt en
*
p ermis sion of t he Ap ache Group .
*
* THIS SOFT WARE IS P ROVID ED `` AS IS '' A ND AN Y EXP RESSE D OR IMPL IED
* WARR ANTIE S, I NCLUD ING, BUT N OT LI MITE D TO, THE IMPLI ED WA RRAN TIES
* OF M ERCHA NTAB ILITY AND FITNE SS FO R A PARTI CULAR PURP OSE A RE
* DISC LAIME D. IN NO EVEN T SHA LL TH E AP ACHE SOFTW ARE F OUNDA TION OR
* ITS CONTR IBUT ORS B E LIA BLE F OR AN Y DI RECT, INDI RECT, INCI DENT AL,
* SPEC IAL, EXEM PLARY , OR CONSE QUENT IAL DAMAG ES (I NCLUD ING, BUT NOT
* LIMI TED T O, P ROCUR EMENT OF S UBSTI TUTE GOOD S OR SERVI CES; LOSS OF
* USE, DATA , OR PROF ITS; OR BU SINES S IN TERRU PTION ) HOW EVER CAUS ED AN D
* ON A NY TH EORY OF L IABIL ITY, WHETH ER I N CON TRACT , STR ICT L IABI LITY,
* OR T ORT ( INCL UDING NEGL IGENC E OR OTHE RWISE ) ARI SING IN AN Y WA Y OUT
* OF T HE US E OF THIS SOFT WARE, EVEN IF ADVIS ED OF THE POSSI BILI TY OF
* SUCH DAMA GE.
* ==== ===== ==== ===== ===== ===== ===== ==== ===== ===== ===== ===== ==== ===== ==
*
* This soft ware cons ists of vo lunta ry c ontri butio ns ma de by man y
* indi vidua ls o n beh alf o f the Apac he S oftwa re Fo undat ion. For more
* info rmati on o n the Apac he So ftwar e Fo undat ion, pleas e see
* <htt p://w ww.a pache .org/ >.
*
* [Add ition al n otice s, if requ ired by p rior licen sing condi tion s]
*
*/
public void inva lidat e() {
serv erSe ssion .remo veApp licat ionS essio n(con text) ;
// r emov e eve rythi ng in the sess ion
Enum erat ion e num = valu es.ke ys() ;
whil e (e num.h asMor eElem ents( )) {
Stri ng na me = (Stri ng)en um.n extEl ement ();
remo veVal ue(na me);
}
vali d = false ;
}
pub lic b oole an is New() {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
StandardSession
S
andardSess on
package org. apac he.to mcat. sessi on;
import
import
import
import
import
import
import
import
import
import
import
import
import
import
java. io.I OExce ption ;
java. io.O bject Input Strea m;
java. io.O bject Outpu tStre am;
java. io.S erial izabl e;
java. util .Enum erati on;
java. util .Hash table ;
java. util .Vect or;
javax .ser vlet. Servl etExc eptio n;
javax .ser vlet. http. HttpS essio n;
javax .ser vlet. http. HttpS essio nBin dingE vent;
javax .ser vlet. http. HttpS essio nBin dingL isten er;
javax .ser vlet. http. HttpS essio nCon text;
org.a pach e.tom cat.c atali na.*;
org.a pach e.tom cat.u til.S tring Mana ger;
thro w new Ille galSt ateEx cept ion(m sg);
}
if ( this Acces sTime == c reati onTi me) {
retu rn tr ue;
} el se {
retu rn fa lse;
}
}
/**
* @depr ecat ed
*/
pub lic v oid putVa lue(S tring name , Ob ject value ) {
setA ttri bute( name, valu e);
}
pub lic v oid setAt tribu te(St ring name , Obj ect v alue) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
thro w new Ille galSt ateEx cept ion(m sg);
/**
* Stan dard impl ement ation of t he <b >Ses sion< /b>
interfa ce. This obje ct is
* seri aliza ble, so t hat i t can be s tore d in
persist ent s tora ge or tran sferr ed
* to a diff eren t JVM for distr ibuta ble sessi on
support .
* <p>
* <b>I MPLEM ENTA TION NOTE< /b>: An i nsta nce o f thi s
class r epres ents both the
* inte rnal (Ses sion) and appli catio n le vel
(HttpSe ssion ) vi ew of the sessi on.
* Howe ver, beca use t he cl ass i tself is not d eclar ed
public, Java log ic ou tside
* of t he <c ode> org.a pache .tomc at.se ssio n</co de>
package cann ot c ast a n
* Http Sessi on v iew o f thi s ins tance bac k to a
Session view .
*
* @aut hor C raig R. M cClan ahan
* @ver sion $Rev ision : 1.2 $ $D ate: 2000 /05/1 5
17:54:1 0 $
*/
}
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.va lue. iae") ;
thro w new Ille galAr gumen tExc eptio n(msg );
}
remo veVa lue(n ame);
final c lass Stan dardS essio n
imp lemen ts H ttpSe ssion , Ses sion {
/**
/**
* Retur n th e <co de>Ht tpSes sion< /cod e> fo r whi ch th is
object
* is th e fa cade.
*/
pub lic H ttpS essio n get Sessi on() {
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- Session Publ ic M ethod s
/**
* Updat e th e acc essed time info rmat ion f or th is se ssion .
This me thod
* shoul d be call ed by the conte xt w hen a requ est c omes in
for a p artic ular
* sessi on, even if th e app licat ion does not r efere nce i t.
*/
pub lic v oid acces s() {
((Ht tpSes sionB indin gList ener )valu e).va lueBo und(e );
}
// R emov e thi s ses sion from our manag er's activ e
session s
// U nbin d any obje cts a ssoci ated with this sess ion
Vect or r esult s = n ew Ve ctor( );
Enum erat ion a ttrs = get Attri bute Names ();
whil e (a ttrs. hasMo reEle ments ()) {
Stri ng at tr = (Stri ng) a ttrs .next Eleme nt();
resu lts.a ddEle ment( attr) ;
}
Enum erat ion n ames = res ults. elem ents( );
whil e (n ames. hasMo reEle ments ()) {
Stri ng na me = (Stri ng) n ames .next Eleme nt();
remo veAtt ribut e(nam e);
}
thro w new Ille galSt ateEx cept ion(m sg);
}
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.va lue. iae") ;
thro w new Ille galAr gumen tExc eptio n(msg );
}
public class App licat ionSe ssion impl emen ts Ht tpSes sion {
retu rn v alues .get( name) ;
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
pri vate Hash table valu es = new H asht able( );
pri vate Stri ng id ;
pri vate Serv erSes sion serve rSess ion;
pri vate Cont ext c ontex t;
pri vate long crea tionT ime = Syst em.c urren tTime Milli s();;
pri vate long this Acces sTime = cr eati onTim e;
pri vate long last Acces sed = crea tion Time;
pri vate int inact iveIn terva l = - 1;
pri vate bool ean v alid = tru e;
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --------- Inst ance Vari ables
/**
* The c olle ction of u ser d ata a ttri butes
associa ted w ith this Sessi on.
*/
pri vate Hash table attr ibute s = n ew H ashta ble() ;
Stri ng[] valu eName s = n ew St ring [name s.siz e()];
/**
* Relea se a ll ob ject refer ences , an d ini tiali ze in stanc e
variabl es, i n
* prepa rati on fo r reu se of this obj ect.
*/
pub lic v oid recyc le() {
// R eset the insta nce v ariab les assoc iated with this
Session
attr ibut es.cl ear() ;
crea tion Time = 0L;
id = nul l;
last Acce ssedT ime = 0L;
mana ger = nul l;
maxI nact iveIn terva l = - 1;
isNe w = true;
isVa lid = fal se;
/**
* The t ime this sessi on wa s cre ated , in
millise conds sin ce mi dnigh t,
* Janua ry 1 , 197 0 GMT .
*/
pri vate long crea tionT ime = 0L;
/**
* The s essi on id entif ier o f thi s Se ssion .
*/
pri vate Stri ng id = nu ll;
/**
* @depr ecat ed
*/
pub lic S trin g[] g etVal ueNam es() {
Enum erat ion e = ge tAttr ibute Name s();
Vect or n ames = new Vect or();
App licat ionS essio n(Str ing i d, Se rver Sessi on se rverS essio n,
Cont ext conte xt) {
this .ser verSe ssion = se rverS essi on;
this .con text = con text;
this .id = id;
/**
* Descr ipti ve in forma tion descr ibin g thi s
Session impl emen tatio n.
*/
pri vate stat ic fi nal S tring info =
"Standa rdSes sion /1.0" ;
if ( this .inac tiveI nterv al != -1) {
this .inac tiveI nterv al *= 60;
pub lic E nume ratio n get Attri buteN ames () {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
}
Ser verSe ssio n get Serve rSess ion() {
retu rn s erver Sessi on;
}
thro w new Ille galSt ateEx cept ion(m sg);
}
/**
* The M anag er wi th wh ich t his S essi on is
associa ted.
*/
pri vate Mana ger m anage r = n ull;
}
/**
* Retur n th e <co de>is Valid </cod e> f lag f or th is se ssion .
*/
boo lean isVa lid() {
retu rn ( Enume ratio n)val uesCl one. keys( );
}
voi d acc esse d() {
// s et l ast a ccess ed to this Acce ssTim e as it wi ll be lef t ove r
// f rom the p revio us ac cess
last Acce ssed = thi sAcce ssTim e;
this Acce ssTim e = S ystem .curr entT imeMi llis( );
/**
* @depr ecat ed
*/
/**
* The m axim um ti me in terva l, in sec onds, betw een
client reque sts befor e
* the s ervl et co ntain er ma y inv alid ate t his
session . A nega tive time
* indic ates that the sessi on sh ould neve r tim e
out.
*/
pri vate int maxIn activ eInte rval = -1 ;
pub lic v oid remov eValu e(Str ing n ame) {
remo veAt tribu te(na me);
}
vali date ();
/**
* Flag indi catin g whe ther this sess ion i s new or
}
pub lic v oid remov eAttr ibute (Stri ng n ame) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
voi d val idat e() {
// i f we have an i nacti ve in terv al, c heck to se e if we'v e exc eeded it
if ( inac tiveI nterv al != -1) {
int thisI nterv al =
(int) (Syst em.cu rrent Time Milli s() - last Acces sed) / 10 00;
if ( (man ager != nu ll) & & man ager .getD istri butab le() &&
!( valu e ins tance of Se riali zabl e))
thro w new Ille galAr gumen tExc eptio n
(sm.g etStr ing(" stand ardS essio n.set Attri bute. iae" ));
retu rn ( this. isVal id);
}
sync hron ized (attr ibute s) {
remo veAtt ribut e(nam e);
attr ibute s.put (name , val ue);
if ( value inst anceo f Htt pSes sionB indin gList ener)
((Htt pSess ionBi nding List ener) valu e).va lueBo und
( new H ttpSe ssion Bind ingEv ent(( HttpS essio n) t his, name) );
}
/**
* Set t he < code> isNew </cod e> fl ag f or th is se ssion .
*
* @para m is New T he ne w val ue fo r th e <co de>is New</ code>
flag
*/
voi d set New( boole an is New) {
Hash tabl e val uesCl one = (Has htab le)va lues. clone ();
/**
* Calle d by cont ext w hen r eques t co mes i n so that acces ses and
* inact ivit ies c an be deal t wit h ac cordi ngly.
*/
/**
* Bind an o bject to t his s essio n, u sing the s pecif ied n ame. If an ob ject
* of th e sa me na me is alre ady b ound to t his s essio n, th e ob ject is
* repla ced.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueBou nd()< /code > on the objec t.
*
* @para m na me Na me to whic h the obj ect i s bou nd, c annot be null
* @para m va lue O bject to b e bou nd, canno t be null
*
* @exce ptio n Ill egalA rgume ntExc epti on if an a ttemp t is made to a dd a
* non- seri aliza ble o bject in a n en viron ment marke d dis trib utabl e.
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*/
pub lic v oid setAt tribu te(St ring name , Obj ect v alue) {
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- Sess ion
Package Meth ods
/**
* The l ast acces sed t ime f or th is S essio n.
*/
pri vate long last Acces sedTi me = crea tionT ime;
retu rn v alueN ames;
}
remo veAt tribu te(na me);
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.va lue. iae") ;
// ----- ---- ----- ----- ----- ----- ---- ----- ----- - Htt pSess ion Priva te Me thods
/**
* Read a se riali zed v ersio n of this sess ion o bject from the spec ified
* objec t in put s tream .
* <p>
* <b>IM PLEM ENTAT ION N OTE</ b>: The refer ence to th e own ing Manag er
* is no t re store d by this metho d, a nd mu st be set expli citl y.
*
* @para m st ream The i nput strea m to read from
*
* @exce ptio n Cla ssNot Found Excep tion if a n unk nown class is speci fied
* @exce ptio n IOE xcept ion i f an inpu t/out put e rror occur s
*/
pri vate void read Objec t(Obj ectIn putS tream stre am)
thro ws C lassN otFou ndExc eptio n, I OExce ption {
not.
*/
pri vate bool ean i sNew = tru e;
/**
* Flag indi catin g whe ther this sess ion i s val id
or not.
*/
pri vate bool ean i sVali d = f alse;
thro w new Ille galAr gumen tExc eptio n(msg );
}
// HTTP SESS ION I MPLEM ENTAT ION M ETHO DS
Obje ct o = va lues. get(n ame);
pub lic S trin g get Id() {
if ( vali d) {
retu rn id ;
} el se {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
if ( o in stanc eof H ttpSe ssion Bind ingLi stene r) {
Http Sessi onBin dingE vent e =
new H ttpSe ssion Bindi ngEv ent(t his,n ame);
/**
* The s trin g man ager for t his p acka ge.
*/
pri vate Stri ngMan ager sm =
this .isV alid = isV alid;
}
StringM anage r.ge tMana ger(" org.a pache .tom cat.s essio n")
;
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- HttpSes sion Prop ertie s
retu rn ( this. creat ionTi me);
pub lic v oid setMa xInac tiveI nterv al(i nt in terva l) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
thro w new Ille galSt ateEx cept ion(m sg);
}
thro w new Ille galSt ateEx cept ion(m sg);
}
inac tive Inter val = inte rval;
}
/**
* The H TTP sessi on co ntext asso ciat ed wi th th is
session .
*/
pri vate stat ic Ht tpSes sionC ontex t se ssion Conte xt
= null;
/**
* The c urre nt ac cesse d tim e for thi s ses sion.
*/
pri vate long this Acces sedTi me = crea tionT ime;
}
/**
*
* @depr ecat ed
*/
pub lic i nt g etMax Inact iveIn terva l() {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --------- Sess ion Prope rties
/**
* Write a s erial ized versi on of thi s ses sion objec t to the speci fied
* objec t ou tput strea m.
* <p>
* <b>IM PLEM ENTAT ION N OTE</ b>: The ownin g Man ager will not be st ored
* in th e se riali zed r epres entat ion of th is Se ssion . Af ter calli ng
* <code >rea dObje ct()< /code >, yo u mu st se t the asso ciate d Ma nager
* expli citl y.
* <p>
* <b>IM PLEM ENTAT ION N OTE</ b>: Any attri bute that is no t Se riali zable
* will be s ilent ly ig nored . If you do n ot wa nt an y suc h at tribu tes,
* be su re t he <c ode>d istri butab le</ code> prop erty of ou r as socia ted
* Manag er i s set to < code> true< /cod e>.
*
* @para m st ream The o utput stre am t o wri te to
*
* @exce ptio n IOE xcept ion i f an inpu t/out put e rror occur s
*/
pri vate void writ eObje ct(Ob jectO utpu tStre am st ream) thro ws I OExce ption {
if ( sess ionCo ntext == n ull)
sess ionCo ntext = ne w Sta ndar dSess ionCo ntext ();
retu rn ( sessi onCon text) ;
}
retu rn i nacti veInt erval ;
}
pub lic l ong getLa stAcc essed Time( ) {
if ( vali d) {
retu rn la stAcc essed ;
} el se {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
}
//----- ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- ----- ----
/**
* Set t he c reati on ti me fo r thi s se ssion . Th is
method is ca lled by t he
* Manag er w hen a n exi sting Sess ion insta nce i s
reused.
*
* @para m ti me Th e new crea tion time
*/
pub lic v oid setCr eatio nTime (long tim e) {
thro w new Ille galSt ateEx cept ion(m sg);
this .cre ation Time = tim e;
this .las tAcce ssedT ime = time ;
this .thi sAcce ssedT ime = time ;
}
}
}
/**
* Retur n th e ses sion ident ifier for this
session .
*/
pub lic S trin g get Id() {
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --HttpSes sion Publ ic Me thods
/**
* Retur n th e obj ect b ound with the speci fied name in th is
session , or
* <code >nul l</co de> i f no objec t is boun d wit h tha t nam e.
*
* @para m na me Na me of the attri bute to b e ret urned
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic O bjec t get Attri bute( Strin g na me) {
/**
* Set t he s essio n ide ntifi er fo r th is se ssion .
*
* @para m id The new s essio n ide ntif ier
*/
pub lic v oid setId (Stri ng id ) {
if ( (thi s.id != nu ll) & & (ma nage r != null) &&
(m anag er in stanc eof M anage rBas e))
((Ma nager Base) mana ger). remo ve(th is);
this .id = id;
ServerSession
ServerSess
on
package org. apac he.to mcat. sessi on;
import org.a pach e.tom cat.c ore.* ;
import org.a pach e.tom cat.u til.S tring Mana ger;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. *;
import javax .ser vlet. http. *;
void va lidat e() {
// i f we have an i nacti ve in terv al, c heck to se e if
// w e've exce eded it
if ( inac tiveI nterv al != -1) {
int thisI nterv al =
(int) (Syst em.cu rrent Time Milli s() - last Acces sed) / 10 00;
if ( (man ager != nu ll) & & (ma nage r ins tance of
Manager Base) )
((Ma nager Base) mana ger). add( this) ;
}
/**
* Retur n de scrip tive infor matio n ab out t his
Session impl emen tatio n and
* the c orre spond ing v ersio n num ber, in t he
format
*
<code>& lt;de scri ption >/ <v ersio n&gt ;</co de>.
*/
pub lic S trin g get Info( ) {
retu rn 0 ;
pub lic i nt r eques tMap( Reque st re ques t ) {
Stri ng s essio nId = null ;
}
Cook ie c ookie s[]=r eques t.get Cook ies() ; // asser t !=n ull
/** Noti fica tion of co ntext shut down
*/
pub lic v oid conte xtShu tdown ( Con text ctx )
thro ws T omcat Excep tion
{
if( ctx. getDe bug() > 0 ) ctx .log ("Rem oving sess ions from " + ctx ) ;
ctx. getS essio nMana ger() .remo veSe ssion s(ctx );
}
for( int i=0; i<co okies .leng th; i++ ) {
Cook ie co okie = coo kies[ i];
if ( cooki e.get Name( ).equ als( "JSES SIONI D")) {
sessi onId = coo kie.g etVa lue() ;
sessi onId= valid ateSe ssio nId(r eques t, se ssion Id);
if (s essio nId!= null) {
r eques t.set Reque sted Sessi onIdF romCo okie( true );
}
}
Serve rSess ionMa nager ssm =
S erver Sessi onMan ager .getM anage r();
ssm.r emove Sessi on(th is);
}
}
public class Ser verSe ssion {
}
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
pri vate Hash table valu es = new H asht able( );
pri vate Hash table appS essio ns = new Hasht able( );
pri vate Stri ng id ;
pri vate long crea tionT ime = Syst em.c urren tTime Milli s();;
pri vate long this Acces sTime = cr eati onTim e;
pri vate long last Acces sed = crea tion Time;
pri vate int inact iveIn terva l = - 1;
syn chron ized void inva lidat e() {
Enum erat ion e num = appS essio ns.k eys() ;
Ser verSe ssio n(Str ing i d) {
this .id = id;
}
}
appS essio n.inv alida te();
}
}
/** Vali date and fix t he se ssion id. If t he se ssion is n ot v alid retur n nul l.
* It w ill also clean up t he se ssio n fro m loa d-bal ancin g st rings .
* @retu rn s essio nId, or nu ll if not vali d
*/
pri vate Stri ng va lidat eSess ionId (Req uest reque st, S tring ses sionI d){
// G S, W e pig gybac k the JVM id o n top of t he se ssion coo kie
// S epar ate t hem . ..
sta tic a dvic e(Sta ndard Sessi on s) : in valid ate(s ) {
befo re {
if ( !s.is Valid ())
throw new Illeg alSta teEx cepti on
( s.sm. getSt ring( "sta ndard Sessi on."
+ th isJoi nPoin t.met hodNa me
+ ". ise") );
}
}
/**
* This clas s is a du mmy i mplem entat ion of th e <co de>Ht tpSes sion Conte xt</c ode>
* inte rface , to conf orm t o the requ irem ent t hat s uch a n obj ect be re turne d
* when <cod e>Ht tpSes sion. getSe ssion Cont ext() </cod e> is call ed.
*
* @aut hor C raig R. M cClan ahan
*
* @dep recat ed A s of Java Servl et AP I 2. 1 wit h no repla cemen t. The
* int erfac e wi ll be remo ved i n a f utur e ver sion of th is AP I.
*/
final c lass Stan dardS essio nCont ext i mple ments Http Sessi onCon text {
pri vate Vect or du mmy = new Vecto r();
/**
* Retur n th e ses sion ident ifier s of all sessi ons d efine d
* withi n th is co ntext .
*
* @depr ecat ed As of J ava S ervle t AP I 2.1 with no r eplac emen t.
* This met hod m ust r eturn an e mpty <cod e>Enu merat ion</ code >
* and will be r emove d in a fut ure versi on of the API.
*/
pub lic E nume ratio n get Ids() {
}
remo veVa lue(n ame); // remov e an y exi sting bind ing
valu es.p ut(na me, v alue) ;
}
pub lic l ong getLa stAcc essed Time( ) {
retu rn l astAc cesse d;
}
pub lic O bjec t get Value (Stri ng na me) {
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("s erver Sessi on.va lue.i ae") ;
/**
* Set t he M anage r wit hin w hich this Sess ion i s
valid.
*
* @para m ma nager The new M anage r
*/
pub lic v oid setMa nager (Mana ger m anag er) {
this .man ager = man ager;
pub lic A ppli catio nSess ion g etApp lica tionS essio n(Con text cont ext,
bool ean creat e) {
Appl icat ionSe ssion appS essio n =
(App licat ionSe ssion )appS essi ons.g et(co ntext );
thro w new Ille galAr gumen tExc eptio n(msg );
}
}
retu rn ( dummy .elem ents( ));
/**
* Inval idat es th is se ssion and unbi nds a ny ob jects boun d
to it.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on
* an i nval idate d ses sion
*/
pub lic v oid inval idate () {
/**
* The s trin g man ager for t his p acka ge.
*/
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
}
// X XX
// s ync t o ens ure v alid?
pub lic E nume ratio n get Value Names () {
retu rn v alues .keys ();
}
appS essio n = n ew Ap plica tion Sessi on(id , thi s, co ntex t);
appS essio ns.pu t(con text, app Sessi on);
pub lic v oid remov eValu e(Str ing n ame) {
valu es.r emove (name );
}
}
// X XX
// m ake sure that we ha ven't gon e ove r the end of ou r
// i nact ive i nterv al -- if s o, i nvali date and c reate
// a new appS essio n
pub lic v oid setMa xInac tiveI nterv al(i nt in terva l) {
inac tive Inter val = inte rval;
}
retu rn a ppSes sion;
/**
* Retur n th e max imum time inter val, in s econd s,
between clie nt r eques ts
* befor e th e ser vlet conta iner will inva lidat e
the ses sion. A negat ive
* time indi cates that the sessi on s hould neve r
time ou t.
*
* @exce ptio n Ill egalS tateE xcept ion if th is
method is ca lled on
* an i nval idate d ses sion
*/
pub lic i nt g etMax Inact iveIn terva l() {
retu rn ( this. maxIn activ eInte rval );
pub lic i nt g etMax Inact iveIn terva l() {
retu rn i nacti veInt erval ;
}
}
}
voi d rem oveA pplic ation Sessi on(Co ntex t con text) {
appS essi ons.r emove (cont ext);
// XXX
// sync' d fo r saf ty -- no o ther thre ad sh ould be ge tting som ethin g
// from this whil e we are r eapin g. T his i sn't the m ost o ptim al
// solut ion for t his, but w e'll dete rmine some thing else lat er.
}
/**
* Calle d by cont ext w hen r eques t co mes i n so that acces ses and
* inact ivit ies c an be deal t wit h ac cordi ngly.
*/
syn chron ized void reap () {
Enum erat ion e num = appS essio ns.k eys() ;
voi d acc esse d() {
// s et l ast a ccess ed to this Acce ssTim e as it wi ll be lef t ove r
// f rom the p revio us ac cess
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Appl icati onSes sion appSe ssio n =
(Appl icati onSes sion) appS essio ns.ge t(key );
last Acce ssed = thi sAcce ssTim e;
this Acce ssTim e = S ystem .curr entT imeMi llis( );
/**
* Set t he m aximu m tim e int erval , in seco nds,
between clie nt r eques ts
* befor e th e ser vlet conta iner will inva lidat e
the ses sion. A negat ive
* time indi cates that the sessi on s hould neve r
time ou t.
*
* @para m in terva l The new maxim um i nterv al
*/
pub lic v oid setMa xInac tiveI nterv al(i nt in terva l)
{
/**
* Retur n th e <co de>Ht tpSes sion< /cod e> as socia ted w ith t he
* speci fied sess ion i denti fier.
*
* @para m id Sess ion i denti fier for which to l ook u p a s essi on
*
* @depr ecat ed As of J ava S ervle t AP I 2.1 with no r eplac emen t.
* This met hod m ust r eturn null and will be r emove d in a
* futu re v ersio n of the A PI.
*/
pub lic H ttpS essio n get Sessi on(St ring id) {
}
retu rn ( null) ;
/**
* Retur n <c ode>t rue</ code> if t he c lient does not yet k now
about t he
* sessi on, or if the clien t cho oses not to jo in th e
session . Fo r
* examp le, if th e ser ver u sed o nly cooki e-bas ed se ssion s,
and the clie nt
* has d isab led t he us e of cooki es, then a ses sion would be
new on each
* reque st.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic b oole an is New() {
/**
* The b ackg round thre ad.
*/
pri vate Thre ad th read = nul l;
req. setS essio n( se ssion );
}
* and lifec ycle conf igura tion is no t su pport ed.
* <p>
// XXX s houl d we throw exce ption or just retur n nul l ??
Once we commi t to the n ew
pub lic H ttpS essio n fin dSess ion( Cont ext c tx, S tring id ) {
* para digm, I w ould sugge st mo ving the logic impl ement ed he re b ack i nto
// S tart the backg round reap er t hread
thre adSt art() ;
T he To mcat. Next "Man ager" inte rface acts mor e lik e a
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- ---- Prope rties
// V alid ate a nd up date our c urre nt co mpone nt st ate
if ( !sta rted)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.not Start ed")) ;
star ted = fal se;
/**
* Retur n th e che ck in terva l (in sec onds) for this Manag er.
*/
pub lic i nt g etChe ckInt erval () {
// S top the b ackgr ound reape r th read
thre adSt op();
retu rn ( this. check Inter val);
}
// E xpir e all acti ve se ssion s
Sess ion sessi ons[] = fi ndSes sion s();
for (int i = 0; i < ses sions .len gth; i++) {
Stan dardS essio n ses sion = (S tanda rdSes sion) sess ions [i];
if ( !sess ion.i sVali d())
conti nue;
sess ion.e xpire ();
}
/**
* Set t he c heck inter val ( in se cond s) fo r thi s Man ager.
*
* @para m ch eckIn terva l The new chec k int erval
*/
pub lic v oid setCh eckIn terva l(int che ckInt erval ) {
ServerSessionManager
ServerSess
onManager
package org. apac he.to mcat. sessi on;
import org.a pach e.tom cat.u til.* ;
import org.a pach e.tom cat.c ore.* ;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. http. *;
// XXX
// sync' d fo r saf ty -- no o ther thre ad sh ould be ge tting som ethin g
// from this whil e we are r eapin g. T his i sn't the m ost o ptim al
// solut ion for t his, but w e'll dete rmine some thing else lat er.
syn chron ized void reap () {
Enum erat ion e num = sess ions. keys ();
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Serv erSes sion sessi on = (Ser verSe ssion )sess ions. get( key);
/**
*
* @aut hor J ames Dunc an Da vidso n [du ncan @eng. sun.c om]
* @aut hor J ason Hunt er [j ch@en g.sun .com ]
* @aut hor J ames Todd [gon zo@en g.sun .com ]
*/
sess ion.r eap() ;
sess ion.v alida te();
}
this .che ckInt erval = ch eckIn terv al;
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- --- Priva te Me thods
/**
* Retur n de scrip tive infor matio n ab out t his M anage r imp leme ntati on an d
* the c orre spond ing v ersio n num ber, in t he fo rmat
* <code >&lt ;desc ripti on&gt ;/&lt ;ver sion& gt;</ code> .
*/
pub lic S trin g get Info( ) {
/**
* Inval idat e all sess ions that have expi red.
*/
pri vate void proc essEx pires () {
long tim eNow = Sys tem.c urren tTim eMill is();
Sess ion sessi ons[] = fi ndSes sion s();
for (int i = 0; i < ses sions .len gth; i++) {
Stan dardS essio n ses sion = (S tanda rdSes sion) sess ions [i];
if ( !sess ion.i sVali d())
conti nue;
int maxIn activ eInte rval = se ssion .getM axIna ctive Inte rval( );
if ( maxIn activ eInte rval < 0)
conti nue;
int timeI dle = // T runca te, do no t rou nd up
(int) ((ti meNow - se ssio n.get LastA ccess edTim e()) / 10 00L);
if ( timeI dle > = max Inact iveI nterv al)
sessi on.ex pire( );
}
}
/**
* Retur n th e max imum numbe r of acti ve Se ssion s all owed, or -1 fo r
* no li mit.
*/
pub lic i nt g etMax Activ eSess ions( ) {
retu rn ( this. maxAc tiveS essio ns);
}
}
}
}
public class Ser verSe ssion Manag er im plem ents Sessi onMan ager {
syn chron ized void remo veSes sion( Serv erSes sion sessi on) {
Stri ng i d = s essio n.get Id();
pri vate Stri ngMan ager sm =
Stri ngMa nager .getM anage r("or g.ap ache. tomca t.ses sion" );
pri vate stat ic Se rverS essio nMana ger manag er; / / = n ew Se rver Sessi onMan ager( );
sess ion. inval idate ();
sess ions .remo ve(id );
/**
* Set t he m aximu m num ber o f act ives Sess ions allow ed, o r -1 for
* no li mit.
*
* @para m ma x The new maxim um nu mber of s essio ns
*/
pub lic v oid setMa xActi veSes sions (int max) {
/**
* Sleep for the durat ion s pecif ied by th e <co de>ch eckIn terv al</c ode>
* prope rty.
*/
pri vate void thre adSle ep() {
try {
Thre ad.sl eep(c heckI nterv al * 1000 L);
} ca tch (Inte rrupt edExc eptio n e) {
;
}
}
pro tecte d in t ina ctive Inter val = -1;
this .max Activ eSess ions = max ;
pub lic v oid remov eSess ions( Conte xt c ontex t) {
Enum erat ion e num = sess ions. keys ();
sta tic {
mana ger = new Serv erSes sionM anag er();
}
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Serv erSes sion sessi on = (Ser verSe ssion )sess ions. get( key);
Appl icati onSes sion appSe ssio n =
sessi on.ge tAppl icati onSe ssion (cont ext, false );
pri vate Hash table sess ions = new Has htabl e();
pri vate Reap er re aper;
if ( appSe ssion != n ull) {
appSe ssion .inva lidat e();
}
pri vate Serv erSes sionM anage r() {
reap er = Reap er.ge tReap er();
reap er.s etSer verSe ssion Manag er(t his);
reap er.s tart( );
}
}
}
/**
* Used by c ontex t to confi gure the sessi on ma nager 's in acti vity timeo ut.
*
* The S essi onMan ager may h ave s ome defau lt se ssion time out , the
* Conte xt o n the othe r han d has it' s tim eout set b y the dep loyme nt
* descr ipto r (we b.xml ). Th is me thod lets the Conte xt co nfor gure the
* sessi on m anage r acc ordin g to this valu e.
*
* @para m mi nutes The sessi on in acti vity timeo ut in minu tes.
*/
pub lic v oid setSe ssion TimeO ut(in t mi nutes ) {
if(- 1 != minu tes) {
// T he ma nager work s wit h se conds ...
inac tiveI nterv al = (minu tes * 60) ;
}
}
pub lic v oid acces sed( Conte xt ct x, R eques t req , Str ing i d ) {
Appl icat ionSe ssion apS= (Appl icat ionSe ssion )find Sessi on( ctx, id);
if( apS= =null ) ret urn;
Serv erSe ssion serv S=apS .getS erve rSess ion() ;
serv S.ac cesse d();
apS. acce ssed( );
}
// c ache it - no n eed t o com pute it a gain
req. setS essio n( ap S );
}
pub lic H ttpS essio n cre ateSe ssion (Con text ctx) {
Stri ng s essio nId = Sess ionId Gene rator .gene rateI d();
Serv erSe ssion sess ion = new Serv erSes sion( sessi onId) ;
sess ions .put( sessi onId, sess ion) ;
}
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- Publ ic Me thods
}
/**
* Const ruct and retur n a n ew se ssio n obj ect, based on t he d efaul t
* setti ngs speci fied by th is Ma nage r's p roper ties. The ses sion
* id wi ll b e ass igned by t his m etho d, an d ava ilabl e via the getI d()
* metho d of the retur ned s essio n. If a new s essio n can not be cr eated
* for a ny r eason , ret urn < code> null </cod e>.
*
* @exce ptio n Ill egalS tateE xcept ion if a new s essio n can not be
* inst anti ated for a ny re ason
*/
pub lic S essi on cr eateS essio n() {
/**
* Start the back groun d thr ead t hat will perio dical ly ch eck for
* sessi on t imeou ts.
*/
pri vate void thre adSta rt() {
if ( thre ad != null )
retu rn;
thre adDo ne = false ;
thre ad = new Threa d(thi s, th read Name) ;
thre ad.s etDae mon(t rue);
thre ad.s tart( );
if ( (max Activ eSess ions >= 0) &&
(s essi ons.s ize() >= m axAct iveS essio ns))
thro w new Ille galSt ateEx cept ion
(sm.g etStr ing(" stand ardM anage r.cre ateSe ssion .ise "));
}
/**
* Stop the backg round thre ad th at i s per iodic ally check ing for
* sessi on t imeou ts.
*/
pri vate void thre adSto p() {
retu rn ( super .crea teSes sion( ));
}
if ( thre ad == null )
retu rn;
}
thre adDo ne = true;
thre ad.i nterr upt() ;
try {
thre ad.jo in();
} ca tch (Inte rrupt edExc eptio n e) {
;
}
if(- 1 != inac tiveI nterv al) {
sess ion. setMa xInac tiveI nterv al(i nacti veInt erval );
}
retu rn s essio n.get Appli catio nSes sion( ctx, true );
retu rn ( this. isNew );
}
}
thre ad = null ;
pub lic H ttpS essio n fin dSess ion(C onte xt ct x, St ring id) {
Serv erSe ssion sSes sion= (Serv erSe ssion )sess ions. get(i d);
if(s Sess ion== null) retu rn nu ll;
}
retu rn s Sessi on.ge tAppl icati onSe ssion (ctx, fals e);
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- - Ba ckgro und T hread
}
this .max Inact iveIn terva l = i nter val;
/**
* The b ackg round thre ad th at ch ecks for sessi on ti meout s an d shu tdown .
*/
pub lic v oid run() {
}
voi d val idat e()
// L oop until the termi natio n se mapho re is set
whil e (! threa dDone ) {
thre adSle ep();
proc essEx pires ();
}
}
}
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Sess ion s essio n = m anage r.fi ndSes sion( id);
* coll ectio n cl ass, and h as mi nimal kno wledg e of the d etail ed r eques t
if(s essio n!=nu ll)
* proc essin g se manti cs of hand ling sess ions.
retur n ses sion. getSe ssio n();
* <p>
} ca tch (IOEx cepti on e) {
}
retu rn ( null) ;
* a Co ntext to tell the M anage r tha t we crea te wh at th e def ault sess ion
}
* time out f or t his w eb ap plica tion (spe cifie d in the d eploy ment
descrip tor)
pub lic H ttpS essio n cre ateSe ssion (Con text ctx) {
* shou ld be .
retu rn
*
manag er.cr eateS essio n(). getSe ssion ();
}
* @aut hor C raig R. M cClan ahan
*/
public final cla ss St andar dSess ionMa nage r
* Remov e al l ses sions beca use o ur a ssoci ated Conte xt is bei ng sh ut
down.
imp lemen ts S essio nMana ger {
*
* @para m ct x The cont ext t hat i s be ing s hut d own
*/
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- -Constru ctors
pub lic v oid remov eSess ions( Conte xt c tx) {
// c onte xts, we ju st wa nt to rem ove t he se ssion s of ctx!
// T he m anage r wil l sti ll ru n af ter t hat ( i.e. keep dat abase
* Creat e a new S essio nMana ger t hat adapt s to the c orres pond ing
Manager
// c onne ction open
* imple ment ation .
if ( mana ger i nstan ceof Lifec ycle ) {
*/
try {
pub lic S tand ardSe ssion Manag er() {
((Lif ecycl e) ma nager ).st op();
} ca tch ( Lifec ycleE xcept ion e) {
mana ger = new Stan dardM anage r();
throw new Illeg alSta teEx cepti on("" + e) ;
if ( mana ger i nstan ceof Lifec ycle ) {
}
try {
}
((Lif ecycl e) ma nager ).st art() ;
}
} ca tch ( Lifec ycleE xcept ion e) {
throw new Illeg alSta teEx cepti on("" + e) ;
}
}
/**
* Used by c ontex t to confi gure the sessi on ma nager 's in acti vity
timeout .
*
* The S essi onMan ager may h ave s ome defau lt se ssion time out , the
}
* Conte xt o n the othe r han d has it' s tim eout set b y the dep loyme nt
* descr ipto r (we b.xml ). Th is me thod lets the Conte xt co nfor gure the
/**
* Grace full y ter minat e the acti ve u se of the publi c met hods of t his
* compo nent . Th is me thod shoul d be the last one c alled on a giv en
* insta nce of th is co mpone nt.
*
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s no t bee n sta rted
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s al ready
* been sto pped
* @exce ptio n Lif ecycl eExce ption if this compo nent detec ts a fata l err or
* that nee ds to be r eport ed
*/
pub lic v oid stop( ) thr ows L ifecy cleE xcept ion {
/**
* Name to r egist er fo r the back grou nd th read.
*/
pri vate Stri ng th readN ame = "Sta ndar dMana ger";
}
11
try {
* XXX - At pres ent, there is n o way (vi a the Sess ionMa nager int erfac e)
for
}
/**
* The b ackg round thre ad co mplet ion semap hore.
*/
pri vate bool ean t hread Done = fal se;
}
}
// c ache the HttpS essio n - a void anot her f ind
* <p>
* XXX - At pres ent, use o f <co de>St anda rdMan ager< /code > is hard code d,
((Lif ecycl e) ma nager ).co nfigu re(nu ll);
appS essio n.val idate ();
}
}
((Se ssion ) ses sion) .acce ss() ;
* Spec ializ ed i mplem entat ion o f org .apa che.t omcat .core .Sess ionM anage r
* that adap ts t o the new compo nent- base d Man ager imple menta tion .
* <b>I MPLEM ENTA TION NOTE< /b>:
Manager /Sess ion
// V alid ate a nd up date our c urre nt co mpone nt st ate
if ( !con figur ed)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.not Confi gured "));
if ( star ted)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.alr eadyS tarte d")) ;
star ted = tru e;
/**
* Has t his compo nent been start ed y et?
*/
pri vate bool ean s tarte d = f alse;
if ( sess ionId != n ull & & ses sion Id.le ngth( )!=0) {
// G S, We are in a probl em h ere, we ma y act ually get
// m ultip le Se ssion cook ies (one for t he ro ot
// c ontex t and one for t he r eal c ontex t... or ol d se ssion
// c ookie . We must check for vali dity in th e cur rent cont ext.
Cont ext c tx=re quest .getC onte xt();
Sess ionMa nager sM = ctx. getS essio nMana ger() ;
if(n ull ! = sM. findS essio n(ct x, se ssion Id)) {
sM.ac cesse d(ctx , req uest , ses sionI d );
reque st.se tRequ ested Sess ionId (sess ionId );
if( d ebug> 0 ) c m.log (" F inal sessi on id " + sess ionId );
retur n ses sionI d;
}
}
retu rn n ull;
pub lic s tati c Ser verSe ssion Manag er g etMan ager( ) {
retu rn m anage r;
}
}
// C ause this sess ion t o exp ire
expi re() ;
retu rn v alues .get( name) ;
if ( appS essio n == null && cr eate ) {
* Prepa re f or th e beg innin g of acti ve us e of the p ublic met hods of th is
* compo nent . Th is me thod shoul d be call ed af ter < code> conf igure ()</c ode>,
* and b efor e any of t he pu blic meth ods o f the comp onent are util ized.
*
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s no t yet been
* conf igur ed (i f req uired for this comp onent )
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s al ready been
* star ted
* @exce ptio n Lif ecycl eExce ption if this compo nent detec ts a fata l err or
* that pre vents this comp onent fro m bei ng us ed
*/
pub lic v oid start () th rows Lifec ycle Excep tion {
/**
* The m axim um nu mber of ac tive Sess ions allow ed, o r -1 for no li mit.
*/
pro tecte d in t max Activ eSess ions = -1 ;
if( debu g>0 ) cm.l og(" Orig sess ionId " + sess ionId );
if ( null != s essio nId) {
int idex = ses sionI d.las tInd exOf( SESSI ONID_ ROUTE _SEP );
if(i dex > 0) {
sessi onId = ses sionI d.su bstri ng(0, idex );
}
}
}
Vect or r esult s = n ew Ve ctor( );
Enum erat ion a ttrs = get Attri bute Names ();
whil e (a ttrs. hasMo reEle ments ()) {
Stri ng at tr = (Stri ng) a ttrs .next Eleme nt();
resu lts.a ddEle ment( attr) ;
}
Stri ng n ames[ ] = n ew St ring[ resu lts.s ize() ];
for (int i = 0; i < nam es.le ngth ; i++ )
name s[i] = (St ring) resu lts. eleme ntAt( i);
retu rn ( names );
retu rn ( this. manag er);
if( sess ion = = nul l) re turn;
if ( sess ion i nstan ceof Sessi on)
// X XX X XX a manag er ma y be shar ed by mult iple
/**
retu rn ( this. info) ;
}
Http Sess ion s essio n=fin dSess ion( ctx, id);
/**
// ---- ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- ---- - Pri vate Class
/**
* Retur n th e Man ager withi n whi ch t his S essio n
is vali d.
*/
pub lic M anag er ge tMana ger() {
* @para m se ssion The sessi on to be marke d
pub lic v oid acces sed(C ontex t ctx , Re quest req, Stri ng id ) {
/**
/**
node = a ttrib utes. getNa medIt em(" maxIn activ eInte rval" );
if ( node != n ull) {
try {
setMa xInac tiveI nterv al(I ntege r.par seInt (node .get NodeV alue( )));
} ca tch ( Throw able t) {
;
// XXX - Thr ow e xcept ion?
}
}
/**
* The d escr iptiv e inf ormat ion a bout this impl ement ation .
*/
pri vate stat ic fi nal S tring info = " Stand ardMa nager /1.0" ;
// XXX w hat is th e cor rect behav ior if th e ses sion is in vali d ?
// We ma y st ill s et it and just retu rn se ssion inva lid.
cro sscut inv alida te(St andar dSess ion s): s & (i nt ge tMaxI nact iveIn terva l() |
l ong g etCre atio nTime () |
O bject getA ttri bute( Strin g) |
E numer ation get Attri buteN ames( ) |
S tring [] ge tVal ueNam es() |
v oid i nvali date () |
b oolea n isN ew() |
v oid r emove Attr ibute (Stri ng) |
v oid s etAtt ribu te(St ring, Obje ct));
/**
* Retur n th e obj ect b ound with the speci fied name in th is
session , or
* <code >nul l</co de> i f no objec t is boun d wit h tha t nam e.
*
* @para m na me Na me of the value to be re turne d
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d
by
* <cod e>ge tAttr ibute ()</c ode>
*/
pub lic O bjec t get Value (Stri ng na me) {
Thi s sh ould be
*
*/
import org.a pach e.tom cat.c ore.S essio nMan ager;
import org.a pach e.tom cat.u til.S essio nUti l;
}
}
retu rn ( attri butes .keys ());
/**
* Retur n th e set of n ames of ob ject s bou nd to this
session . If the re
* are n o su ch ob jects , a z ero-l engt h arr ay is retu rned.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d
by
* <cod e>ge tAttr ibute Names ()</c ode>
*/
pub lic S trin g[] g etVal ueNam es() {
* Mark the speci fied sessi on's last acce ssed time.
* calle d fo r eac h req uest by a Requ estIn terce ptor.
import org.a pach e.tom cat.c ore.R eques t;
import org.a pach e.tom cat.c ore.R espon se;
* sessi on m anage r acc ordin g to this valu e.
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- Ins tance
Variabl es
*
* @para m mi nutes The sessi on in acti vity timeo ut in minu tes.
*/
/**
pub lic v oid setSe ssion TimeO ut(in t mi nutes ) {
* The M anag er im pleme ntati on we are actu ally using .
if(- 1 != minu tes) {
*/
// T he ma nager work s wit h se conds ...
pri vate Mana ger m anage r = n ull;
mana ger.s etMax Inact iveIn terv al(mi nutes * 60 );
}
}
thro w new Ille galAr gumen tExc eptio n(msg );
pub lic l ong getCr eatio nTime () {
retu rn c reati onTim e;
node = a ttrib utes. getNa medIt em(" maxAc tiveS essio ns");
if ( node != n ull) {
try {
setMa xActi veSes sions (Int eger. parse Int(n ode.g etNo deVal ue()) );
} ca tch ( Throw able t) {
;
// XXX - Thr ow e xcept ion?
}
}
/**
import org.a pach e.tom cat.c atali na.*;
import org.a pach e.tom cat.c ore.C ontex t;
* the core leve l.
node = a ttrib utes. getNa medIt em(" check Inter val") ;
if ( node != n ull) {
try {
setCh eckIn terva l(Int eger .pars eInt( node. getNo deVa lue() ));
} ca tch ( Throw able t) {
;
// XXX - Thr ow e xcept ion?
}
}
/**
* Has t his compo nent been confi gure d yet ?
*/
pri vate bool ean c onfig ured = fal se;
// S eria lize the a ttrib ute c ount and the attri bute valu es
stre am.w riteO bject (new Integ er(r esult s.siz e())) ;
Enum erat ion n ames = res ults. elem ents( );
whil e (n ames. hasMo reEle ments ()) {
Stri ng na me = (Stri ng) n ames .next Eleme nt();
stre am.wr iteOb ject( name) ;
stre am.wr iteOb ject( attri bute s.get (name ));
}
}
retu rn ( getAt tribu te(na me));
}
}
// P arse and proce ss ou r con figu ratio n par amete rs
if ( !("M anage r".eq uals( param eter s.get NodeN ame() )))
retu rn;
Name dNod eMap attri butes = pa rame ters. getAt tribu tes() ;
Node nod e = n ull;
/**
* The i nter val ( in se conds ) bet ween chec ks fo r exp ired sess ions.
*/
pri vate int check Inter val = 60;
retu rn ( this. info) ;
pub lic v oid putVa lue(S tring name , Ob ject value ) {
if ( name == n ull) {
Stri ng ms g = s m.get Strin g("s erver Sessi on.va lue.i ae") ;
pub lic S trin g get Id() {
retu rn i d;
}
// V alid ate a nd up date our c urre nt co mpone nt st ate
if ( conf igure d)
thro w new Life cycle Excep tion
(sm.g etStr ing(" stand ardM anage r.alr eadyC onfig ured "));
conf igur ed = true;
if ( para meter s == null)
retu rn;
import javax .ser vlet. http. Cooki e;
import javax .ser vlet. http. HttpS essio n;
}
}
/**
* Retur n th e las t tim e the clie nt s ent a requ est
associa ted w ith this
* sessi on, as th e num ber o f mil lise conds sinc e
midnigh t, Ja nuar y 1, 1970
* GMT. Act ions that your appli cati on ta kes,
such as gett ing or se tting
* a val ue a ssoci ated with the s essi on, d o not
affect the a cces s tim e.
*/
pub lic l ong getLa stAcc essed Time( ) {
retu rn ( this. lastA ccess edTim e);
whil e (e num.h asMor eElem ents( )) {
Obje ct ke y = e num.n extEl emen t();
Appl icati onSes sion appSe ssio n =
(Appl icati onSes sion) appS essio ns.ge t(key );
/**
* Stan dard impl ement ation of t he <b >Man ager< /b> i nterf ace t hat provi des
* no s essio n pe rsist ence or di strib utab le ca pabil ities , but doe s sup port
* an o ption al, confi gurab le, m aximu m nu mber of ac tive sessi ons allow ed.
* <p>
* Life cycle con figur ation of t his c ompo nent assum es an XML node
* in t he fo llow ing f ormat :
* <cod e>
*
<M anag er cl assNa me="o rg.ap ache .tomc at.se ssion .Stan dard Manag er"
*
check Inter val=" 60" m axAc tiveS essio ns="- 1"
*
maxIn activ eInte rval= "-1" />
* </co de>
* wher e you can adju st th e fol lowin g pa ramet ers, with defau lt v alues
* in s quare bra ckets :
* <ul>
* <li> <b>ch eckI nterv al</b > - T he in terv al (i n sec onds) betw een backg round
*
threa d ch ecks for e xpire d ses sion s. [ 60]
* <li> <b>ma xAct iveSe ssion s</b> - Th e ma ximum numb er of sess ions allo wed t o
*
be ac tive at o nce, or -1 for no l imit. [-1 ]
* <li> <b>ma xIna ctive Inter val</ b> - The defau lt ma ximum numb er o f sec onds of
*
inact ivit y bef ore w hich the s ervl et co ntain er is allo wed to ti me ou t
*
a ses sion , or -1 fo r no limit . T his v alue shoul d be over ridde n fro m
*
the d efau lt se ssion time out s peci fied in th e web appl icat ion d eploy ment
*
descr ipto r, if any. [-1 ]
* </ul >
*
* @aut hor C raig R. M cClan ahan
* @ver sion $Rev ision : 1.1 .1.1 $ $Da te: 2000/ 05/02 21:2 8:30 $
*/
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- Ins tance Vari ables
Stri ng s ig="; jsess ionid =";
int foun dAt=- 1;
if( debu g>0 ) cm.l og(" XXX R URI= " + r eques t.get Reque stUR I());
if ( (fou ndAt= reque st.ge tRequ estU RI(). index Of(si g))!= -1){
sess ionId =requ est.g etReq uest URI() .subs tring (foun dAt+ sig.l ength ());
// r ewrit e URL , do I nee d to do a nythi ng mo re?
requ est.s etReq uestU RI(re ques t.get Reque stURI ().su bstr ing(0 , fou ndAt) );
sess ionId =vali dateS essio nId( reque st, s essio nId);
if ( sessi onId! =null ){
reque st.se tRequ ested Sess ionId FromU RL(tr ue);
}
}
retu rn 0 ;
// ---- ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- Pub lic
Methods
import java. io.I OExce ption ;
/**
* Confi gure this comp onent , bas ed o n the spec ified conf igur ation
* param eter s. T his m ethod shou ld b e cal led i mmedi ately aft er th e
* compo nent inst ance is cr eated , an d bef ore < code> start ()</ code>
* is ca lled .
*
* @para m pa ramet ers C onfig urati on p arame ters for t his c ompo nent
* (<B> FIXM E: Wh at ob ject type shou ld th is re ally be?)
*
* @exce ptio n Ill egalS tateE xcept ion if th is co mpone nt ha s al ready been
* conf igur ed an d/or start ed
* @exce ptio n Lif ecycl eExce ption if this compo nent detec ts a fata l err or
* in t he c onfig urati on pa ramet ers it wa s giv en
*/
pub lic v oid confi gure( Node param eter s)
thro ws L ifecy cleEx cepti on {
public final cla ss St andar dMana ger
ext ends Mana gerBa se
imp lemen ts L ifecy cle, Runna ble {
}
}
if ( thisI nterv al > inact iveI nterv al) {
inval idate ();
/**
* Core impl emen tatio n of a ser ver s essi on
*
* @aut hor J ames Dunc an Da vidso n [du ncan @eng. sun.c om]
* @aut hor J ames Todd [gon zo@en g.sun .com ]
*/
// ----- ---- ----- ----- ----- ----- ---- ----- ----- ----- ----- - Li fecyc le Me thods
java. io.I OExce ption ;
java. util .Enum erati on;
java. util .Hash table ;
java. util .Vect or;
org.a pach e.tom cat.c atali na.*;
javax .ser vlet. http. Cooki e;
javax .ser vlet. http. HttpS essio n;
org.a pach e.tom cat.u til.S tring Mana ger;
org.w 3c.d om.Na medNo deMap ;
org.w 3c.d om.No de;
}
/**
* Retur n an <cod e>Enu merat ion</ code > of
<code>S tring </co de> o bject s
* conta inin g the name s of the o bjec ts bo und t o thi s
session .
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic E nume ratio n get Attri buteN ames () {
StandardSessionManager
S
andardSess onManager
package org. apac he.to mcat. sessi on;
package org. apac he.to mcat. sessi on;
import
import
import
import
import
import
import
import
import
import
}
// A ccum ulate the names of s eria lizab le at tribu tes
Vect or r esult s = n ew Ve ctor( );
Enum erat ion a ttrs = get Attri bute Names ();
whil e (a ttrs. hasMo reEle ments ()) {
Stri ng at tr = (Stri ng) a ttrs .next Eleme nt();
Obje ct va lue = attr ibute s.ge t(att r);
if ( value inst anceo f Ser iali zable )
resul ts.ad dElem ent(a ttr) ;
}
retu rn ( attri butes .get( name) );
}
resp onse .addH eader ( Coo kieTo ols. getCo okieH eader Name( cook ie),
Coo kieTo ols. getCo okieH eader Value (coo kie)) ;
cook ie.s etVer sion( 0);
resp onse .addH eader ( Coo kieTo ols. getCo okieH eader Name( cook ie),
Coo kieTo ols. getCo okieH eader Value (coo kie)) ;
pub lic v oid setCo ntext Manag er( C onte xtMan ager cm ) {
this .cm= cm;
}
// W rite the scala r ins tance var iable s (ex cept Manag er)
stre am.w riteO bject (new Long( crea tionT ime)) ;
stre am.w riteO bject (id);
stre am.w riteO bject (new Long( last Acces sedTi me));
stre am.w riteO bject (new Integ er(m axIna ctive Inter val)) ;
stre am.w riteO bject (new Boole an(i sNew) );
stre am.w riteO bject (new Boole an(i sVali d));
retu rn ( this. id);
}
Cook ie c ookie = ne w Coo kie(" JSES SIONI D",
r eqSe ssion Id);
cook ie.s etMax Age(- 1);
cook ie.s etPat h(ses sionP ath);
cook ie.s etVer sion( 1);
pub lic v oid setDe bug( int i ) {
Syst em.o ut.pr intln ("Set debu g to " + i);
debu g=i;
}
}
/**
* Retur n th e ses sion conte xt wi th w hich this sessi on is
associa ted.
*
* @depr ecat ed As of V ersio n 2.1 , th is me thod is de preca ted
and has no
* repl acem ent. It w ill b e rem oved in a futu re ve rsion of
the
* Java Ser vlet API.
*/
pub lic H ttpS essio nCont ext g etSes sion Conte xt() {
thro w new Ille galSt ateEx cept ion(m sg);
pub lic H ttpS essio nCont ext g etSes sion Conte xt() {
retu rn n ew Se ssion Conte xtImp l();
}
// G S, p iggyb ack t he jv m rou te o n the sess ion i d.
if(! sess ionPa th.eq uals( "/")) {
Stri ng jv mRout e = r reque st.g etJvm Route ();
if(n ull ! = jvm Route ) {
reqSe ssion Id = reqSe ssio nId + SESS IONID _ROUT E_SE P + j vmRou te;
}
}
// GS, s epar ates the s essio n id from the jvm r oute
sta tic f inal char SESS IONID _ROUT E_SE P = ' .';
int debu g=0;
Con textM anag er cm ;
// D eser ializ e the attr ibute cou nt an d att ribut e val ues
int n = ((Int eger) stre am.re adOb ject( )).in tValu e();
for (int i = 0; i < n; i++) {
Stri ng na me = (Stri ng) s trea m.rea dObje ct();
Obje ct va lue = (Obj ect) stre am.re adObj ect() ;
attr ibute s.put (name , val ue);
}
((Ht tpSes sionB indin gList ener )o).v alueU nboun d(e);
valu es.r emove (name );
}
pub lic l ong getCr eatio nTime () {
if ( vali d) {
retu rn cr eatio nTime ;
} el se {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
// G S, s et th e pat h att ribut e to the cooki e. Th is wa y
// m ulti ple s essio n coo kies can be us ed, o ne fo r eac h
// c onte xt.
Stri ng s essio nPath = rr eques t.ge tCont ext() .getP ath() ;
if(s essi onPat h.len gth() == 0 ) {
sess ionPa th = "/";
}
/**
* Will proc ess the r eques t and dete rmin e the sess ion I d, an d se t it
* in t he Re ques t.
* It a lso m arks the sessi on as acce ssed .
*
* This impl emen tatio n onl y han dles Cook ies s essio ns, p lease ext end o r
* add new i nter cepto rs fo r oth er me thod s.
*
*/
public class Ses sionI nterc eptor exte nds Base Inter cepto r imp leme nts R eques tInte rcept or {
// D eser ializ e the scal ar in stan ce va riabl es (e xcept Man ager)
crea tion Time = ((L ong) strea m.re adObj ect() ).lon gValu e();
id = (St ring) stre am.re adObj ect( );
last Acce ssedT ime = ((Lo ng) s trea m.rea dObje ct()) .long Valu e();
maxI nact iveIn terva l = ( (Inte ger) stre am.re adObj ect() ).in tValu e();
isNe w = ((Boo lean) stre am.re adOb ject( )).bo olean Value ();
isVa lid = ((B oolea n) st ream. read Objec t()). boole anVal ue() ;
/**
* Retur n th e tim e whe n thi s ses sion was creat ed, i n
millise conds sin ce
* midni ght, Janu ary 1 , 197 0 GMT .
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is
called on an
* inva lida ted s essio n
*/
pub lic l ong getCr eatio nTime () {
}
thro w new Ille galSt ateEx cept ion(m sg);
}
}
pub lic i nt b efore Body( Requ est r requ est, Respo nse r espon se ) {
Stri ng r eqSes sionI d = r espon se.g etSes sionI d();
if( debu g>0 ) cm.l og("B efore Bod y " + reqS essio nId ) ;
if( reqS essio nId== null)
retu rn 0;
import org.a pach e.tom cat.c ore.* ;
import org.a pach e.tom cat.u til.* ;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. http. *;
pub lic S essi onInt ercep tor() {
}
}
StandardManager
S
andardManager
package org. apac he.to mcat. reque st;
this .isN ew = isNew ;
}
/**
* Set t he < code> isVal id</c ode> flag for this sessi on.
*
* @para m is Valid The new v alue for the
<code>i sVali d</c ode> flag
*/
voi d set Vali d(boo lean isVal id) {
thro w new Ille galSt ateEx cept ion(m sg);
}
if ( thisI nterv al > inact iveI nterv al) {
inval idate ();
}
}
}
SessionInterceptor
Sess
on n ercep or
}
// T ell our M anage r tha t thi s Se ssion has been recyc led
if ( (man ager != nu ll) & & (ma nage r ins tance of
Manager Base) )
((Ma nager Base) mana ger). recy cle(t his);
name s.co pyInt o(val ueNam es);
this .ina ctive Inter val = cont ext. getSe ssion TimeO ut();
}
/**
* Remov e th e obj ect b ound with the speci fied name from this sess ion. If
* the s essi on do es no t hav e an obje ct bo und w ith t his n ame, this meth od
* does noth ing.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueUnb ound( )</co de> o n th e obj ect.
*
* @para m na me Na me of the objec t to remo ve fr om th is se ssio n.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d by
* <cod e>re moveA ttrib ute() </cod e>
*/
pub lic v oid remov eValu e(Str ing n ame) {
}
}
}
whil e (e .hasM oreEl ement s()) {
name s.add Eleme nt(e. nextE leme nt()) ;
}
}
// M ark this sessi on as inva lid
setV alid (fals e);
supe r();
this .man ager = man ager;
pub lic O bjec t get Attri bute( Strin g na me) {
if ( ! va lid) {
Stri ng ms g = s m.get Strin g("a pplic ation Sessi on.se ssio n.ise ");
/**
* Core impl emen tatio n of an ap plica tion leve l ses sion
*
* @aut hor J ames Dunc an Da vidso n [du ncan @eng. sun.c om]
* @aut hor J ason Hunt er [j ch@en g.sun .com ]
* @aut hor J ames Todd [gon zo@en g.sun .com ]
*/
sync hron ized (attr ibute s) {
Obje ct ob ject = att ribut es.g et(na me);
if ( objec t == null)
retur n;
attr ibute s.rem ove(n ame);
//
S ystem .out. print ln( "Remo ving attri bute " + name );
if ( objec t ins tance of Ht tpSe ssion Bindi ngLis tener ) {
((Htt pSess ionBi nding List ener) obje ct).v alueU nbou nd
( new H ttpSe ssion Bind ingEv ent(( HttpS essio n) t his, name) );
}
}
if ( (man ager != nu ll) & & (ma nage r ins tance of
Manager Base) )
((Ma nager Base) mana ger). remo ve(th is);
/**
* Const ruct a ne w Ses sion assoc iate d wit h the
specifi ed Ma nage r.
*
* @para m ma nager The manag er wi th w hich this
Session is a ssoc iated
*/
pub lic S tand ardSe ssion (Mana ger m anag er) {
valu es.p ut(na me, v alue) ;
/**
* @depr ecat ed
*/
pub lic O bjec t get Value (Stri ng na me) {
retu rn g etAtt ribut e(nam e);
}
/**
* Remov e th e obj ect b ound with the speci fied name from this sess ion. If
* the s essi on do es no t hav e an obje ct bo und w ith t his n ame, this meth od
* does noth ing.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueUnb ound( )</co de> o n th e obj ect.
*
* @para m na me Na me of the objec t to remo ve fr om th is se ssio n.
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*/
pub lic v oid remov eAttr ibute (Stri ng n ame) {
/**
* Perfo rm t he in terna l pro cessi ng r equir ed to inva lidat e
this se ssion ,
* witho ut t rigge ring an ex cepti on i f the sess ion h as
already expi red.
*/
pub lic v oid expir e() {
// ----- ---- ----- ----- ----- ----- ---- ----- ----- --------- ----- - Co nstru ctors
}
package org. apac he.to mcat. sessi on;
import org.a pach e.tom cat.c ore.* ;
import org.a pach e.tom cat.u til.S tring Mana ger;
import java. io.* ;
import java. net. *;
import java. util .*;
import javax .ser vlet. *;
import javax .ser vlet. http. *;
setA ttri bute( name, valu e);
}
this .las tAcce ssedT ime = this .thi sAcce ssedT ime;
this .thi sAcce ssedT ime = Syst em.c urren tTime Milli s();
this .isN ew=fa lse;
}
// remov e an y exi sting bind ing
if ( valu e != null && va lue i nsta nceof Http Sessi onBin ding Liste ner) {
Http Sessi onBin dingE vent e =
new H ttpSe ssion Bindi ngEv ent(t his, name) ;
* Bind an o bject to t his s essio n, u sing the s pecif ied n ame. If an ob ject
* of th e sa me na me is alre ady b ound to t his s essio n, th e ob ject is
* repla ced.
* <p>
* After thi s met hod e xecut es, a nd i f the obje ct im pleme nts
* <code >Htt pSess ionBi nding Liste ner< /code >, th e con taine r ca lls
* <code >val ueBou nd()< /code > on the objec t.
*
* @para m na me Na me to whic h the obj ect i s bou nd, c annot be null
* @para m va lue O bject to b e bou nd, canno t be null
*
* @exce ptio n Ill egalS tateE xcept ion if th is me thod is ca lled on a n
* inva lida ted s essio n
*
* @depr ecat ed As of V ersio n 2.2 , th is me thod is re place d by
* <cod e>se tAttr ibute ()</c ode>
*/
pub lic v oid putVa lue(S tring name , Ob ject value ) {
retu rn ( (Http Sessi on) t his);
}
}
modular aspects
HTTPRequest
getCookies()
getRequestURI()(doc)
getSession()
getRequestedSessionId()
...
SessionInterception
requestMap(request)
beforeBody(req, resp)
...
Session
HTTPResponse
getAttribute(name)
setAttribute(name, val)
invalidate()
...
getRequest()
setContentType(contentType)
getOutptutStream()
setSessionId(id)
...
Servlet
12
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AspectJ™ is…
• a small and well-integrated extension to Java
• a general-purpose AO language
– just as Java is a general-purpose OO language
• freely available implementation
– compiler is Open Source
• includes IDE support
– emacs, JBuilder, Forte
• user feedback is driving language design
– users@aspectj.org
– support@aspectj.org
• currently at 1.0b1 release
13
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
expected benefits of using AOP
• good modularity,
even for crosscutting concerns
–
–
–
–
less tangled code
more natural code
shorter code
easier maintenance and evolution
• easier to reason about, debug, change
– more reusable
• library aspects
• plug and play aspects when appropriate
14
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
looking ahead
problem structure
Part IV:
crosscutting in the design, and
how to use AspectJ to capture that
AspectJ mechanisms
Part II:
crosscutting in the code
mechanisms AspectJ provides
15
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
outline
• I AOP overview
– brief motivation, essence of AOP idea
• II AspectJ language mechanisms
– basic concepts, language semantics
• III development environment
– IDE support, running the compiler, debugging etc.
• IV using aspects
– aspect examples, how to use AspectJ to program
aspects, exercises to solidify the ideas
• V related work
– survey of other activities in the AOP community
16
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Part II
Basic Mechanisms of AspectJ
goals of this chapter
• present basic language mechanisms
– using one simple example
• emphasis on what the mechanisms do
• small scale motivation
• later chapters elaborate on
– environment, tools
– larger examples, design and SE issues
18
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
basic mechanisms
• 1 overlay onto Java
– dynamic join points
• “points in the execution” of Java programs
• 4 small additions to Java
– pointcuts
• pick out join points and values at those points
– primitive pointcuts
– user-defined pointcuts
– advice
• additional action to take at join points in a pointcut
– intra-class declarations (aka “open classes”)
– aspect
• a modular unit of crosscutting behavior
– comprised of advice, intra-class declarations,
field,constructor and method declarations
19
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
a simple figure editor
factory methods
Display
* FigureElement
Figure
makePoint(..)
makeLine(..)
Point
setX(int)
setY(int)
moveBy(int, int)
Line
2
setP1(Point)
setP2(Point)
20
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
operations that
move elements
a simple figure editor
class Line implements FigureElement{
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) { this.p1 = p1; }
void setP2(Point p2) { this.p2 = p2; }
void moveBy(int dx, int dy) { ... }
}
class Point implements FigureElement {
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) { this.x = x; }
void setY(int y) { this.y = y; }
void moveBy(int dx, int dy) { ... }
}
21
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
display updating
• collection of figure elements
–
–
–
–
that move periodically
must refresh the display as needed
complex collection
asynchronous events
• other examples
– session liveness
– value caching
22
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
we will initially assume
just a single display
join points
key points in dynamic call graph
a method is called
and returns or
throws
a Figure
dispatch
a method is
called
and returns
or throws
a Line
a method executes
and returns or throws
a method executes
and returns or throws
23
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
dispatch
join point terminology
a Line
method call
join points
dispatch
method
execution
join points
• several kinds of join points
–
–
–
–
–
method & constructor call join points
method & constructor execution join points
field get & set join points
exception handler execution join points
static & dynamic initialization join points
24
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
join point terminology
key points in dynamic call graph
all join points on this slide are
within the control flow of
this join point
a Line
a
Figure
repeated calls result in new join points
25
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
primitive pointcuts
“a means of identifying join points”
a pointcut is a kind of predicate on join points that:
– can match or not match any given join point and
– optionally, can pull out some of the values at that join point
call(void Line.setP1(Point))
matches if the join point is a method call with this signature
26
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
pointcut composition
pointcuts compose like predicates, using &&, || and !
a “void Line.setP1(Point)” call
or
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
a “void Line.setP2(Point)” call
each time a Line receives a
“void setP1(Point)” or “void setP2(Point)” method call
27
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
user-defined pointcuts
defined use the pointcut construct
user-defined (aka named) pointcuts
– can be used in the same way as primitive pointcuts
name
parameters
pointcut move():
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
more on parameters
and how pointcut can
expose values at join
points in a few slides
28
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
pointcuts
user-defined pointcut designator
pointcut move():
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
primitive pointcut designator, can also be:
- call, execution
- this, target
- get, set
- within, withincode
- handler
- cflow, cflowbelow
- initialization, staticinitialization
29
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
after advice
action to take after
computation under join points
after advice runs
“on the way back out”
a Line
pointcut move():
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
after() returning: move() {
<code here runs after each move>
}
30
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
a simple aspect
DisplayUpdating v1
an aspect defines a special class
that can crosscut other classes
aspect DisplayUpdating {
pointcut move():
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
after() returning: move() {
Display.update();
}
}
box means complete running code
31
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
without AspectJ
DisplayUpdating v1
class Line {
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
Display.update();
}
void setP2(Point p2) {
this.p2 = p2;
Display.update();
}
}
• what you would expect
– update calls are tangled through the code
– “what is going on” is less explicit
32
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
pointcuts
can cut across multiple classes
pointcut move():
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point)) ||
call(void Point.setX(int))
||
call(void Point.setY(int));
33
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
pointcuts
can use interface signatures
pointcut move():
call(void FigureElement.moveBy(int, int)) ||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point))
||
call(void Point.setX(int))
||
call(void Point.setY(int));
34
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
a multi-class aspect
DisplayUpdating v2
aspect DisplayUpdating {
pointcut move():
call(void FigureElement.moveBy(int, int)) ||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point))
||
call(void Point.setX(int))
||
call(void Point.setY(int));
after() returning: move() {
Display.update();
}
}
35
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
using values at join points
demonstrate first, explain in detail afterwards
• pointcut can explicitly expose certain values
• advice can use value
parameter
mechanism
being used
pointcut move(FigureElement figElt):
target(figElt) &&
(call(void FigureElement.moveBy(int, int)) ||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point))
||
call(void Point.setX(int))
||
call(void Point.setY(int)));
after(FigureElement fe) returning: move(fe) {
<fe is bound to the figure element>
}
36
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
explaining parameters…
of user-defined pointcut designator
• variable in place of type name in pointcut designator
– pulls corresponding value out of join points
• variable bound in user-defined pointcut designator
– makes value accessible on pointcut
pointcut parameters
pointcut move(Line l):
target(l) &&
(call(void Line.setP1(Point)) ||
call(void Line.setP2(Point)));
typed variable in place of type name
after(Line line): move(line) {
<line is bound to the line>
}
37
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
explaining parameters…
of advice
• variable bound in advice
• variable in place of type name in pointcut designator
– pulls corresponding value out of join points
– makes value accessible within advice
pointcut move(Line l):
target(l) &&
(call(void Line.setP1(Point)) ||
call(void Line.setP2(Point)));
advice parameters
after(Line line): move(line) {
<line is bound to the line>
}
38
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
typed variable in place
of type name
explaining parameters…
• value is ‘pulled’
– right to left across ‘:’
left side : right side
– from pointcut designators to user-defined pointcut designators
– from pointcut to advice
pointcut move(Line l):
target(l) &&
(call(void Line.setP1(Point)) ||
call(void Line.setP2(Point)));
after(Line line): move(line) {
<line is bound to the line>
}
39
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
target
primitive pointcut designator
target(<type name>)
any join point at which
target object is an instance of type (or class) name
target(Point)
target(Line)
target(FigureElement)
“any join point” means it matches join points of all kinds
•
•
•
•
•
method & constructor call join points
method & constructor execution join points
field get & set join points
exception handler execution join points
static & dynamic initialization join points
40
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
an idiom for…
getting target object in a polymorphic pointcut
target(<supertype name>) &&
• does not further restrict the join points
• does pick up the target object
pointcut move(FigureElement figElt):
target(figElt) &&
(call(void Line.setP1(Point)) ||
call(void Line.setP2(Point)) ||
call(void Point.setX(int))
||
call(void Point.setY(int)));
after(FigureElement fe): move(fe) {
<fe is bound to the figure element>
}
41
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
context & multiple classes
DisplayUpdating v3
aspect DisplayUpdating {
pointcut move(FigureElement figElt):
target(figElt) &&
(call(void FigureElement.moveBy(int, int)) ||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point))
||
call(void Point.setX(int))
||
call(void Point.setY(int)));
after(FigureElement fe): move(fe) {
Display.update(fe);
}
}
42
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
without AspectJ
class Line {
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
}
void setP2(Point p2) {
this.p2 = p2;
}
}
class Point
{
private int x = 0, y= 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) {
this.x = x;
}
void setY(int y) {
this.y = y;
}
}
43
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
without AspectJ
DisplayUpdating v1
class Line {
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
Display.update();
}
void setP2(Point p2) {
this.p2 = p2;
Display.update();
}
}
class Point
{
private int x = 0, y= 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) {
this.x = x;
}
void setY(int y) {
this.y = y;
}
}
44
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
without AspectJ
DisplayUpdating v2
class Line {
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
Display.update();
}
void setP2(Point p2) {
this.p2 = p2;
Display.update();
}
}
class Point
{
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) {
this.x = x;
Display.update();
}
void setY(int y) {
this.y = y;
Display.update();
}
}
45
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
without AspectJ
DisplayUpdating v3
class Line {
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
Display.update(this);
}
void setP2(Point p2) {
this.p2 = p2;
Display.update(this);
}
}
class Point
{
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
• no locus of “display updating”
void setX(int x) {
this.x = x;
Display.update(this);
}
void setY(int y) {
this.y = y;
Display.update(this);
}
}
46
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
– evolution is cumbersome
– changes in all classes
– have to track & change all callers
with AspectJ
class Line {
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
}
void setP2(Point p2) {
this.p2 = p2;
}
}
class Point
{
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) {
this.x = x;
}
void setY(int y) {
this.y = y;
}
}
47
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
with AspectJ
DisplayUpdating v1
class Line {
aspect DisplayUpdating {
private Point p1, p2;
pointcut move():
call(void Line.setP1(Point)) ||
call(void Line.setP2(Point));
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
}
void setP2(Point p2) {
this.p2 = p2;
}
after() returning: move() {
Display.update();
}
}
}
class Point
{
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) {
this.x = x;
}
void setY(int y) {
this.y = y;
}
}
48
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
with AspectJ
DisplayUpdating v2
class Line {
aspect DisplayUpdating {
private Point p1, p2;
pointcut move():
call(void FigureElement.moveBy(int, int) ||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point))
||
call(void Point.setX(int))
||
call(void Point.setY(int));
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
}
void setP2(Point p2) {
this.p2 = p2;
}
after() returning: move() {
Display.update();
}
}
}
class Point
{
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) {
this.x = x;
}
void setY(int y) {
this.y = y;
}
}
49
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
with AspectJ
DisplayUpdating v3
class Line {
aspect DisplayUpdating {
private Point p1, p2;
pointcut move(FigureElement figElt):
target(figElt) &&
(call(void FigureElement.moveBy(int, int) ||
call(void Line.setP1(Point))
||
call(void Line.setP2(Point))
||
call(void Point.setX(int))
||
call(void Point.setY(int)));
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) {
this.p1 = p1;
}
void setP2(Point p2) {
this.p2 = p2;
}
after(FigureElement fe) returning: move(fe) {
movees.add(fe);
}
}
class Point
{
}
private int x = 0, y = 0;
int getX() { return x; }
int getY() { return y; }
void setX(int x) {
this.x = x;
}
void setY(int y) {
this.y = y;
}
• clear display updating module
}
50
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
– all changes in single aspect
– evolution is modular
advice is
additional action to take at join points
• before
before proceeding at join point
• after returning a value to join point
• after throwing a throwable to join point
• after
returning to join point either way
• around
on arrival at join point gets explicit
control over when&if program proceeds
51
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
contract checking
simple example of before/after/around
• pre-conditions
– check whether parameter is valid
• post-conditions
– check whether values were set
• condition enforcement
– force parameters to be valid
52
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
pre-condition
using before advice
aspect PointBoundsPreCondition {
before(int newX):
call(void Point.setX(int)) && args(newX) {
assert(newX >= MIN_X);
what follows the ‘:’ is
assert(newX <= MAX_X);
always a pointcut –
}
primitive or user-defined
before(int newY):
call(void Point.setY(int)) && args(newY) {
assert(newY >= MIN_Y);
assert(newY <= MAX_Y);
}
private void assert(boolean v) {
if ( !v )
throw new RuntimeException();
}
}
53
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
post-condition
using after advice
aspect PointBoundsPostCondition {
after(Point p, int newX):
call(void Point.setX(int)) && target(p) && args(newX) {
assert(p.getX() == newX);
}
after(Point p, int newY):
call(void Point.setY(int)) && target(p) && args(newY) {
assert(p.getY() == newY);
}
private void assert(boolean v) {
if ( !v )
throw new RuntimeException();
}
}
54
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
condition enforcement
using around advice
aspect PointBoundsEnforcement {
void around(Point p, int newX):
call(void Point.setX(int)) && target(p) && args(newX) {
proceed(p, clip(newX, MIN_X, MAX_X));
}
void around(Point p, int newY):
call(void Point.setY(int)) && target(p) && args(newY) {
proceed(p, clip(newY, MIN_Y, MAX_Y));
}
private int clip(int val, int min, int max) {
return Math.max(min, Math.min(max, val));
}
}
55
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
special static method
<result type> proceed(arg1, arg2, …)
available only in around advice
means “run what would have run if this around advice had not been
defined”
56
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
other primitive pointcuts
this(<type name>)
within(<type name>)
withincode(<method/constructor signature>)
any join point at which
currently executing object is an instance of type or class name
currently executing code is contained within class name
currently executing code is specified method or constructor
get(int Point.x)
set(int Point.x)
field reference or assignment join points
57
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
fine-grained protection
a runtime error
class Figure {
public Point makeLine(Line p1, Line p2) { new Line... }
public Point makePoint(int x, int y)
{ new Point... }
...
}
want to ensure that any creation of
figure elements goes through the
factory methods
aspect FactoryEnforcement {
pointcut illegalNewFigElt():
(call(Point.new(..)) || call(Line.new(..))) &&
!withincode(* Figure.make*(..));
before(): illegalNewFigElt() {
throw new Error("Use factory method instead.");
}
}
58
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
fine-grained protection
a compile-time error
class Figure {
public Point makeLine(Line p1, Line p2) { new Line... }
public Point makePoint(int x, int y)
{ new Point... }
...
}
want to ensure that any creation of
figure elements goes through the
factory methods
aspect FactoryEnforcement {
pointcut illegalNewFigElt():
(call(Point.new(..)) || call(Line.new(..))) &&
!withincode(* Figure.make*(..));
declare error: illegalNewFigElt()
"Use factory method instead.");
}
}
59
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
must be a “static pointcut”
(more on this later)
fine-grained protection
as a static inner class
class Line implements FigureElement{
private Point p1, p2;
Point getP1() { return p1; }
Point getP2() { return p2; }
void setP1(Point p1) { this.p1 = p1; }
void setP2(Point p2) { this.p2 = p2; }
void moveBy(int dx, int dy) { ... }
static aspect SetterEnforcement {
declare error: set(Point Line.*) &&
!withincode(void Line.setP*(Point))
"Use setter method, even inside Line class.";
}
60
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
wildcarding in pointcuts
target(Point)
target(graphics.geom.Point)
target(graphics.geom.*)
target(graphics..*)
“*” is wild card
“..” is multi-part wild card
any type in graphics.geom
any type in any sub-package
of graphics
call(void Point.setX(int))
call(public * Point.*(..))
call(public * *(..))
any public method on Point
any public method on any type
call(void
call(void
call(void
call(void
any getter
Point.getX())
Point.getY())
Point.get*())
get*())
call(Point.new(int, int))
call(new(..))
61
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
any constructor
property-based crosscutting
package com.xerox.scan;
public class C2 {
package com.xerox.print;…
package com.xerox.copy;
public int frotz() {public class C3 {
public class C1 {
A.doSomething(…);
…
…
…
public void foo() {
public String s1() {
}
A.doSomething(…);
A.doSomething(…);
public
int
bar()
{
…
…
A.doSomething(…);
}
}
…
…
…
}
}
}
…
}
• crosscuts of methods with a common property
– public/private, return a certain value, in a particular package
• logging, debugging, profiling
– log on entry to every public method
62
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
property-based crosscutting
aspect PublicErrorLogging {
Log log = new Log();
neatly captures public
interface of mypackage
pointcut publicInterface():
call(public * com.xerox..*.*(..));
after() throwing (Error e): publicInterface() {
log.write(e);
}
}
consider code maintenance
• another programmer adds a public method
• i.e. extends public interface – this code will still work
• another programmer reads this code
• “what’s really going on” is explicit
63
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
special value
reflective* access to the join point
thisJoinPoint.
Signature
Object[]
...
getSignature()
getArgs()
available in any advice
thisJoinPoint is abbreviated to ‘tjp’ in these slides to
save slide space
* introspective subset of reflection consistent with Java
64
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
using thisJoinPoint
in highly polymorphic advice
aspect PointCoordinateTracing {
before(Point p, int newVal): set(int Point.*) &&
target(p) &&
args(newVal) {
System.out.println("At " +
tjp.getSignature() +
" field is set to " +
newVal +
".");
}
}
65
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
using thisJoinPoint makes it possible
for the advice to recover information
about where it is running
other primitive pointcuts
execution(void Point.setX(int))
method/constructor execution join points (actual running method)
initialization(Point)
object initialization join points
staticinitialization(Point)
class initialization join points (as the class is loaded)
66
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
other primitive pointcuts
cflow(pointcut designator)
all join points within the dynamic control flow of any join
point in pointcut designator
cflowbelow(pointcut designator)
all join points within the dynamic control flow below any join
point in pointcut designator
67
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
context sensitive aspects
DisplayUpdating v4
aspect DisplayUpdating {
pointcut move(FigureElement figElt):
target(figElt) &&
the non-reentrant calls idiom:
(call(void FigureElement.moveBy(int, int)) ||
call(void Line.setP1(Point)) ||
ptc &&||!cflowbelow(ptc)
call(void Line.setP2(Point))
call(void Point.setX(int))
||
call(void Point.setY(int)));
pointcut topLevelMove(FigureElement figElt):
move(figElt) && !cflowbelow(move(FigureElement));
after(FigureElement fe) returning: topLevelMove(fe) {
Display.update(fe);
}
}
68
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
wildcarding in pointcuts
target(Point)
target(graphics.geom.Point)
target(graphics.geom.*)
target(graphics..*)
“*” is wild card
“..” is multi-part wild card
any type in graphics.geom
any type in any sub-package
of graphics
call(void Point.setX(int))
call(public * Point.*(..))
call(public * *(..))
any public method on Point
any public method on any type
call(void
call(void
call(void
call(void
any getter
Point.getX())
Point.getY())
Point.get*())
get*())
call(Point.new(int, int))
call(new(..))
69
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
any constructor
property-based crosscutting
package com.xerox.scan;
public class C2 {
package com.xerox.print;…
package com.xerox.copy;
public int frotz() {public class C3 {
public class C1 {
A.doSomething(…);
…
…
…
public void foo() {
public String s1() {
}
A.doSomething(…);
A.doSomething(…);
public
int
bar()
{
…
…
A.doSomething(…);
}
}
…
…
…
}
}
}
…
}
• crosscuts of methods with a common property
– public/private, return a certain value, in a particular package
• logging, debugging, profiling
– log on entry to every public method
70
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
property-based crosscutting
aspect PublicErrorLogging {
Log log = new Log();
neatly captures public
interface of mypackage
pointcut publicInterface():
call(public * com.xerox..*.*(..));
after() throwing (Error e): publicInterface() {
log.write(e);
}
}
consider code maintenance
• another programmer adds a public method
• i.e. extends public interface – this code will still work
• another programmer reads this code
• “what’s really going on” is explicit
71
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
intra-type declarations
1
DisplayUpdating v5
aspect DisplayUpdating {
adds members to target interface/class
private Display FigureElement.display;
static void setDisplay(FigureElement fe, Display d) {
fe.display = d;
}
pointcut move(FigureElement figElt):
<as before>;
after(FigureElement fe): move(fe) {
fe.display.update(fe);
}
}
1. recently termed “open classes”
72
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
field/getter/setter idiom
aspect DisplayUpdating {
private with respect to
enclosing aspect declaration
private Display FigureElement.display;
static void setDisplay(FigureElement fe, Display d) {
fe.display = d;
}
the display field
– is a field of FigureElement,
pointcut move(FigureElement
figElt): but
<as before>;
– belongs to DisplayUpdating aspect
– DisplayUpdating aspect should provide getter/setter
after(FigureElement fe): move(fe) {
fe.display.update(fe);
}
}
73
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
is this still a “GOF pattern”?
aspect DisplayUpdating {
private List FigureElement.observers = new LinkedList();
static void addDisplay(FigureElement fe, Display d) {
fe.observers.add(d);
}
static void removeDisplay(FigureElement fe, Display d) {
fe.observers.remove(d);
}
pointcut move(FigureElement figElt):
<as before>;
after(FigureElement fe): move(fe) {
Iterator iter = fe.observers.iterator();
...
}
74
}
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
another pattern
aspect MumbleRWSynchronization {
pointcut readers(..): …;
pointcut writers(..): …;
before(..):
after (..):
before(..):
after (..):
readers(.)
readers(.)
writers(.)
readers(.)
{
{
{
{
beforeReader(..); }
afterWriter(..); }
beforeWriter(..); }
afterWriter(..); }
private beforeReader(..) {
...
}
<other helper methods here>
}
75
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
inheritance & specialization
• pointcuts can have additional advice
– aspect with
• concrete pointcut
• perhaps no advice on the pointcut
– in figure editor
• move() can have advice from multiple aspects
– module can expose certain well-defined pointcuts
• abstract pointcuts can be specialized
– aspect with
• abstract pointcut
• concrete advice on the abstract pointcut
76
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
a shared pointcut
public class FigureEditor {
...
pointcut move(FigureElement figElt):
target(figElt) && ...;
...
}
aspect DisplayUpdating {
...
after(FigureElement fe) returning:
FigureEditor.move(fe) {
...
}
...
}
77
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
a reusable aspect
abstract public aspect RemoteExceptionLogging {
abstract pointcut logPoint();
abstract
after() throwing (RemoteException e): logPoint() {
log.println(“Remote call failed in: ” +
thisJoinPoint.toString() +
“(” + e + “).”);
}
}
public aspect MyRMILogging extends RemoteExceptionLogging {
pointcut logPoint():
call(* RegistryServer.*.*(..)) ||
call(private * RMIMessageBrokerImpl.*.*(..));
}
78
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
an aspect as a reusable pattern
aspect RWSynchronization {
abstract pointcut readers(..): …;
abstract pointcut writers(..): …;
before(..):
after (..):
before(..):
after (..):
readers(.)
readers(.)
writers(.)
readers(.)
{
{
{
{
beforeReader(..); }
afterWriter(..); }
beforeWriter(..); }
afterWriter(..); }
<helper methods as before>
}
aspect MumbleRWSynchronization extends RWSynchronization {
abstract pointcut readers(..): …;
abstract pointcut writers(..): …;
79
}
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspect instances
aspect PublicErrorLogging
pertarget(PublicErrorLogging.publicInterface()) {
Log log = new Log();
one instance of the aspect for each object
that ever executes at these points
pointcut publicInterface():
call(public * com.xerox..*.*(..));
after() throwing (Error e): publicInterface() {
log.write(e);
}
80
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
looking up aspect instances
:
static Log getLog(Object obj) {
return (PublicErrorLogging.aspectOf(obj)).log;
}
}
• static method of aspects
– for default aspects takes no argument
– for aspects of pertarget/perthis takes an Object
– for aspects of percflow takes no arguments
• returns aspect instance
81
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspect relations
pertarget(<pointcut>)
perthis(<pointcut>)
one aspect instance for each
object that is ever “this” at
the join points
percflow(<pointcut>)
percflowbelow(<pointcut>)
one aspect instance for each join point
in pointcut, is available at all joinpoints in
cflow or cflowbelow
82
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
p1
l1
p2
p3
l2
context sensitive aspects
DisplayUpdating v4
aspect DisplayUpdating {
List movers = new LinkedList();
List movees = new LinkedList();
// …
pointcut moveCall(Object mover, FigureElement movee):
this(mover) && target(movee) &&
(call(void Line.setP1(Point)) ||
call(void Line.setP2(Point)) ||
call(void Point.setX(int))
||
call(void Point.setY(int)));
after(Object mover, FigureElement movee) returning:
moveCall(mover, movee) {
movers.add(mover);
movees.add(movee);
}
}
83
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
summary
join points
method & constructor
call
execution
field
get
set
exception handler
execution
initialization
aspects
crosscutting type
pertarget
perthis
percflow
percflowbelow
pointcuts
-primitivecall
execution
handler
get set
initialization
dispatch
this target
within withincode
cflow cflowbelow
-user-definedpointcut
declaration
abstract
overriding
static
84
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
advice
before
after
around
intra-type decls
declare
error
where we have been…
… and where we are going
problem structure
Part IV:
crosscutting in the design, and
how to use AspectJ to capture that
AspectJ mechanisms
Part II:
crosscutting in the code
mechanisms AspectJ provides
85
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Part III
AspectJ IDE support
programming environment
• AJDE support for
– emacs, JBuilder, Forte
• also jdb style debugger (ajdb)
• and window-based debugger
•
•
•
•
navigating AspectJ code
compiling
tracking errors
debugging
• ajdoc
87
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Part IV
Using Aspects
goals of this chapter
• present examples of aspects in design
– intuitions for identifying aspects
• present implementations in AspectJ
– how the language support can help
• work on implementations in AspectJ
– putting AspectJ into practice
• raise some style issues
– objects vs. aspects
• when are aspects appropriate?
89
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
example 1
plug & play tracing
• simple tracing
– exposes join points and uses very simple advice
• an unpluggable aspect
– core program functionality is unaffected by the
aspect
90
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
tracing without AspectJ
class TraceSupport {
TraceSupport
static int TRACELEVEL = 0;
static protected PrintStream stream = null;
static protected int callDepth = -1;
static void init(PrintStream _s) {stream=_s;}
static void traceEntry(String str) {
if (TRACELEVEL == 0) return;
callDepth++;
printEntering(str);
}
static void traceExit(String str) {
if (TRACELEVEL == 0) return;
callDepth--;
printExiting(str);
}
class Point {
}
void set(int x, int y) {
TraceSupport.traceEntry(“Point.set”);
_x = x; _y = y;
TraceSupport.traceExit(“Point.set”);
}
}
91
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
a clear crosscutting structure
TraceSupport
all modules of the system use the
trace facility in a consistent way:
entering the methods and
exiting the methods
this line is about
interacting with
the trace facility
92
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
tracing as an aspect
aspect PointCoordTracing {
TraceSupport
pointcut trace():
within(com.bigboxco.boxes.*) &&
execution(* *(..));
before(): trace() {
TraceSupport.traceEntry(
thisJoinPoint.getSignature());
}
after(): trace() {
TraceSupport.traceExit(
thisJoinPoint.getSignature());
}
}
93
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
plug and debug
• plug in:
• unplug:
ajc Point.java Line.java
TraceSupport.java PointTracing.java
ajc Point.java Line.java
• or…
94
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
plug and debug
//From ContextManager
public void service( Request rrequest, Response rresponse ) {
// log( "New request " + rrequest );
try {
//
System.out.print("A");
rrequest.setContextManager( this );
rrequest.setResponse(rresponse);
rresponse.setRequest(rrequest);
// wront request - parsing error
int status=rresponse.getStatus();
// log( "New
request " + rrequest );
// System.out.print(“A”);
if( status < 400 )
status= processRequest( rrequest );
if(status==0)
status=authenticate( rrequest, rresponse );
if(status == 0)
status=authorize( rrequest, rresponse );
if( status == 0 ) {
rrequest.getWrapper().handleRequest(rrequest,
rresponse);
} else {
// something went wrong
handleError( rrequest, rresponse, null, status );
}
} catch (Throwable t) {
handleError( rrequest, rresponse, t, 0 );
}
// System.out.print("B");
try {
rresponse.finish();
rrequest.recycle();
rresponse.recycle();
} catch( Throwable ex ) {
if(debug>0) log( "Error closing request " + ex);
}
// log( "Done with request " + rrequest );
// System.out.print("C");
return;
}
// System.out.print("B");
if(debug>0)
log("Error closing request " + ex);
// log("Done with request " + rrequest);
// System.out.print("C");
95
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
plug and debug
• turn debugging on/off without editing
classes
• debugging disabled with no runtime
cost
• can save debugging code between
uses
• can be used for profiling, logging
• easy to be sure it is off
96
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspects in the design
have these benefits
• objects are no longer responsible for using
the trace facility
– trace aspect encapsulates that responsibility, for
appropriate objects
• if the Trace interface changes, that change is
shielded from the objects
– only the trace aspect is affected
• removing tracing from the design is trivial
– just remove the trace aspect
97
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspects in the code
have these benefits
• object code contains no calls to trace
functions
– trace aspect code encapsulates those calls, for
appropriate objects
• if the trace interface changes, there is no
need to modify the object classes
– only the trace aspect class needs to be modified
• removing tracing from the application is
trivial
– compile without the trace aspect class
98
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
tracing: object vs. aspect
• using an object
captures tracing
support, but does
not capture its
consistent usage by
other objects
TraceSupport
99
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
• using an aspect
captures the
consistent usage of
the tracing support
by the objects
TraceSupport
tracing
exercises
1. Make a Tracing library aspect, and
redefine PointTracing as extension of
it.
2. The original after advice runs whether
computation returned normally or
threw an exception. Instead, define
one advice for normal return, and a
second for abrupt return that also
prints the exception.
100
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
refactor TraceMyClasses into a reusable
(library) aspect and an extension
equivalent to TraceMyClasses
abstract aspect Tracing {
// what goes here?
}
aspect PointTracing extends Tracing {
// what goes here?
}
101
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
discussion
• what, at the design level, does each of these
aspects implement?
• did you retain TraceSupport class?
• what do you think of the names Tracing and
PointTracing for these aspects? what did you
name the abstract pointcut
• can you combine the techniqes of OO
frameworks with these aspects to make the
Tracing aspect even more flexible? is it a
good idea to do so?
• …
102
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
example 2
roles/views
CloneablePoint
<<aspect>>
clone()
HashablePoint
<<aspect>>
equals(o:Object)
hashCode()
Point
x: double
y: double
theta: double
rho: double
rotate(angle:double)
offset(dx:double,dy:double)
...
103
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
ComparablePoint
<<aspect>>
compareTo(o:Object)
CloneablePoint
aspect CloneablePoint {
declare parents: Point implements Cloneable;
public Object Point.clone()
// we choose to bring all
makeRectangular();
//
makePolar();
//
return super.clone();
}
}
104
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
throws CloneNotSupportedException {
fields up to date before cloning
defined in class Point
defined in class Point
roles/views
exercise/discussion
• Write the HashablePoint and
ComparablePoint aspects.
• Consider a more complex system.
Would you want the HashablePoint
aspect associated with the Point class,
or with other HashableX objects, or
both?
105
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
example 3
counting bytes
interface OutputStream {
public void write(byte
b);
public void write(byte[] b);
}
/**
* This SIMPLE aspect keeps a global count of all
* the bytes ever written to an OutputStream.
*/
aspect ByteCounting {
int count = 0;
int getCount() { return count; }
//
//
// what goes here? //
//
//
}
106
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
complete the code
for ByteCounting
/**
* This SIMPLE aspect keeps a global count of all
* all the bytes ever written to an OutputStream.
*/
aspect ByteCounting {
int count = 0;
int getCount() { return count; }
}
107
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
counting bytes v1
a first attempt
aspect ByteCounting {
int count = 0;
int getCount() { return count; }
after() returning:
call(void OutputStream.write(byte)) {
count = count + 1;
}
after(byte[] bytes) returning:
call(void OutputStream.write(bytes)) {
count = count + bytes.length;
}
}
108
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
counting bytes
some stream implementations
class SimpleOutputStream implements OutputStream {
public void write(byte b) { … }
public void write(byte[] b) {
for (int i = 0; i < b.length; i++) write(b[i]);
}
}
class OneOutputStream implements OutputStream {
public void write(byte b) { … }
public void write(byte[] b) { … }
}
109
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
counting bytes
another implementation
class OtherOutputStream implements OutputStream {
public void write(byte b) {
byte[] bs = new byte[1] { b };
write(bs);
}
public void write(byte[] b) { … }
}
110
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
counting bytes v2
using cflowbelow for more robust counting
aspect ByteCounting {
int count = 0;
int getCount() { return count; }
pointcut write(): call(void OutputStream.write(byte)) ||
call(void OutputStream.write(byte[]));
pointcut writeCflow(): cflowbelow(write());
after() returning:
!writeCflow() && call(void OutputStream .write(byte)) {
count++;
}
after(byte[] bytes) returning:
!writeCflow() && call(void OutputStream .write(bytes)) {
count = count + bytes.length;
}
}
111
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
counting bytes v3
per-stream counting
aspect ByteCounting {
/* put declarations here that provide per-stream count state */
pointcut write(): call(void OutputStream.write(byte)) ||
call(void OutputStream.write(byte[]));
/* ... and show how to properly increment the count state */
... count = count + 1;
... count = count + bytes.length;
}
112
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
counting bytes v3
per-stream counting
aspect ByteCounting {
/* put declarations here that provide per-stream count state */
private int OutputStream.count = 0;
static public int getCount(OutputStream os) { return os.count; }
/* or ??? */
public int OutputStream.getCount() { return count; }
third party perspective:
pointcut write(): call(void OutputStream.write(byte)) ||
call(void OutputStream.write(byte[]));
s.getCount();
ByteCounting.getCount(s);
/* ... and show how to properly increment the count state */
... s.count = s.count + 1;
... s.count = s.count + bytes.length;
}
113
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
counting bytes
exercises
• How do the aspects change if the
method void write(Collection c) is
added to the OutputStream interface?
• How would you change v2 to handle
byte generators:
interface ByteGenerator {
int getLength();
void generateTo(OutputStream s);
}
114
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
example 4
context-passing aspects
caller1
Service
caller2
workers need to know the caller:
• capabilities
• charge backs
• to customize result
worker 1
115
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
worker 2
worker 3
context-passing aspects
caller1
Service
caller2
workers need to know the caller:
• capabilities
• charge backs
• to customize result
worker 1
116
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
worker 2
worker 3
context-passing aspects
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
117
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
context-passing aspects
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
pointcut workPoints(Worker w):
target(w) && call(void Worker.doTask(Task));
118
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
context-passing aspects
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
pointcut workPoints(Worker w):
target(w) && call(void Worker.doTask(Task));
pointcut perCallerWork(Caller c, Worker w):
cflow(invocations(c)) && workPoints(w);
119
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
context-passing aspects
abstract aspect CapabilityChecking {
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
pointcut workPoints(Worker w):
target(w) && call(void Worker.doTask(Task));
pointcut perCallerWork(Caller c, Worker w):
cflow(invocations(c)) && workPoints(w);
before (Caller c, Worker w): perCallerWork(c, w) {
w.checkCapabilities(c);
}
}
120
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
example 5
properties of interfaces
interface Forest {
int howManyTrees();
int howManyBirds();
...
}
pointcut forestCall():
call(* Forest.*(..));
before(): forestCall():
}
121
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
{
example n1
• points
– with location and color
• a screen
– that monitors location changes
– that monitors color changes
– that monitors screen changes
122
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
observe
setX, setY
Display
println(String)
updateStatus(String)
Point
setX(int)
setY(int)
setColor(Color)
observe
setColor
123
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
observe
println
<point 12> moved
<point 28> changed color
observe
setX, setY
Point
setX(int)
setY(int)
setColor(Color)
observe
setColor
<point 12> movedobserve
<point 28> changed
color
println
last change: 14:02:29
124
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
complete the code
aspect CoordinateObserving {
HashMap perPointObservers = new WeakHashMap();
static void addObserver(Point p, Display d) { ... }
static void removeObserver(Point p, Display d) { ... }
Iterator getObservers(Point p) { ... }
pointcut change(): (call(void Point.setX(int)) ||
call(void Point.setY(int))) &&
target(p);
after(Point p) returning: change() {
// iterate for each display in observers…
update(p, d);
}
void update(Point p, Display d) {
d.println(“Point “ + p + “has moved” …);
}
}
125
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
complete the code
aspect CoordinateObserving {
HashMap perPointObservers = new WeakHashMap();
static void addObserver(Point p, Display d) { ... }
static void removeObserver(Point p, Display d) { ... }
Iterator getObservers(Point p) { ... }
pointcut change(): (call(void Point.setX(int)) ||
call(void Point.setY(int))) &&
target(p);
after(Point p) returning: change() {
// iterate for each display in observers…
update(p, d);
}
void update(Point p, Display d) {
d.println(“Point “ + p + “has moved” …);
}
}
126
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
complete the code
aspect Observing {
HashMap perPointObservers = new WeakHashMap();
static void addObserver(Object p, Object d) { ... }
static void removeObserver(Point p, Display d) { ... }
Iterator getObservers(Point p) { ... }
abstract pointcut change();
after(Point p) returning: change() {
// iterate for each display in observers…
update(p, d);
}
abstract void update(Point p, Display d);
}
}
127
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
complete the code
aspect ColorObserving {
Display d; // assume this is set up for you
}
128
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
complete the code
for DisplayXXX
aspect DisplayObserving {
Display d; // assume this is set up for you
}
129
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
aspect Observing {
}
130
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
abstract these into
a reusable aspect
exercise
abstract these into
a reusable aspect
abstract aspect Observing {
private WeakHashMap perSubjectObservers = new WeakHashMap();
private Collection getObservers(Subject s) {
Collection observers = (Collection)perSubjectObservers.get(s);
if ( observers == null ) {
observers = new LinkedList();
perSubjectObservers.put(s, observers);
}
return observers;
}
protected interface Subject { }
protected interface Observer { }
public void
addObserver(Subject s, Observer o) { getObservers(s).add(o);
}
public void removeObserver(Subject s, Observer o) { getObservers(s).remove(o); }
abstract pointcut change();
after(Subject s): change() {
Iterator iter = getObservers(s).iterator();
while ( iter.hasNext() ) {
updateObserver(s, ((Observer)iter.next()));
}
}
abstract void updateObserver(Subject s, Observer o);
}
131
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
abstract these into
a reusable aspect
public aspect ColorObserving extends Observing {
declare parents: Point implements Subject;
declare parents: Screen implements Observer;
pointcut changes(Subject s): call(void Point.setColor(Color)) && target(s);
void updateObserver(Subject s, Observer o) {
((Screen)o).display("Screen updated because color changed.");
}
}
132
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
abstract these into
a reusable aspect
public aspect CoordinateObserving extends Observing {
declare parents: Point implements Subject;
declare parents: Screen implements Observer;
pointcut changes(Subject s): (call(void Point.setX(int)) ||
call(void Point.setY(int)) ) &&
target(s);
void updateObserver(Subject s, Observer o) {
((Screen)o).display("Screen updated because coordinates changed.");
}
}
133
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
abstract these into
a reusable aspect
public aspect ScreenObserving extends Observing {
declare parents: Screen implements Subject;
declare parents: Screen implements Observer;
pointcut changes(Subject s): call(void Screen.display(String)) &&
target(s);
void updateObserver(Subject s, Observer o) {
((Screen)o).display("Screen updated because screen displayed.");
}
}
134
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspects on interfaces
a first attempt
aspect Forestry {
pointcut forestCall():
call(* Forest.*(..));
before(): forestCall() {
System.out.println(tjp.getSignature() +
" is a Forest-Method.");
}
}
135
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspects on interfaces
an implementation
class ForestImpl implements Forest {
public static void main(String[] args) {
Forest f1 = new ForestImpl();
f1.toString();
f1.howManyTrees();
f1.howManyTrees();
}
public int howManyTrees() { return 100; }
public int howManyBirds() { return 200; }
}
•
interface Forest includes methods from Object, such as
toString()
136
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspects on interfaces
adding constraints
aspect Forestry {
pointcut forestCall():
call(* Forest.*(..)) &&
!call(* Object.*(..));
before(): forestCall() {
System.out.println(thisJoinPoint.methodName +
" is a Forest-method.");
}
}
137
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
aspects on interfaces
exercises
• In this example you needed to
constrain a pointcut because of
undesired inheritance. Think of an
example where you would want to
capture methods in a super-interface.
• Constraining a pointcut in this way can
be seen as an aspect idiom. What other
idioms have you seen in this tutorial?
138
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
example 6
RMI exception aspects
139
client reactions to failures:
- abort
- try another server
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
a TimeServer design
140
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
the TimeService
public interface TimeService extends Remote {
/**
* What's the time?
*/
public Date getTime() throws RemoteException;
/**
* Get the name of the server
*/
public String getName() throws RemoteException;
/**
* Exported base name for the service
*/
public static final String nameBase = "TimeService";
}
141
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
the TimeServer
public class TimeServer extends UnicastRemoteObject
implements TimeService {
/**
* The remotely accessible methods
*/
public Date
getTime() throws RemoteException {return new Date();}
public String getName() throws RemoteException {return toString();}
/**
* Make a new server object and register it
*/
public static void main(String[] args) {
TimeServer ts = new TimeServer();
Naming.bind(TimeService.nameBase, ts);
}
/**
* Exception pointcuts. Code is not complete without advice on them.
*/
pointcut create():
within(TimeServer) && call(TimeServer.new());
no exception
catching here,
but notice
pointcut bind(): within(TimeServer) && call(void Naming.bind(String,..));
pointcut bindName(String name): args(name, ..) && bind();
}
142
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AbortMyServer
aspect AbortMyServer {
TimeServer around(): TimeServer.create() {
TimeServer result = null;
try {
result = proceed();
} catch (RemoteException e){
System.out.println("TimeServer err: " + e.getMessage());
System.exit(2);
}
return result;
}
declare soft: RemoteException: TimeServer.create();
void around(String name): TimeServer.bindName(name) {
try {
proceed(name);
System.out.println("TimeServer: bound name.");
} catch (Exception e) {
System.err.println("TimeServer: error " + e);
System.exit(1);
}
}
declare soft: Exception: TimeServer.bind();
}
143
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
RetryMyServer
aspect RetryMyServer {
TimeServer around(): TimeServer.create() {
TimeServer result = null;
try { result = proceed(); }
catch (RemoteException e){
System.out.println("TimeServer error."); e.printStackTrace();
}
return result;
}
declare soft: RemoteException: TimeServer.create();
void around(String name): TimeServer.bindName(name) {
for (int tries = 0; tries < 3; tries++) {
try {
proceed(name + tries);
System.out.println("TimeServer: Name bound in registry.");
return;
} catch (AlreadyBoundException e) {
System.err.println("TimeServer: name already bound");
}
System.err.println("TimeServer: Giving up."); System.exit(1);
}
declare soft: Exception: TimeServer.bind();
}
144
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
the Client
again, no
exception
catching here
public class Client {
TimeService server = null;
/**
* Get a server and ask it the time occasionally
*/
void run() {
server = (TimeService)Naming.lookup(TimeService.nameBase);
System.out.println("\nRemote Server=" + server.getName() + "\n\n");
while (true) {
System.out.println("Time: " + server.getTime());
pause();
}
}
/**
* Exception pointcuts. Code is not complete without advice on them.
*/
pointcut setup(): call(Remote Naming.lookup(..));
pointcut setupClient(Client c): this(c) && setup();
pointcut serve(): call(* TimeService.*(..));
pointcut serveClient(Client c, TimeService ts):
this(c) && target(ts) && serve();
… other methods …
145
}
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AbortMyClient
aspect AbortMyClient {
Remote around(Client c): Client.setupClient(c) {
Remote result = null;
try {
result = proceed(c);
} catch (Exception e) {
System.out.println("Client: No server. Aborting.");
System.exit(0);
}
return result;
}
declare soft: Exception: Client.setup();
Object around(Client c, TimeService ts): Client.serveClient(c, ts) {
Object result = null;
try {
result = proceed(c, ts);
} catch (RemoteException e) {
System.out.println("Client: Remote Exception. Aborting.");
System.exit(0);
}
return result;
}
declare soft: RemoteException: Client.serve();
146
}
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
RetryMyClient
aspect RetryMyClient {
Remote around(Client c): Client.setupClient(c) {
Remote result = null;
try { result = proceed(c);}
catch (NotBoundException e) {
System.out.println("Client: Trying alternative name...");
result = findNewServer(TimeService.nameBase, c.server, 3);
if (result == null) System.exit(1); /* No server found */
} catch (Exception e2) { System.exit(2); }
return result;
}
declare soft: Exception: Client.setup();
Object around(Client c, TimeService ts): Client.serveClient(c,ts) {
try { return proceed(c,ts); }
catch (RemoteException e) {
c.server = findNewServer(TimeService.nameBase, c.server, 3);
if (c.server == null) System.exit(1); /* No server found */
try { return proceed(c, c.server); }
catch (RemoteException e2) { System.exit(2); }
return null;
}
}
declare soft: RemoteException: Client.serve();
static TimeService findNewServer(String baseName,
Object currentServer, int nservers) { … }
147
}
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
building the client
• abort mode:
ajc Client.java TimeServer_Stub.java AbortMyClient.java
• retry mode:
ajc Client.java TimeServer_Stub.java RetryMyClient.java
• switch to different failure handling modes
without editing
• no need for subclassing or delegation
• reusable failure handlers
148
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
RMI exception handling
exercises
• Write another exception handler that, on
exceptions, gives up the remote mode and
instantiates a local TimeServer.
• How would this client look like if the
exception handling were not designed with
aspects? Can you come up with a flexible OO
design for easily switching between
exception handlers?
• Compare the design of exception handlers
with aspects vs. with your OO design
149
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
exercise
aspect UseLocalClient {
Object around(Client c, TimeService ts): Client.serveClient(c, ts) {
Object result = null;
try {
result = proceed(c, ts);
} catch (RemoteException e) {
c.s = new TimeServer();
proceed(c, s);
}
return result;
}
declare soft: RemoteException: Client.serve();
}
150
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
example 7
layers of functionality
• given a basic telecom operation, with
customers, calls, connections
• model/design/implement utilities such
as
– timing
– consistency checks
– ...
151
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
telecom basic design
Customer
Call
void
void
void
1
startCall(Customer)
pickupCall(Call)
mergeCalls(Call, Call)
hangupCall(Call)
Call
1
0..N
Customer getCaller()
void pickup()
void merge(Call)
void hangup()
1
0..N
Connection
caller
receiver
Customer getCaller()
Customer getReceiver()
void complete()
void drop()
Local
152
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
LongDistance
These classes
define the
protocols for
setting up calls
(includes
conference
calling) and
establishing
connections
timing
entities
store total
connection
time
0..N
Customer
1
1
Call
1
0..N
caller
Connection
time each connection
receiver
Local
153
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
LongDistance
timing
some actions
0..N
connection dropped:
add time
Customer
1
1
Call
1
0..N
caller
Connection
receiver
Local
154
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
connection made:
start timing
connection dropped:
stop timing
LongDistance
timing
additional design elements
long getTime()
0..N
Customer
1
Timer
void stop()
void start()
long getTime()
invoke when
connection drops
set and invoke
upon new
connection
Call
1
1
0..N
caller
Connection
receiver
Local
155
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
LongDistance
timing
exercise
• Write an aspect representing the timing
protocol.
156
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
timing
what is the nature of the crosscutting?
• connections and calls are involved
• well defined protocols among them
• pieces of the timing protocol must be
triggered by the execution of certain
basic operations. e.g.
– when connection is completed,
set and start a timer
– when connection drops,
stop the timer and add time to customers’
connection time
157
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
timing
an aspect implementation
aspect Timing {
private Timer Connection.timer = new Timer();
private long Customer.totalConnectTime = 0;
public static long getTotalConnectTime(Customer c) {
return c.totalConnectTime;
}
pointcut startTiming(Connection c): target(c) && call(void c.complete());
pointcut
endTiming(Connection c): target(c) && call(void c.drop());
after(Connection c): startTiming(c) {
c.timer.start();
}
after(Connection c): endTiming(c) {
Timer timer = c.timer;
timer.stop();
long currTime = timer.getTime();
c.getCaller().totalConnectTime += currTime;
c.getReceiver().totalConnectTime += currTime;
}
}
158
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
timing as an object
Customer
...
long getTime()
void addToTime(long)
0..N
1
addToTime(timer.getTime())
0..N
Timer
void stop()
void start()
long getTime()
Connection
...
drop()
new(..)
timing as an object captures timing support, but does not
capture the protocols involved in implementing the
timing feature
159
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
timing as an aspect
Timing
long getTime()
void addToTime(long t)
Customer
...
0..N
1
addToTime(timer.getTime())
0..N
Timer
void stop()
void start()
long getTime()
Connection
...
drop()
new(..)
timing as an aspect captures the protocols involved in
implementing the timing feature
160
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
timing as an aspect
has these benefits
• basic objects are not responsible for using
the timing facility
– timing aspect encapsulates that responsibility, for
appropriate objects
• if requirements for timing facility change,
that change is shielded from the objects
– only the timing aspect is affected
• removing timing from the design is trivial
– just remove the timing aspect
161
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
timing with AspectJ
has these benefits
• object code contains no calls to timing
functions
– timing aspect code encapsulates those calls, for
appropriate objects
• if requirements for timing facility change,
there is no need to modify the object classes
– only the timing aspect class and auxiliary classes
needs to be modified
• removing timing from the application is trivial
– compile without the timing aspect class
162
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
timing
exercises
• How would you change your program if
the interface to Timer objects changed to
Timer
void start()
long stopAndGetTime()
• What changes would be necessary
without the aspect abstraction?
163
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
telecom, continued
layers of functionality: consistency
• ensure that all calls and connections
are being shut down in the simulation
164
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
consistency checking
1
Customer
Call
void
void
void
startCall(Customer)
pickupCall(Call)
mergeCalls(Call, Call)
hangupCall(Call)
1
store each new call
remove calls that
Customer getCaller()
• hangup
void pickup()
• merge
void merge(Call)
Call
0..N
void hangup()
0..N
1
0..N
Connection
caller
receiver
Customer getCaller()
Customer getReceiver()
void complete()
void drop()
store each new connection
remove connections that drop
0..N
Local
LongDistance
165
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
List of
Calls
List of
Connections
check at the end
of simulation
consistency checking
aspect ConsistencyChecker {
Vector calls = new Vector(), connections = new Vector();
/* The lifecycle of calls */
after(Call c): target(c) && call(Call.new(..)) {
calls.addElement(c);
}
after(Call c): target(c) && call(* Call.hangup(..)) {
calls.removeElement(c);
}
after(Call other): args(other) && (void Call.merge(Call)) {
calls.removeElement(other);
}
/* The lifecycle of connections */
after(Connection c): target(c) && call(Connection.new(..)) {
connections.addElement(c);
}
after(Connection c): target(c) && call(* Connection.drop(..)) {
connections.removeElement(c);
}
after(): within(TelecomDemo) && executions(void main(..)) {
if (calls.size() != 0) println("ERROR on calls clean up.");
if (connections.size()!=0) println("ERROR on connections clean up.");
}
}
166
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
summary so far
• presented examples of aspects in
design
– intuitions for identifying aspects
• presented implementations in AspectJ
– how the language support can help
• raised some style issues
– objects vs. aspects
167
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
when are aspects appropriate?
• is there a concern that:
– crosscuts the structure of several objects or operations
– is beneficial to separate out
168
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
… crosscutting
• a design concern that involves several
objects or operations
• implemented without AOP would lead
to distant places in the code that
– do the same thing
• e.g. traceEntry(“Point.set”)
• try grep to find these [Griswold]
– do a coordinated single thing
• e.g. timing, observer pattern
• harder to find these
169
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
… beneficial to separate out
• does it improve the code in real ways?
– separation of concerns
• e.g . think about service without timing
– clarifies interactions, reduces tangling
• e.g. all the traceEntry are really the same
– easier to modify / extend
• e.g. change the implementation of tracing
• e.g. abstract aspect re-use
– plug and play
• tracing aspects unplugged but not deleted
170
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
good designs
summary
• capture “the story” well
• may lead to good implementations,
measured by
–
–
–
–
code size
tangling
coupling
etc.
171
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
learned through
experience, influenced
by taste and style
expected benefits of using AOP
• good modularity, even in the presence
of crosscutting concerns
– less tangled code, more natural code, smaller
code
– easier maintenance and evolution
• easier to reason about, debug, change
– more reusable
• more possibilities for plug and play
• abstract aspects
172
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Part V
References, Related Work
AOP and AspectJ on the web
• aspectj.org
• aosd.net (www.parc.xerox.com/aop)
174
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Workshops
• ECOOP’97
– http://wwwtrese.cs.utwente.nl/aop-ecoop97
• ICSE’98
– http://www.parc.xerox.com/aop/icse98
• ECOOP’98
– http://wwwtrese.cs.utwente.nl/aop-ecoop98
• ECOOP’99
– http://wwwtrese.cs.utwente.nl/aop-ecoop99
• OOPSLA’99
– http://www.cs.ubc.ca/~murphy/multid-workshop-oopsla99/index.htm
• ECOOP’00
– http://trese.cs.utwente.nl/Workshops/adc2000/
• OOPSLA’00
– http://trese.cs.utwente.nl/Workshops/OOPSLA2000/
• ECOOP’01
175
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
growing interest
in separation of crosscutting concerns
• see workshop proceedings
• upcoming AOSD conference
176
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AOP future –
idea, language, tools
• objects are
•
•
•
•
code and state
“little computers”
message as goal
hierarchical structure
• languages support
• encapsulation
• polymorphism
• inheritance
• tools
• browser, editor, debuggers
• preserve object abstraction
• aspects are
•
•
•
•
+ crosscutting structure
• languages support
•
•
•
+ crosscutting
• tools
•
•
+ preserve aspect abstraction
177
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AOP future
• language design
– more dynamic crosscuts, type system …
• tools
– more IDE support, aspect discovery, re-factoring, recutting…
• software engineering
– finding aspects, modularity principles, …
• metrics
– measurable benefits, areas for improvement
• theory
– type system for crosscutting, fast compilation,
advanced crosscut constructs
178
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AspectJ & the Java platform
• AspectJ is a small extension to the Java
programming language
– all valid programs written in the Java programming
language are also valid programs in the AspectJ
programming language
• AspectJ has its own compiler, ajc
– ajc runs on Java 2 platform
– ajc is available under Open Source license
– ajc produces Java platform compatible .class files
179
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AspectJ status
• release status
– 3 major, ~18 minor releases over last year (1.0b1 is current)
– tools
• IDE extensions: Emacs, JBuilder 3.5, JBuilder 4, Forte4J
• ajdoc to parallel javadoc
• debugger: command line, GUI, & IDE
– license
• compiler, runtime and tools are free for any use
• compiler and tools are Open Source
• aspectj.org
– May 1999: 90 downloads/mo, 20 members on users list
– Feb 2001: 600 downloads/mo, 600 members on users list
180
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
AspectJ future
continue building language, compiler & tools
• 1.0
– compilation direct to bytecodes
• 1.1
– incremental compiler
• 1.2
– source of target classes not required?
• 2.0
– new dynamic crosscut constructs
commercialization decision after 1.0
181
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
credits
AspectJ.org is a Xerox PARC project:
Bill Griswold, Erik Hilsdale, Jim Hugunin, Wes Isberg,
Vladimir Ivanovic, Mik Kersten, Gregor Kiczales,
Jeffrey Palm
slides, compiler, tools & documentation are available at aspectj.org
partially funded by DARPA under contract F30602-97-C0246
182
Aspect-Oriented Programming with AspectJ -- OOPSLA 2001
Download