Sunday, April 01, 2007

 

Default Interface Implementation

這是AspectJ in Action8.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
似乎還沒有辦法用快捷鍵則是比較麻煩的地方

Labels: , ,


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: , , ,


Thursday, March 22, 2007

 

Worker Object Creation Pattern

這是拿AspectJ in Action8.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: , , ,