ラベル JDO の投稿を表示しています。 すべての投稿を表示
ラベル JDO の投稿を表示しています。 すべての投稿を表示

2009年6月27日土曜日

GAEで派生データを登録


すでにこの設定などは古くなっている可能性があります。

Slim3の開発はこんなブログより正式ドキュメントが有効です。
Slim3サイト
非公式と言われていますが充実した日本語サイトもあります。
Slim3日本語サイト



少し前に試した時にダメだったので諦めていたのですが、
再度チャレンジしたらOKだったので投稿しておきます。

親クラスを準備します。

package bz.ziro.slim3.test.model;

import java.io.Serializable;
import java.util.Date;
import java.util.logging.Logger;

import javax.jdo.JDOHelper;
import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import javax.jdo.annotations.Version;
import javax.jdo.annotations.VersionStrategy;

import com.google.appengine.api.users.User;

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
@Version(strategy = VersionStrategy.VERSION_NUMBER)
public class Parent implements Serializable {

private static final long serialVersionUID = 1L;

@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(Parent.class.getName());

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String key;


@Persistent
private User creator;
@Persistent
private Date createDate;
@Persistent
private User editor;
@Persistent
private Date editDate;

/**
* @return the key
*/
public String getKey() {
return key;
}

/**
* @param key
* the key to set
*/
public void setKey(String key) {
this.key = key;
}
public User getCreator() {
return creator;
}

public void setCreator(User creator) {
this.creator = creator;
}

public Date getCreateDate() {
return createDate;
}

public void setCreateDate(Date createDate) {
this.createDate = createDate;
}

public User getEditor() {
return editor;
}

public void setEditor(User editor) {
this.editor = editor;
}

public Date getEditDate() {
return editDate;
}

public void setEditDate(Date editDate) {
this.editDate = editDate;
}

/**
* @return the version
*/
public long getVersion() {
return (Long) JDOHelper.getVersion(this);
}
}



でこのクラスを派生した子クラスを準備します。


package bz.ziro.slim3.test.model;

import java.io.Serializable;
import java.util.logging.Logger;

import javax.jdo.JDOHelper;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.Version;
import javax.jdo.annotations.VersionStrategy;

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable = "true")
@Version(strategy = VersionStrategy.VERSION_NUMBER)
public class Child extends Parent implements Serializable {

private static final long serialVersionUID = 1L;

@SuppressWarnings("unused")
private static final Logger logger = Logger.getLogger(Child.class.getName());

@Persistent
private String name;
@Persistent
private String detail;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
/**
* @param detail セットする detail
*/
public void setDetail(String detail) {
this.detail = detail;
}
/**
* @return detail
*/
public String getDetail() {
return detail;
}
/**
* @return the version
*/
public long getVersion() {
return (Long) JDOHelper.getVersion(this);
}
}



これで準備完了です。
ChildオブジェクトをGAE(JDO,BigTable)で登録すれば
Parentの属性も登録できます。


実装の通り、登録ユーザや登録日付などテーブル内にある同一の属性を
親クラスを利用することにより、はしょることができます。
まぁ私の場合は更新時などにオブジェクトに都度同一の実装が必要になり
困っていたので助かります。

JDOを知った時に論理モデル(つうかUML記述?)をそのまま使えるなぁ。。。
って思ってやったらダメだったんですけど、やっぱできるんですね。

ちなみにDataNucleusでJDBC(HSQLDB)で同じようにやると
Parentテーブルがにもデータがあって。。。って感じになった記憶があります。
※同一のエンティティではないです。


ちなみにSlim3のDaoでMetaクラスを利用して検索式を作成しても
ChildMetaに存在しないのでエラーになります。
問い合わせるかはもう少し試してからにしようと思ってます。

2009/07/08 ※再度試したらSlim3でも動作しました。
2009/07/26 ※再度試したらSlim3で動作。。。っていうかGAEで動作しませんでした。
ので、Embeddedの話で記述します。

2009年5月31日日曜日

Slim3でユーザの検索


