java - Assert package call directions with AspectJ -


let's assume have following package structure

some.package     |-aaa.private     |-aaa.public     |-bbb.private     |-bbb.public 

my architecture demand, make calls some.package.aaa..* some.package.bbb.public..* , vice versa, calls some.package.bbb..* some.package.aaa.public..*. in other words, if traverse "major" package border (e.g. aaa bbb), want allow calls public package in root of other major package.

is possible define aspectj pointcut, selects joinpoints violate rule? i.e. if want write

declare error: insomemajorpackage() && callingnonpublicpackageofothermajorpackage() :     "please make calls public interfaces of other major packages"; 

is there way define 2 pointcuts, such enforce rule?

attention: lengthy answer because of code samples.

i created sample project can downloaded scrum-master.de. package structure follows:

package structure

as can see, below main application package de.scrum_master there 3 "major" packages common, feature1, feature2, each containing sub-packages pub (public) , prv (private). additionally there aop package containing aspects. each pub/prv sub-package contains dummy class.

the java classes follows:

package de.scrum_master.common.pub;  import de.scrum_master.common.prv.commonprivate; import de.scrum_master.feature1.prv.feature1private; import de.scrum_master.feature1.pub.feature1public; import de.scrum_master.feature2.prv.feature2private; import de.scrum_master.feature2.pub.feature2public;  public class application {     private int id;     private string name;      public application(int id, string name) {         super();         this.id = id;         this.name = name;     }      public static void main(string[] args) {         system.out.println(new application    (1, "application"));         system.out.println(new commonprivate  (2, "common (private)"));         system.out.println(new feature1public (3, "feature 1 (public)"));         system.out.println(new feature1private(4, "feature 1 (private)"));         system.out.println(new feature2public (5, "feature 2 (public)"));         system.out.println(new feature2private(6, "feature 2 (private)"));     }      @override     public string tostring() {         return "application [id=" + id + ", name=" + name + "]";     } } 
package de.scrum_master.common.prv;  public class commonprivate {     private int id;     private string name;      public commonprivate(int id, string name) {         super();         this.id = id;         this.name = name;     }      @override     public string tostring() {         return "commonprivate [id=" + id + ", name=" + name + "]";     } } 
package de.scrum_master.feature1.pub;  public class feature1public {     private int id;     private string name;      public feature1public(int id, string name) {         super();         this.id = id;         this.name = name;     }      @override     public string tostring() {         return "feature1public [id=" + id + ", name=" + name + "]";     } } 
package de.scrum_master.feature1.prv;  import de.scrum_master.feature2.prv.feature2private; import de.scrum_master.feature2.pub.feature2public;  public class feature1private {     private int id;     private string name;      public feature1private(int id, string name) {         super();         this.id = id;         this.name = name;     }      @override     public string tostring() {         new feature2private(11111, "this should illegal");         new feature2public(22222, "this should ok");         return "feature1private [id=" + id + ", name=" + name + "]";     } } 
package de.scrum_master.feature2.pub;  public class feature2public {     private int id;     private string name;      public feature2public(int id, string name) {         super();         this.id = id;         this.name = name;     }      @override     public string tostring() {         return "feature2public [id=" + id + ", name=" + name + "]";     } } 
package de.scrum_master.feature2.prv;  import de.scrum_master.feature1.prv.feature1private; import de.scrum_master.feature1.pub.feature1public;  public class feature2private {     private int id;     private string name;      public feature2private(int id, string name) {         super();         this.id = id;         this.name = name;     }      @override     public string tostring() {         new feature1private(33333, "this should illegal");         new feature1public(44444, "this should ok");         return "feature2private [id=" + id + ", name=" + name + "]";     } } 

now need our aspect. more exactly, need abstract base aspect , 1 package-specific concrete sub-aspect each "major" package. not nice, works.

the abstract base aspect looks this:

package de.scrum_master.aop;  public abstract aspect accesscontroller {     // method/constructor calls base package     pointcut basepackagecall():         call(* de.scrum_master..*.*(..)) || call(de.scrum_master..*.new(..));      // method/constructor calls public packages     pointcut publicpackagecall() :         call(* de.scrum_master..*.pub..*(..)) || call(de.scrum_master..*.pub..new(..));      // own "major" package. please override in concrete sub-aspect this:     // within(de.scrum_master.mymajor..*)      pointcut ownpackage();      // method/constructor calls within own "major" package. please override in concrete sub-aspect this:     // call(* de.scrum_master.mymajor..*(..)) || call(de.scrum_master.mymajor..new(..))      pointcut ownpackagecall();      pointcut forbiddencall() :         ownpackage() && basepackagecall() && !(publicpackagecall() || ownpackagecall());      declare error: forbiddencall() :         "illegal call non-public foreign major package"; } 

as can see there 2 pointcuts must concretised sub-aspects this:

package de.scrum_master.aop;  public aspect accesscontroller_common extends accesscontroller {     pointcut ownpackage() :         within(de.scrum_master.common..*);      pointcut ownpackagecall() :         call(* de.scrum_master.common..*(..)) || call(de.scrum_master.common..new(..)); } 
package de.scrum_master.aop;  public aspect accesscontroller_feature1 extends accesscontroller {     pointcut ownpackage() :         within(de.scrum_master.feature1..*);      pointcut ownpackagecall() :         call(* de.scrum_master.feature1..*(..)) || call(de.scrum_master.feature1..new(..)); } 
package de.scrum_master.aop;  public aspect accesscontroller_feature2 extends accesscontroller {     pointcut ownpackage() :         within(de.scrum_master.feature2..*);      pointcut ownpackagecall() :         call(* de.scrum_master.feature2..*(..)) || call(de.scrum_master.feature2..new(..)); } 

creating sub-aspects new "major" packages simple copy & paste plus minor editing corresponding package name.

if inspect application.main, feature1private.tostring , feature2private.tostring see built in illegal calls non-public foreign sub-packages there, 4 in all. looks in eclipse's problem view:

enter image description here

a few more words base/sub aspects: while in advice possible dynamically determine package names , more magic via reflection, declare error based on pointcuts can determined statically during compile time. thus, must more specific , explicit here requires have 1 sub-aspect each "major" package in scenario. alternative 1 big concrete aspect containing pointcuts each single package. thought ugly though.

now enjoy solution, think adequately addresses problem. :-)


Comments

Popular posts from this blog

css - Which browser returns the correct result for getBoundingClientRect of an SVG element? -

gcc - Calling fftR4() in c from assembly -

Function that returns a formatted array in VBA -