ファサードパターンは、呼び出し元クライアントと Java Persistence API のモデルエンティティー、およびオペレーション間の対話をカプセル化し、一元化する上位クラスを定義します。ファサードパターンは、一群のエンティティーに対するオペレーションに単一のインタフェースを提供します。このファサードを利用するクライアントは、各エンティティーの API の詳細をすべて意識する必要はなく、エンティティーマネージャーまたはそのほかのトランザクションマネージャーにアクセスする際に使用される、持続性機構を意識する必要もありません。呼び出し元クライアントとモデル層のエンティティーとの間にファサードを導入することによって、コードが疎結合になり、保守が容易になります。
コード例 1 に示すように、ファサードを利用したコードはすっきりとしたものになります。ファサードを利用しないと、エンティティーのクライアントはそのエンティティーの詳細を知っている必要があり、エンティティーへのアクセスが必要になるたびに、類似のコードをほかの場所にカット & ペーストすることになります。ファサードを導入後のコードでは、モデル層のエンティティーの細部の多くが隠されています。
ファサード導入前 | ファサード導入後 |
public class MyWebClient ... {
//これでモデル層のエンティティーにアクセスします EntityManager em = |
...
myfacade.addItem(item); |
public class CatalogFacade implements ServletContextListener {
@PersistenceUnit(unitName="CatalogPu") private EntityManagerFactory emf;
@Resource UserTransaction utx;
public CatalogFacade(){}
public void contextDestroyed(ServletContextEvent sce) {
if (emf.isOpen()) {
emf.close();
}
}
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
context.setAttribute("CatalogFacade", this);
}
public void addItem(Item item) throws InvalidItemException {
EntityManager em = emf.createEntityManager();
if(item.getName().length() == 0)
throw new InvalidItemException("The item" + " name cannot be empty. Pease specify a name for the item.");
try {
utx.begin();
em.joinTransaction();
em.persist(item);
utx.commit();
} catch(Exception exe){
System.err.println("Error persisting item: "+exe);
try {
utx.rollback();
} catch (Exception e) {
System.err.println("Error persisting item: "+ e.getMessage(), e);
}
throw new RuntimeException("Error persisting item: "+ exe.getMessage(), exe);
} finally {
em.close();
}
}
public Item getItem(int itemID){
EntityManager em = emf.createEntityManager();
Item item = em.find(Item.class,itemID);
em.close();
return item;
}
public List
EntityManager em = emf.createEntityManager();
List
em.close();
return items;
}
ServletContextListener
インタフェースを実装させていることです。こうすることにより、Java EE プラットフォームの Java Persistence エンティティーや関連サービスにアクセスするときに有用な注釈を利用できます。サーブレットなどの Web コンポーネントがこのファサードを検索して利用する方法を見てみましょう。たとえば addItem
メソッドには、エンティティーにアクセスするためのトランザクション境界用の JTA API が必要です。また、データベースに新しい Item を格納するには、EntityManager API が必要です。ファサードクラス内の 1 箇所にこうしたコードをまとめると、エンティティーへのアクセスが必要になるたびにアプリケーションの至るところに類似のコードをカット&ペーストするよりも便利です。コード例 3: モデルファサードを使って Java Persistence エンティティーにアクセスする Web コンポーネント
public class CatalogServlet extends HttpServlet {
private ServletContext context;
private CatalogFacade cf;
public void init(ServletConfig config)throws ServletException {
context = config.getServletContext();
cf = (CatalogFacade)context.getAttribute("CatalogFacade");
initPathMapping();
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
try {
if (selectedURL.equals("additem.do")) {
//要求から値を取得し、
//その値を新規 Item に設定して、データベースに追加
String desc = request.getParameter("item_desc");
String name = request.getParameter("item_name");
...
Item item = new Item();
item.setName(name);
item.setDescription(desc);
...
cf.addItem(item); //こうしてから、ファサードを呼び出す
...
}
}
init
メソッドによってファサードを取得し、そのファサードをほかのクライアント要求で利用、共有できるよう、サーブレットにフィールドとして格納していることです。要求を処理する際、サーブレットはファサードを使用することができ、エンティティーへのアクセスに必要なエンティティーや持続性関係の細部に関わる必要がなくなります。
@Stateless()
public class CatalogFacadeBean implements CatalogFacade {
@PersistenceContext(unitName="CatalogPu")
private EntityManager em;
public void addItem(Item item) throws InvalidItemException {
if(item.getName().length() == 0)
throw new InvalidItemException("The item" +
" name cannot be empty. Please specify a name for the item.");
em.persist(item);
}
public Item getItem(int itemID) {
Item item = em.find(Item.class,itemID);
return item;
}
public List<Item> getAllItems() {
List<Item> items = em.createQuery("SELECT OBJECT(i) FROM Item i").getResultList();
return item;
}
}
public class CatalogServlet extends HttpServlet {
private Map nameSpace;
private ServletContext context;
@EJB(name="CatalogFacadeBean") private CatalogFacade cf;
public void init(ServletConfig config) throws ServletException {
context = config.getServletContext();
initPathMapping();
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
try {
if (selectedURL.equals("additem.do")) {
//要求から値を取得し、新規 Item にその値を設定
String desc = request.getParameter("item_desc");
String name = request.getParameter("item_name");
...
Item item = new Item();
item.setName(name);
item.setDescription(desc);
...
//ファサードを使用して新規 Item をデータベースに追加
cf.addItem(item);
...
}
...
}
@EJB(name="CatalogFacadeBean")
を使ってファサードをルックアップし、取得するために、依存性注入を使用しています。ほかのクライアント要求で利用、共有できるよう、ファサードをフィールドとして格納しています。ファサードを利用することで、モデル層へのアクセスの詳細が隠されます。