hatenob

プログラムって分からないことだらけ

Wildfly 8とHibernate OGMでMongoDBにJPA

前回からの続き的内容。
RESTの受け口が作れたので、今度はそれを永続化するところに挑戦。

永続化と言えばDBなので、MySQLとかでもいんだけれども、せっかくなのでMongoDBに永続化することにしてみます。
Javaなので、APIは当然JPAです!って、MongoDBとかってJPA対応したクライアントとかあるのだろうか?と思って探していたら、Hibernate OGMというのを使うとできるらしいということが分かった。
んで、これはどうやらWildfly 8.2にはデフォルトでは含まれていないもののようだということも分かった。
ダウンロードしてきてmodulesに登録してもいいのだけれど、お試しなのでwarに抱き込んでやることにします。

pom.xml

warに抱き込むことにしたのでdependencyにscopeをcompileで追加してやります。
resteasyはJPAには関係なくて、テストする時用のJAX-RSクライアントです。

<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-mongodb</artifactId>
    <version>4.1.0.CR1</version>
    <scope>compile</scope>
</dependency>

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-jaxrs</artifactId>
    <version>3.0.10.Final</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.jboss.resteasy</groupId>
    <artifactId>resteasy-client</artifactId>
    <version>3.0.10.Final</version>
    <scope>test</scope>
</dependency>

Entity

エンティティクラスはこんな感じ。

@Entity
public class Todo implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;

    @Column
    private String title;

    @Column
    private boolean done;

    // setter/getterは省略

GeneratedValueのところが少しはまりポイントでした。
何もつけないとエラーになったので、色々調べて上の書き方に落ち着きました。

persistence.xml

ほぼサンプルから拾ったまんま。

<persistence-unit name="mongoUnit" transaction-type="JTA">
    <!-- Use Hibernate OGM provider: configuration will be transparent -->
    <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
    <class>com.github.chanko.jpa.Todo</class>
    <properties>
        <property name="hibernate.transaction.jta.platform"
            value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
        <property name="hibernate.ogm.datastore.provider" value="mongodb" />
        <property name="hibernate.ogm.datastore.host" value="192.168.33.11" />
        <property name="hibernate.ogm.datastore.port" value="27017" />
        <property name="hibernate.ogm.datastore.database" value="todo" />
    </properties>
</persistence-unit>

直接ホストを指定してるけれど、wildflyのdatasourceに設定してそれを参照するようなやり方は見つけらなかった。ここはイマイチなところ。

EJB

JPAエンティティはEJBから扱ってやることにします。
JPAにしたのでこちらは特にいつも通りで変わったことはしておりません。

@Stateless
@Named
public class TodoBean {
    @PersistenceContext
    private EntityManager em;

    public void register(String title, boolean done) {
        Todo todo = new Todo();
        todo.setTitle(title);
        todo.setDone(done);

        em.persist(todo);
    }
}

JAX-RS

リクエストの受け口を作っておきます。
引数や戻りのクラス構造はご想像ください。

@Path("todo")
public class TodoService {
    @Inject
    private TodoBean todoBean;

    @PUT
    @Path("register")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Result register(TodoParam param) {
        try {
            todoBean.register(param.getTitle(), param.isDone());

            Result r = new Result();
            r.setResult("success");
            r.setCount(1);

            return r;
        } catch (Throwable t) {
            Result r = new Result();
            r.setResult("failure");
            r.setCount(-1);
            return r;
        }
    }
}

JAX-RSクライアント

あとはこのサービスを呼んでやればOKです。
JUnitから実行したりできるので、JAX-RSのクライアントを使って呼び出すことにします。

Client client = ClientBuilder.newClient();
Response res = client
    .target(new URI("http://localhost:8080/chanko-angularjs/rs/todo/register"))
    .request(MediaType.APPLICATION_JSON)
    .put(Entity.json(Json.createObjectBuilder()
        .add("title", "hoge").add("done", true).build()
        .toString()));

結果

無事に登録されました。

> db.Todo.find()
{ "_id" : "23cb7f5b-1bfa-49d4-b0a2-281479201004", "title" : "hoge", "done" : true }

まとめ

Wildfly 8.2とHibernate OGMを使って、MongoDBにJPAでアクセスできるようになりました。
メデタシ、メデタシ。

あとはAngularJSからREST APIを投げるところが書けたら完成。
あと少し。