IK.AM

@making's tech note


Java EE 6 ハンズオンラボでJavaEE6を始めよう!(JBoss Forge付き) javaee glassfishjp

🗃 {Programming/Java/JavaEE6/AdventCalendar/2012}
🗓 Updated at 2012-11-20T17:17:57Z  🗓 Created at 2012-11-20T17:17:57Z   🌎 English Page

JavaEE Advent Calendar 2012 1日目の記事です。

Java EE6 ハンズオンラボ

Oracleの@arunguptaさんが公開しているJavaEE6ハンズオンラボはご存知でしょうか? このハンズオンでは簡単なアプリケーションを作成することでJavaEE6の主要技術を一通り学ぶことができます。 扱っている技術は

  • JPA 2 (MetaModelを使ったCriteriaQuery含む)
  • Sevlet 3
  • EJB 3.1 (@Schedule含む)
  • JSF 2 (Ajax含む)
  • JAX-RS
  • CDI (Interceptor含む)
  • Bean Validation

です。46ページのドキュメントですが要領よく、かなり網羅されています。

これからJavaEE6を始める人の最初の一歩にぴったりではないでしょうか。

Beginning Java EE 6 GlassFish 3で始めるエンタープライズJava (Programmer’s SELECTION)

金魚本についている付録のハンズオンはこの資料の前のバージョンの翻訳です(あれを書いたのも実は自分なのですが。。色々すいません)。

そして今回のバージョンの資料は細々と翻訳しています。 https://github.com/making/javaee6-hol-glassfish-doc

翻訳バージョンはhttps://javaee6-hol-glassfish-doc.readthedocs.org/から参照可能です(随時更新中)

訳がいまいちなところも多々あるので、翻訳に協力してくれる方はpull requestください! よろしくお願いします!!

JBoss Forgeでチュートリアルを進めてみる

ではこのチュートリアルをJBoss Forgeで作ってみましょう。 本家チュートリアルではNetBeansを使ってJavaEE6アプリケーションを作成していますが、 折角なのであえてJBoss Forgeでもやってみます。

元々次の回に書くつもりでしたが、JavaEE Advent Calendarが埋まっちゃったので。。

JBoss Forgeって何?

JBoss ForgeはJava EE用のRADツールで、プロジェクト(+ソース)雛形生成ツールという色が強いです。コマンドラインでMavenベースドなプロジェクトを構築して、ソースコードを生成していきます。 JBossプロダクトですが、APサーバーはJBoss ASに限定しているわけではなく、Glass Fishでも全然OKです。 似たようなプロジェクトでSpring Rooがありますが、Rooは生成されたコードがAspectJの黒魔術すぎて、生成した後実際にどうプロジェクトを進めて良いかわからん!というのに対して、Forgeはplainなソースコードを吐いてくれるので、出力したあと自分で作り込んでいくというのが容易です。

JBoss Forgeをインストール

Macユーザーはbrewでインストールできます。非Macユーザーは自分で調べてください。Mac買えや。

$ brew install jboss-forge
==> Downloading https://repository.jboss.org/nexus/service/local/artifact/maven/redirect?r=releases&g=org.jboss.forge&a=forge-distribution&v=1.1.1.Final&e=zi
######################################################################## 100.0%
/usr/local/Cellar/jboss-forge/1.1.1.Final: 209 files, 29M, built in 107 seconds

JBoss Forgeを実行

forgeコマンドで起動します。環境変数JAVA_HOMEが設定されている必要があります。 Macユーザーは

$ export JAVA_HOME=/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/ 

な感じ。

