Sunday, April 01, 2007
Default Interface Implementation
這是AspectJ in Action裡8.5.4 Providing a default interface implementation中的程式碼
With OOP
public interface Nameable {
public void setName(String name);
public String getName();
}
===============================================================================
public interface Identifiable {
public void setId(String id);
public String getId();
}
===============================================================================
public class Entity implements Nameable, Identifiable {
private String _name;
private String _id;
public void setName(String name) {
_name = name;
}
public String getName() {
return _name;
}
public void setId(String id) {
_id = id;
}
public String getId() {
return _id;
}
}
With AOP
public interface Nameable {
public void setName(String name);
public String getName();
static aspect Impl {
private String Nameable._name;
public void Nameable.setName(String name) {
_name = name;
}
public String Nameable.getName() {
return _name;
}
}
}
===============================================================================
public interface Identifiable {
public void setId(String id);
public String getId();
static aspect Impl {
private String Identifiable._id;
public void Identifiable.setId(String id) {
_id = id;
}
public String Identifiable.getId() {
return _id;
}
}
}
===============================================================================
public class Entity implements Nameable, Identifiable {
}
有了AOP後
Default Implementation不再是class與abstract class的專利
看看上面的程式碼
想想自己系統中多少domain object有name與id這兩個property
就會知道這個AOP Idiom可以省下多少行程式
不過設計上要更小心是一定的
另外AJDT對於這些introduction進來的field與method
似乎還沒有辦法用快捷鍵則是比較麻煩的地方
Monday, March 26, 2007
Paper Note: FormCreationAspect.aj
原本在Execution Code裡面需要跟使用者取得資料時
會產生一個Form物件
並且把一些跟目前Activity有關的資料塞進去這個Form中
如此才能夠讓Form正確地submit回來
public class ActivityExecutionCode extends ActivityExecutionCode {
public void call(Message reqMsg) {
...
Form form = new Form("Activity Form");
form.add(new HiddenField("action", "FormSubmit"));
form.add(new HiddenField("pid", reqMsg.get("pid")));
form.add(new HiddenField("aName", reqMsg.get("aName")));
form.add(new HiddenField("taskId", reqMsg.get("taskId")));
form.add(new Label("message", "Message"));
form.add(new TextField("message", ""));
form.add(new LineBreak());
form.add(new Button(Button.ButtonType.SUBMIT, "Send"));
Message result = form.submit();
String message = result.get("message");
...
}
}
但其實我們不想讓寫Execution Code的設計者管這些其實跟本身Execution Code邏輯無關的東西
所以我們用FormCreationAspect來讓它自動塞入資料
public aspect FormCreationAspect {
pointcut formCreation(Form form): initialization(Form.new(String)) && target(form);
pointcut activityCall(Message reqMsg):
execution(public void ActivityExecutionCode+.call(Message)) && args(reqMsg);
after(Form form, Message reqMsg):
formCreation(form) && cflowbelow(activityCall(reqMsg)){
// action=FormSubmit
form.add(new HiddenField("action", "FormSubmit"));
// pid={pid}
String pidString = reqMsg.get("pid");
if (!ParamUtil.noValue(pidString)) {
Long pid = Long.parseLong(pidString);
form.add(new HiddenField("pid", "" + pid));
}
// aName={aName}
String aName = reqMsg.get("aName");
if (!ParamUtil.noValue(aName)) {
form.add(new HiddenField("aName", aName));
}
// taskId={taskId}
String taskId = reqMsg.get("taskId");
if (!ParamUtil.noValue(taskId)) {
form.add(new HiddenField("taskId", taskId));
}
}
}
原本的Execution Code就變成下面這樣
少了原本塞資料的四行程式碼!
public class ActivityExecutionCode extends ActivityExecutionCode {
public void call(Message reqMsg) {
...
Form form = new Form("Activity Form");
form.add(new Label("message", "Message"));
form.add(new TextField("message", ""));
form.add(new LineBreak());
form.add(new Button(Button.ButtonType.SUBMIT, "Send"));
Message result = form.submit();
String message = result.get("message");
...
}
}
Labels: aop, aspectj, java, note
Thursday, March 22, 2007
Worker Object Creation Pattern
這是拿AspectJ in Action裡8.1 The worker object creation pattern中程式碼修改過的進化版本
我加了Annotation與Java 5新的Concurrent API
public @interface AsynchronousExecution {
}
=============================================================================
public class CachePreFetcher {
@AsynchronousExecution
static void fetch() {
System.out.println("Fetching in thread " + Thread.currentThread());
}
@AsynchronousExecution
static String fetchValue() {
System.out
.println("Fetching Value in thread " + Thread.currentThread());
return "fetchValue";
}
}
=============================================================================
public class ProjectSaver {
@AsynchronousExecution
static void backupSave() {
System.out.println("Saving backup copy in thread "
+ Thread.currentThread());
}
}
=============================================================================
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public abstract aspect AsynchronousExecutionAspect {
public abstract pointcut asyncOperations();
public abstract pointcut asyncValueOperations();
private static final ExecutorService exec = Executors.newCachedThreadPool();
public static void shutDownExecutorService() {
try {
exec.awaitTermination(10, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
System.err.println(e);
}
exec.shutdown();
}
void around(): asyncOperations(){
Runnable worker = new Runnable() {
public void run() {
proceed();
}
};
exec.execute(worker);
}
Object around() : asyncValueOperations(){
Callable<Object> worker = new Callable<Object>() {
public Object call() {
return proceed();
}
};
Future<Object> future = exec.submit(worker);
Object result = null;
try {
result = future.get();
} catch (Exception e) {
System.err.println(e);
}
return result;
}
}
=============================================================================
public aspect SystemAsynchronousExecutionAspect extends
AsynchronousExecutionAspect {
public pointcut asyncOperations():
call(@AsynchronousExecution void *.*(..));
public pointcut asyncValueOperations():
call(@AsynchronousExecution * *.*(..));
}
=============================================================================
public class Test {
public static void main(String[] args) {
CachePreFetcher.fetch();
String value = CachePreFetcher.fetchValue();
System.out.println("CachePreFetcher.fetchValue() returns " + value);
ProjectSaver.backupSave();
AsynchronousExecutionAspect.shutDownExecutorService();
}
}
Labels: aop, aspectj, java, pattern