すでにこの設定などは古くなっている可能性があります。

Slim3の開発はこんなブログより正式ドキュメントが有効です。
Slim3サイト
非公式と言われていますが充実した日本語サイトもあります。
Slim3日本語サイト




UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();

ShopMeta shopMeta = new ShopMeta();
List<Shop> list = from(Shop.class).where(shopMeta.creator.eq(user)).getResultList();


ShopMetaは自動的に作られます。(aptとかをプロジェクトで設定します)
creatorはJDOで保存しているカラムの一部です。
※aptについては今勉強中です。後日設定方法を書きます。

なんかおしゃれになってきましたね。
もし私がゴクウだったら「おらワクワクしてきたぞ状態」です。

2009年5月16日土曜日

DataNucleusでJDBC接続

datanucleus.propertiesを作成して

javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.jdo.JDOPersistenceManagerFactory

javax.jdo.option.ConnectionDriverName=org.hsqldb.jdbcDriver
javax.jdo.option.ConnectionURL=jdbc:hsqldb:hsql://localhost/sealion_db
javax.jdo.option.ConnectionUserName=sa
javax.jdo.option.ConnectionPassword=
javax.jdo.option.Mapping=hsql


クラスパスのトップにおいて

private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("datanucleus.properties");
public static PersistenceManagerFactory get() {
return pmfInstance;
}

でPersistenceManagerFactoryを取得します。

これと同様にMETA-INF/jdoconfig.xmlを作成して

<?xml version="1.0" encoding="utf-8"?>
<jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">

<persistence-manager-factory name="transactions-optional">
<property name="javax.jdo.PersistenceManagerFactoryClass"
value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>
<property name="javax.jdo.option.ConnectionURL" value="appengine"/>
<property name="javax.jdo.option.NontransactionalRead" value="true"/>
<property name="javax.jdo.option.NontransactionalWrite" value="true"/>
<property name="javax.jdo.option.RetainValues" value="true"/>
<property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/>
</persistence-manager-factory>
</jdoconfig>


と行います。
その場合は

private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");
public static PersistenceManagerFactory get() {
return pmfInstance;
}

って感じになります。
何個もセッションを用意する場合は、指定子(transactions-optional)を
変更して追加します。

2009年5月9日土曜日

DataNucleusを動かしてみる

GAEやSlim3を動作させてきました。
せっかくなのでSlim3を生で使いたいと思い立ちました。
Hibernate,S2DAOなどを使って。。。と思いましたが
せっかくなのでDataNucleusを使ってHSQLDBにアクセスしたと思います。
※とは言ってもサンプルです。

まず、DataNucleusのページから
http://sourceforge.net/project/showfiles.php?group_id=222750

・core
・rdbms
・enhancer
・sample

をダウンロードしてきます。

ObjectWebのASMサイトから
http://forge.ow2.org/project/download.php?group_id=23&file_id=9309

・asm

をダウンロードしてきて

Log4Jから
http://logging.apache.org/log4j/1.2/download.html

・Log4J

をダウンロードしてきます。
ApacheJDOから。。。といきたいところですが
JDOの2.3が必要ですので
http://www.datanucleus.org/downloads/maven2/javax/jdo/jdo2-api/

・JDO

をダウンロードしてきます。
HSQLDBから
http://sourceforge.net/project/platformdownload.php?group_id=23316&sel_platform=14519

・HSQLDB

をダウンロードしてきます。

JDOの2.3ってGAEでも使ってるんですけど良いんでしょうね。
※SNAPSHOTからea(アーリーアクセス?)に代わってますね。

解凍してきたHSQLDBの
demo/runServer.bat実行してDBを立ち上げます。


で、DataNucleusのsampleを解凍してeclipseに展開します。
でダウンロードしてきたそれぞれのjarをlibディレクトリなどに展開。
jarをクラスパスに追加してMainを実行します!



・・・・あれ?うごかない。。。
って調べていたら
JDOの設定ファイル「package.jdo」がない。。。
あれ?ormファイルならある。。。なんかの仕様変更ですかね。。。