$ forge
Using Forge at /usr/local/Cellar/jboss-forge/1.1.1.Final/libexec
    _____                    
   |  ___|__  _ __ __ _  ___ 
   | |_ / _ \| `__/ _` |/ _ \  \\
   |  _| (_) | | | (_| |  __/  //
   |_|  \___/|_|  \__, |\___| 
                   |___/      

JBoss Forge, version [ 1.1.1.Final ] - JBoss, by Red Hat, Inc. [ http://jboss.org/forge ]

プロジェクト作成

new-projectコマンドでプロジェクトを作成します。名前とトップレベルのパッケージを指定します(Rooとそっくり)。チュートリアルにしたがってプロジェクト名を"JavaEE6SampleApp"、トップレベルのパッケージを"org.glassfish.samples"

[no project] forge $ new-project --named JavaEE6SampleApp --topLevelPackage org.glassfish.samples
 ? Use [/Users/maki/forge/JavaEE6SampleApp] as project directory? [Y/n] 
***SUCCESS*** Created project [JavaEE6SampleApp] in new working directory [/Users/maki/forge/JavaEE6SampleApp]
Wrote /Users/maki/forge/JavaEE6SampleApp
Wrote /Users/maki/forge/JavaEE6SampleApp/pom.xml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java
Wrote /Users/maki/forge/JavaEE6SampleApp/src/test/java
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/resources
Wrote /Users/maki/forge/JavaEE6SampleApp/src/test/resources
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples

Scaffoldの設定

RADツール定番のScaffoldです。まずはセットアップでViewテクノロジーを選択します。当然JSFを指定。scaffoldコマンドを実行します。設定はデフォルトでいいのでEnterを押しまくってください。

[JavaEE6SampleApp] JavaEE6SampleApp $ scaffold setup --scaffoldType faces
 ? Scaffold provider [faces] is not installed. Install it? [Y/n] 
 ? Facet [forge.maven.WebResourceFacet] requires packaging type(s) [war], but is currently [jar]. Update packaging? (Note: this could deactivate other plugins in your project.) [Y/n] 
***SUCCESS*** Installed [forge.maven.WebResourceFacet] successfully.
Use which version of 'jboss-javaee-6.0' ?

  1 - [org.jboss.spec:jboss-javaee-6.0:pom::1.0.0.Beta4]
  2 - [org.jboss.spec:jboss-javaee-6.0:pom::1.0.0.Beta5]
  3 - [org.jboss.spec:jboss-javaee-6.0:pom::1.0.0.Beta6]
  4 - [org.jboss.spec:jboss-javaee-6.0:pom::1.0.0.Beta7]
  5 - [org.jboss.spec:jboss-javaee-6.0:pom::1.0.0.CR1]
  6 - [org.jboss.spec:jboss-javaee-6.0:pom::1.0.0.Final]
  7 - [org.jboss.spec:jboss-javaee-6.0:pom::2.0.0.Beta1]
  8 - [org.jboss.spec:jboss-javaee-6.0:pom::2.0.0.CR1]
  9 - [org.jboss.spec:jboss-javaee-6.0:pom::2.0.0.Final]
  10 - [org.jboss.spec:jboss-javaee-6.0:pom::2.1.0.Beta1]
  11 - [org.jboss.spec:jboss-javaee-6.0:pom::3.0.0.Beta1]
  12 - [org.jboss.spec:jboss-javaee-6.0:pom::3.0.0.Final]
  13 - [org.jboss.spec:jboss-javaee-6.0:pom::3.0.1.Final]*

 ? Choose an option by typing the number of the selection [*-default]  [0] 
***SUCCESS*** Installed [forge.spec.jpa] successfully.
***SUCCESS*** Installed [forge.spec.ejb] successfully.
***SUCCESS*** Installed [forge.spec.cdi] successfully.
***SUCCESS*** Installed [forge.spec.servlet] successfully.
***SUCCESS*** Installed [forge.spec.jsf.api] successfully.
***SUCCESS*** Installed [faces] successfully.
 ? Create scaffold in which sub-directory of web-root? (e.g. http://localhost:8080/JavaEE6SampleApp/DIR) [/] 
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp
Wrote /Users/maki/forge/JavaEE6SampleApp/pom.xml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/resources/META-INF/persistence.xml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/WEB-INF/beans.xml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/WEB-INF/faces-config.xml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/favicon.ico
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/scaffold/paginator.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/scaffold/pageTemplate.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/index.html
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/index.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/error.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/add.png
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/bootstrap.css
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/false.png
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/favicon.ico
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/forge-logo.png
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/forge-style.css
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/remove.png
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/search.png
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/true.png
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/jboss-community.png
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/WEB-INF/web.xml

実はデフォルトでJSFしか選べません。プラグインをインストールすることでViewを追加することが出来ます。なんとSpring MVC版も作れたりします!

JPAの設定

JPAの設定をします。Hibernate、JBoss ASを使わず、あえてEclipseLink、GlassFishを選択します。データソースのJNDI名もチュートリアルにあわせてjdbc/sampleに。

[JavaEE6SampleApp] JavaEE6SampleApp $ persistence setup --provider ECLIPSELINK --container GLASSFISH_3 --jndiDataSource jdbc/sample
***INFO*** Setting transaction-type="JTA"
***INFO*** Overriding example datasource with [jdbc/sample]
 ? Do you want to install a JPA 2 metamodel generator? [y/N] 
 ? The JPA provider [ECLIPSELINK], also supplies extended APIs. Install these as well? [y/N] 
***SUCCESS*** Persistence (JPA) is installed.
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/resources/META-INF/persistence.xml

次のようなpersistence.xmlが出力されます。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="forge-default" transaction-type="JTA">
    <description>Forge Persistence Unit</description>
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/sample</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Entityを作成

チュートリアルでは既存でDBテーブルからリバースエンジニアリングでEntityを生成していますが、今回はまずは先にEntityを作成してみます。連絡先Eメールアドレスと名前を持ったContactエンティティを作成してみます。パッケージ名はorg.glassfish.samples.entitiesで。

[JavaEE6SampleApp] JavaEE6SampleApp $ entity --named Contact --package org.glassfish.samples.entities --idStrategy AUTO 
Created @Entity [org.glassfish.samples.entities.Contact]
Picked up type <JavaResource>: org.glassfish.samples.entities.Contact
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Contact.java
[JavaEE6SampleApp] Contact.java $ field string --named email
Added field to org.glassfish.samples.entities.Contact: @Column private String email;

Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Contact.java
[JavaEE6SampleApp] Contact.java $ field string --named name
Added field to org.glassfish.samples.entities.Contact: @Column private String name;

Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Contact.java

lsコマンドでフィールド、メソッド一覧を表示できます。id、versionは勝手に付与されます。

[JavaEE6SampleApp] Contact.java $ ls

[fields]
private::Long::id;             private::String::email;        private::String::name;
private::int::version;         

[methods]
public::equals(Object that)::boolean                   public::getEmail()::String
public::getId()::Long                                  public::getName()::String
public::getVersion()::int                              public::hashCode()::int
public::setEmail(final String email)::void             public::setId(final Long id)::void
public::setName(final String name)::void               public::setVersion(final int version)::void
public::toString()::String  

実際には次のようなソースが出力されています。

package org.glassfish.samples.entities;

import javax.persistence.Entity;
import java.io.Serializable;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Column;
import javax.persistence.Version;
import java.lang.Override;

@Entity
public class Contact implements Serializable
{

   @Id
   private @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id", updatable = false, nullable = false)
   Long id = null;
   @Version
   private @Column(name = "version")
   int version = 0;

   @Column
   private String email;

   @Column
   private String name;

   public Long getId()
   {
      return this.id;
   }

   public void setId(final Long id)
   {
      this.id = id;
   }

   public int getVersion()
   {
      return this.version;
   }

   public void setVersion(final int version)
   {
      this.version = version;
   }

   @Override
   public boolean equals(Object that)
   {
      if (this == that)
      {
         return true;
      }
      if (that == null)
      {
         return false;
      }
      if (getClass() != that.getClass())
      {
         return false;
      }
      if (id != null)
      {
         return id.equals(((Contact) that).id);
      }
      return super.equals(that);
   }

   @Override
   public int hashCode()
   {
      if (id != null)
      {
         return id.hashCode();
      }
      return super.hashCode();
   }

   public String getEmail()
   {
      return this.email;
   }

   public void setEmail(final String email)
   {
      this.email = email;
   }

   public String getName()
   {
      return this.name;
   }

   public void setName(final String name)
   {
      this.name = name;
   }

   public String toString()
   {
      String result = "";
      if (email != null && !email.trim().isEmpty())
         result += email;
      if (name != null && !name.trim().isEmpty())
         result += " " + name;
      return result;
   }
}

EntityからScaffold生成

さっきセットアップしたScaffoldを実際に生成しています。

[JavaEE6SampleApp] Contact.java $ scaffold from-entity
***INFO*** Using currently installed scaffold [faces]
 ? [/Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/scaffold/pageTemplate.xhtml] File exists, overwrite? [Y/n] 
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.Contact]
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/view/ContactBean.java
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/contact/create.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/contact/view.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/contact/search.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/resources/scaffold/pageTemplate.xhtml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/view/ViewUtils.java
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/webapp/WEB-INF/classes/META-INF/forge.taglib.xml
Wrote /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Contact.java

パッケージ名を指定しないとviewパッケージに出力されます。まあいいか。

NetBeanでプロジェクトを開く

ForgeでできたプロジェクトはMavenプロジェクトなのでNetBeansでそのまま開けます。開く前にJTAのセットアップをしておきます。これがないとNetBeansでエラーになります。

[JavaEE6SampleApp] Contact.java $ jta setup 
***SUCCESS*** Installed [forge.spec.jta] successfully.
***SUCCESS*** Java Transaction API (JTA) is installed.
Wrote /Users/maki/forge/JavaEE6SampleApp/pom.xml

NetBeansを開いて「プロジェクトを開く」で"JavaEE6SampleApp"を選択し開きます。

こんな感じのプロジェクトになります。

一時的にsrc/main/resources/META-INF/persistence.xmlの"eclipselink.ddl-generation"の値を"create-tables"に変えておきます。

<property name="eclipselink.ddl-generation" value="create-tables"/>

GlassFishを起動した後、プロジェクト名を右クリックして「実行」をクリック。サーバーを選択。

ブラウザが立ち上がり次のような画面が表示されます。

左側の"Contact"をクリックするとContactエンティティのCRUD画面へ遷移します。

既存のテーブルからEntityをリバースエンジニアリングする

チュートリアル同様、APPデスキーマのテーブルからEntityを自動生成してみます。 実はリバースエンジニアリング機能は標準ではなくて、hibernate-toolsプラグインをインストールする必要があります。

[JavaEE6SampleApp] Contact.java $ forge install-plugin hibernate-tools 

NetBeansで立ち上げているDerbyに接続して自動生成させます。derbyclient.jarの位置は適宜修正してください。

[JavaEE6SampleApp] entities $ generate-entities --datasource jdbc/sample --url jdbc:derby://localhost:1527/sample --schema APP --user app --dialect org.hibernate.dialect.DerbyDialect --driver org.apache.derby.jdbc.ClientDriver --pathToDriver /Applications/NetBeans/glassfish-3.1.2.2/javadb/lib/derbyclient.jar --entityPackage org.glassfish.samples.entities
 ? Enter the password for JDBC connection. ***
Found 9 tables in datasource
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Customer.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Sequence.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Product.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Manufacturer.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/PurchaseOrder.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/MicroMarket.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/ProductCode.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/Contact.java
Generated java at /Users/maki/forge/JavaEE6SampleApp/src/main/java/org/glassfish/samples/entities/DiscountCode.java
Generated 9 java files.

エンティティが生成されました。"eclipselink.ddl-generation"を"none"に変更します。

  <property name="eclipselink.ddl-generation" value="none"/>

そしてScaffoldを再実行。

[JavaEE6SampleApp] entities $ scaffold from-entity org.glassfish.samples.entities.* --overwrite 
***INFO*** Using currently installed scaffold [faces]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.Contact]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.Customer]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.DiscountCode]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.Manufacturer]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.MicroMarket]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.Product]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.ProductCode]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.PurchaseOrder]
***SUCCESS*** Generated UI for [org.glassfish.samples.entities.Sequence]
Wrote (略..)

再実行すると次のようにエンティティの選択肢が増えます。

さてここからチュートリアルではServletを作ったり、EJBを作ったりするわけですが、 本記事ではこの辺で終了しておきます。。というかNetBeansで直接作っちゃってOKです。 (ちなみに↑くらいのScaffoldならNetBeans単体で実現できます。。出力されるManagedBeanのソースもあまり奇麗でない。。)

src/main/webapp/resources/scaffold/pageTemplate.xhtmlにFaceletsのテンプレートができているので、 これをベースに新規ページを作っていくのが良いのではないでしょうか。

(ちなみに次のGlassFish勉強会でもこのネタ発表します。。ネタ少なくてすいません)

2日目は@megascusさんお願いします!


✒️️ Edit  ⏰ History  🗑 Delete