http://www.datanucleus.org/products/accessplatform_1_0/guides/jdo/tutorial.html

にあるjdoファイルをコピーして作成します。
・・・それでも実行してもダメでした。

buildファイルなら実行可能なんですが、、、
GAEで見たことあるような、、、

おー!Enhancerですね。


「org.datanucleus.enhancer.DataNucleusEnhancer」を
「src\java\org\datanucleus\samples\jdo\tutorial\package.jdo」を引数にして
実行する必要があります。


・・・これで実行できますがこれは何の為にやってるんだか。。。

ひとまずこれで実行可能になります。
さぁ開発開始だぁー!

2009年5月7日木曜日

JDO関連のデプロイ後の遅延



GAEのアプリケーション管理画面の
「DataStore」→「Indexes」を見ると画像のような画面が出ます。
ここの「Serving」が「Building」ってなってると
パーシスタントクラスの関連を構築中だって意味になります。

こないだやった時は半日(途中睡眠があるのでもう少し早いかも)かかりました。
デプロイした後試せるのは結構時間がかかります。

http://code.google.com/intl/ja/appengine/kb/general.html#indexes

ここにいろいろ書いてあります。

GAEにデータを保存


すでにこの設定などは古くなっている可能性があります。

Slim3の開発はこんなブログより正式ドキュメントが有効です。
Slim3サイト
非公式と言われていますが充実した日本語サイトもあります。
Slim3日本語サイト



さて、Slim3を手に入れ、Strutsでアップロードを可能にした私は
ついにデータを保存するということに挑戦。
っていうか簡単なんですけどね。

単純にBlobデータを使いました。
ファイルをアップロードして
FormFileからInputStreamを取り出して
ByteArrayOutputStreamを利用して


ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream stream = aFile.getInputStream();
byte[] buffer = new byte[8192];
//終了まで読み込み続ける
while (stream.read(buffer) != -1) {
baos.write(buffer);
}
Blob imageBlob = new Blob(baos.toByteArray());


[com.google.appengine.api.datastore.Blob]ですね。
を生成します。

これをJDOで永続化してBigTableに保存します。

でそれを検索して


Image image = getPersistentImage(Long.valueOf(shopId),Long.valueOf(imageId));
Blob blob = image.getImage();
rtnByte = blob.getBytes();


※ImageってのはBlobを保存したパーシスタントクラスです。

取得します。
これをストリームに描きだしたりすると画像が出ます!

Blobを見た時からこれをやりたかったんですけどね。
Slim3の力を借りてここまでたどり着きました!

2009年4月29日水曜日

JDOの1対多

結構はまりました。
ここにあるようにバグにより
親のオブジェクト、子のオブジェクトのキーはKeyにする必要があるようです。
※子は仕様にも記述してありますけどね。

まず親側のクラスを


class Shop {

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

@Persistent(mappedBy = "shop")
private List<Image> imageList;

・・・getter,setterは未記述

}


と記述します。
Keyは通常のIDENTITY(Longで自動設定した場合)と同一で、特に登録などの際に
設定する必要はありません。

そして子のクラスを


class Image {

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

@Persistent
private Shop shop;
・・・getter,setterは未記述
}


というように記述します。

で登録は以下のようにします。


PersistenceManager pm = SessionManager.get().getPersistenceManager();
Transaction tx = null;
try {
String id = mogForm.getId();
Long lngId = Long.valueOf(id);

tx = pm.currentTransaction();
tx.begin();

log.warning(id);
Shop oldShop = pm.getObjectById(Shop.class, lngId);

List<Image> imageList = oldShop.getImageList();
if ( imageList == null ) {
imageList = new ArrayList<Image>();
}

imageList.add(image);
image.setShop(oldShop);

tx.commit();
} finally {
if ( tx != null && tx.isActive() ) {
tx.rollback();
}
pm.close();
}


Shopを検索してImageListを取得して
そこに追加を行ってコミットをかけています。
トランザクションをかけてあげないとエラーになります。
このクラスを登録するというより、親に追加して更新しているイメージです。
※子の追加でも可能かは検証してません。

扱っているShopクラスのidの値は
KeyクラスのgetId()により取得したLong値(Stringで使ってる)になります。
そのまま使用すると"Shop(4)"みたいな値になって検索の際にエラーになります。


・・・あぁ。。。やっとこさ関連が実装できた!

2009年4月26日日曜日

JDOで削除

JDOのオブジェクトを削除します。


PersistenceManager pm = SessionManager.get().getPersistenceManager();
try {
Shop oldShop = pm.getObjectById(Shop.class, Long.valueOf(id));
pm.deletePersistent(oldShop);
} finally {
pm.close();
}


更新時と同じくgetObjectById()でオブジェクトを取得して
deletePersistent()で削除を行います。

簡単ですね。

JDOで更新

JDOで更新を行います。



String id = mogForm.getId();
PersistenceManager pm = SessionManager.get().getPersistenceManager();
try {
Shop oldShop = pm.getObjectById(Shop.class, Long.valueOf(id));

String name = mogForm.getName();
String detail = mogForm.getDetail();
String url = mogForm.getUrl();

oldShop.setName(name);
oldShop.setDetail(detail);
oldShop.setUrl(url);
oldShop.setEditor(user);
oldShop.setEditDate(new Date());

} finally {
pm.close();
}


getObjectById()を利用して検索を行います。

取得してきたオブジェクトを更新してclose()するだけです。
簡単ですね。

Keyを利用した検索もあるみたい。※それは後日

2009年4月25日土曜日

GAEでオブジェクト比較

GAEでログインしたユーザだけのデータを表示したい。

そう思い立ちました。。。がっ!
JDOのオブジェクト比較にSQLってどうするんだろ?
と思い立ちしばし、、、

でできました。


UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();

PersistenceManager pm = SessionManager.get().getPersistenceManager();
Query query = pm.newQuery(Shop.class);

query.setFilter("creator == crrentUser");
query.declareParameters("com.google.appengine.api.users.User crrentUser");

try {
List<Shop> shopList = (List<Shop>)query.execute(user);
for ( Shop oldShop : shopList ) {
Shop newShop = new Shop(oldShop);
shopForm.addShop(newShop);
}
} finally {
query.closeAll();
}


Query::setFilter()でSQLイメージを作って
Query::declareParameters()で型を宣言します。
Query::execute()で比較するオブジェクトを設定しておきます。

これでOKですね!
ログインしたユーザのみの機能もこれでOKですね。

ひとまずSingleton!

さぁ、ひとまず、GoogleAppEngineの
データベースを使うにはSingletonパターンを勉強しましょう!

データベースのリソースを極力使わないのが
システム設計の基本なんですが
まず最初に行わなければいけないのは


package bz.ziro.test.jdo;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public class SessionManager {
private static final PersistenceManagerFactory pmfInstance =
JDOHelper.getPersistenceManagerFactory("transactions-optional");
public static PersistenceManagerFactory get() {
return pmfInstance;
}
}




です。
こうすることで


PersistenceManagerFactory pmf = SessionManager.get();


使うことができます。



いやぁ。。。JDOを真面目に勉強してたらびっくりしました。
JDOってJavaの規格なんですね。。。
それでjarを拾いにいったらApacheで
そのjarだけでは実装できませんって言われて
やばっ!って思ってたら
googleもdatanucleusっていうやつを使ってるんですね。
※ってよく見たらreferenceにも書いてありました!!

ん~やっぱGoogleさんの考えてることはわからん、、、

2009年4月21日火曜日

JDOで保存と検索

さぁGAEでデータベースを取り扱ってみましょう!

JDOを利用して行うことができるようです。
JDOは。。。平たく言うとオブジェクトを保存できる仕組みとでもいいましょうか。。。

下準備は「src/META-INF」に
jdoconfig.xmlを準備する必要があります。

これはeclipseのプラグインでプロジェクトを作成した場合に
勝手にできあがってるみたいです。


それとパーシスタントクラスを準備する必要があります。
このクラスはPOJOと呼ばれる単純なクラスを準備します。


import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import com.google.appengine.api.users.User;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Project {

@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
@PrimaryKey
private Long id;
@Persistent
private String name;
@Persistent
private String detail;
@Persistent
private User creator;
@Persistent
private User editor;

・・・・(getter と setterも準備)
}


残したいデータを準備するのですが
大事なのは「@~」っていう記述方法です。
アノテーションと呼ばれるコメントにより、特性を決める技術です。


@PersistenceCapable(identityType = IdentityType.APPLICATION)
でこのアプリケーションで一意であるデータということ

@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
保存対象でありIDENTITY(一意)であるということ

@PrimaryKey
プライマリーであるということ

@Persistent
保存対象である

ということを意味します。


さぁこれで保存する準備はできました。
画面を作成して保存して一覧に出すようにしてみましょう!

まず実行するJSPを準備


<form name="testForm" action="./JDOServlet" method="post">
<input type="text" name="name">
<textarea name="detail"></textarea>
<input type="submit">
</form>


まぁ普通のHTMLファイルでもOKですね。
でJDOServletをweb.xmlに記述します。


<servlet>
<servlet-name>JDOTestServlet</servlet-name>
<servlet-class>bz.ziro.test.servlet.JDOServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>JDOTestServlet</servlet-name>
<url-pattern>/secure/JDOServlet</url-pattern>
</servlet-mapping>

※servletタグとservlet-mappigタグは順番に並べてください。

で少し長いですがサーブレットは以下のようになります。
※折りたたんであるので広げてください。


public class JDOServlet extends HttpServlet {

/**
*
*/
private static final long serialVersionUID = 1234131818439520488L;

private static PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional");
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {

UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();

String name = req.getParameter("name");
String detail = req.getParameter("detail");

Project project = new Project();
project.setName(name);
project.setDetail(detail);
project.setCreator(user);

PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
pm.makePersistent(project);
} finally {
pm.flush();
}

Query query = pm.newQuery(Project.class);
try {
List<Project> projectList = (List<Project>)query.execute();
PrintWriter writer = resp.getWriter();
resp.setContentType("text/html");
if (projectList.iterator().hasNext()){
writer.println("<table>");
writer.println("<tr>");
writer.println("<td>id</td>");
writer.println("<td>name</td>");
writer.println("<td>detail</td>");
writer.println("</tr>");
for ( Project pro : projectList ) {
writer.println("<tr>");
writer.println("<td>" + pro.getId() + "</td>");
writer.println("<td>" + pro.getName() + "</td>");
writer.println("<td>" + pro.getDetail() + "</td>");
writer.println("</tr>");
}
writer.println("</table>");
} else {
}
} finally {
query.closeAll();
}
}
}


まずProjectのオブジェクトを準備しています。
でPersistenceManagerでmakeします。
これがinsert行為になります。

まだpmは使うのでflushだけして
Queryクラスで一覧を取得してきます。
このQueryクラスでwhere文やlimit文、Order文などを記述します。

でPrintWriterでHTMLに記述をしています。


さぁベタな文法ですがいかがだったでしょうか?
※PMFなどをSingletonパターンを利用しないと
 もう一回インスタンスを取得するとExceptionになります。

http://gae.ziro.bz/secure/test.jsp

でお試しできます。
※ごめんなさい。Creatorユーザでユーザを保存していますので
 試すとアカウントの情報が残ります。
 間違っても何かに使ったりしませんのでお試しください。

※ごめんなさい。現在はStrutsによる実装になってしまいました。

・・・さてトランザクションとかもやらんとな。。。

2009年4月19日日曜日

GAEでJDO

すっごい!!!JDOまで行っちゃうなんて!!!

PersistenceManagerFactoryをSingletonで作成して


・・・ってこれをパッケージングして
自分のクラス構造してたらQueryがあった。。。スゴイ。



うん。すごい。
またJDOについては書きます!