いまいちだ。だめだ。

slim3でgwtやってます。とりあえずは動かしてみよう!ということで、やってます。まだできてませんがメモっときます。

できないだろうとは思いつつ (← DataStoreについてまだよく分かってません) Kindを@NotPersistentでプロパティに持って、Daoでフェッチするときに、Kind自体を検索して、そのプロパティにsetした状態のListを返せれば、JDOHelperをmodelで使う必要ないよなと思った。


何がやりたいかというと、ここでやったものをslim3gwtで実現することです。非所有の関連をもったEntity二つをManageする。
画面はこんな感じ


昨日エラーになった、JDOHelperをクライアント側で使っている部分を削除。というかslim3Gwtのモデルはクライアントとサーバで共用なのでCatを変更するんです。したんです。以下のようなコード群


Cat_slim3_gwt.html

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Cat Manager</title>
<link type="text/css" rel="stylesheet" href="Cat_slim3_gwt.css">
<script type="text/javascript" language="javascript" src="cat_slim3_gwt/cat_slim3_gwt.nocache.js"></script>
</head>

<body>
<div class="head">CatManager</div>


<div class="flame">
		<div id="catcontainer" class="outer">
			<div class="side_title">猫登録</DIV>
		</div>
			<BR class="clears">

		<div id="kindcontainer" class="outer_right">
			<div class="side_title">種類登録</DIV>
		</div>
			<BR class="clears">
</div>
<!-- OPTIONAL: include this if you want history support -->
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1'
	style="position: absolute; width: 0; height: 0; border: 0"></iframe>

</body>
</html>

Cat_slim3_gwt.java

package kijitoraneko.demo.client;

import kijitoraneko.demo.client.service.CatService;
import kijitoraneko.demo.client.service.CatServiceAsync;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.RootPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Cat_slim3_gwt implements EntryPoint {

	private final CatServiceAsync service = GWT.create(CatService.class);

	public void onModuleLoad() {
		CatView cv = new CatView(service);
		KindView kv = new KindView(service);

		RootPanel.get("catcontainer").add(cv);
		RootPanel.get("kindcontainer").add(kv);

	}
}


CatView.java

package kijitoraneko.demo.client;

import java.util.List;

import kijitoraneko.demo.client.service.CatServiceAsync;
import kijitoraneko.demo.shared.model.Cat;
import kijitoraneko.demo.shared.model.Kind;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

public class CatView extends Composite{

	private final CatServiceAsync catservice;

	final TextBox insertTextBox = new TextBox();
	final ListBox listBox = new ListBox();
	final Button insertButton = new Button("お猫登録");
	final Hyperlink catsearchlink = new Hyperlink("All猫検索", "");
	final Button closeCatsButton = new Button("閉じる");
	final Button closeInsertButton = new Button("閉じる");
	final DialogBox dialogBox = new DialogBox();
	final VerticalPanel dialogVPanel = new VerticalPanel();

	public CatView(CatServiceAsync proxy) {
		this.catservice = proxy;
		VerticalPanel vpanel = new VerticalPanel();
		HorizontalPanel hpanel = new HorizontalPanel();
		HorizontalPanel hpanel2 = new HorizontalPanel();

		hpanel.add(insertTextBox);
		hpanel.add(listBox);
		hpanel.add(insertButton);
		hpanel2.add(catsearchlink);
		vpanel.add(hpanel);
		vpanel.add(hpanel2);
		dialogVPanel.setStyleName("dialogVPanel");

		catsearchlink.addClickHandler(new SearchCatsHandler());
		insertButton.addClickHandler(new InsertCatsHandler());

		initKindListBox();
		closeButtonInit();
		initWidget(vpanel);
	}

	private void closeButtonInit(){
		closeCatsButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dialogVPanel.clear();
				dialogBox.hide();
			}
		});

		closeInsertButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dialogVPanel.clear();
				dialogBox.hide();
				insertButton.setEnabled(true);
			}
		});
	}

	private void initKindListBox() {
		catservice.searchAllKind(new AsyncCallback<List<Kind>>() {
			@Override
			public void onFailure(Throwable caught) {
			}
			@Override
			public void onSuccess(List<Kind> result) {
				for (Kind kind : result) {
					listBox.addItem(kind.getName(), kind.getKey());
				}
			}
		});
	}


	class InsertCatsHandler implements ClickHandler {

		public void onClick(ClickEvent event) {
			String kindkey = listBox.getValue(listBox.getSelectedIndex());
			insertCat(kindkey);
		}

		private void insertCat(String kindkey) {
			String catname = insertTextBox.getText();
			Cat cat = new Cat();
			cat.setName(catname);
			catservice.insertCat(cat, kindkey, new AsyncCallback<Cat>() {
				public void onFailure(Throwable caught) {
				}

				@Override
				public void onSuccess(Cat result) {
					Label labeltext = new Label();
					labeltext.setText("登録しました");
					Label label = new Label();
					label.setText(result.getName());
					dialogVPanel.add(labeltext);
					dialogVPanel.add(label);
					dialogVPanel.add(closeCatsButton);
					dialogBox.setWidget(dialogVPanel);
					dialogBox.center();
					dialogBox.show();
				}
			});
		}
	}

	class SearchCatsHandler implements ClickHandler {

		public void onClick(ClickEvent event) {
			searchCats();
		}

		private void searchCats() {
			catservice.searchAllCat(new AsyncCallback<List<Cat>>() {
				public void onFailure(Throwable caught) {
				}

				@Override
				public void onSuccess(List<Cat> result) {
					for (Cat cat : result) {
						Label name = new Label();
						name.setText(cat.getName());
						Label kind = new Label();
						name.setText(cat.getNotpersistkind().getName());
						final HorizontalPanel dialogHPanel = new HorizontalPanel();
						dialogHPanel.add(name);
						dialogHPanel.add(kind);
						dialogVPanel.add(dialogHPanel);
					}
					dialogVPanel.add(closeCatsButton);
					dialogBox.setWidget(dialogVPanel);
					dialogBox.center();
					dialogBox.show();
				}
			});
		}
	}



}


KindView.java

package kijitoraneko.demo.client;

import java.util.List;

import kijitoraneko.demo.client.service.CatServiceAsync;
import kijitoraneko.demo.shared.model.Kind;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

public class KindView extends Composite{

	private final CatServiceAsync catService;

	final Button kindInsertButton = new Button("種類登録");
	final Button kindSearchButton = new Button("全検索");
	final Button searchByStringButton = new Button("前方検索");
	final Button closekindInsertButton = new Button("閉じる");
	final Button closekindSearchButton = new Button("閉じる");
	final Button closesearchByStringButton = new Button("閉じる");
	final TextBox insertField = new TextBox();
	final TextBox frontSearchField = new TextBox();
	final DialogBox dialogBox = new DialogBox();
	final VerticalPanel dialogVPanel = new VerticalPanel();

	public KindView(CatServiceAsync proxy) {
		this.catService = proxy;

		kindInsertButton.addStyleName("sendButton");
		kindSearchButton.addStyleName("sendButton");
		searchByStringButton.addStyleName("sendButton");

		VerticalPanel vpanel = new VerticalPanel();

		HorizontalPanel hp1 = new HorizontalPanel();
		hp1.add(insertField);
		hp1.add(kindInsertButton);
		vpanel.add(hp1);

		HorizontalPanel hp2 = new HorizontalPanel();
		hp2.add(kindSearchButton);
		vpanel.add(hp2);

		HorizontalPanel hp3 = new HorizontalPanel();
		hp3.add(frontSearchField);
		hp3.add(searchByStringButton);
		vpanel.add(hp3);

		dialogVPanel.setStyleName("dialogVPanel");

		kindInsertButton.addClickHandler(new InsertKindHandler());
		kindSearchButton.addClickHandler(new SearchKindHandler());
		searchByStringButton.addClickHandler(new SearchByStringHandler());

		closeButtonInit();
		initWidget(vpanel);
	}


	private void closeButtonInit(){
		closekindSearchButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dialogVPanel.clear();
				dialogBox.hide();
				kindSearchButton.setEnabled(true);
			}
		});

		closesearchByStringButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dialogVPanel.clear();
				dialogBox.hide();
				searchByStringButton.setEnabled(true);
			}
		});

		closekindInsertButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dialogVPanel.clear();
				dialogBox.hide();
				kindInsertButton.setEnabled(true);
			}
		});
	}

	class InsertKindHandler implements ClickHandler {

		public void onClick(ClickEvent event) {
			insertKind();
		}

		private void insertKind() {
			kindInsertButton.setEnabled(false);
			String textToServer = insertField.getText();
			Kind kind = new Kind();
			kind.setName(textToServer);
			catService.insertKind(kind, new AsyncCallback<Kind>() {
				public void onFailure(Throwable caught) {
				}

				public void onSuccess(Kind result) {
					Label labeltext = new Label();
					labeltext.setText("登録しました");
					Label label = new Label();
					label.setText(result.getName());
					dialogVPanel.add(labeltext);
					dialogVPanel.add(label);
					dialogVPanel.add(closekindInsertButton);
					dialogBox.setWidget(dialogVPanel);
					dialogBox.center();
					dialogBox.show();
				}
			});
		}
	}

	class SearchKindHandler implements ClickHandler {

		public void onClick(ClickEvent event) {
			searchAllKind();
		}

		private void searchAllKind() {
			kindSearchButton.setEnabled(false);
			catService.searchAllKind(new AsyncCallback<List<Kind>>() {
				public void onFailure(Throwable caught) {
				}

				public void onSuccess(List<Kind> result) {
					for (Kind kind : result) {
						Label label = new Label();
						label.setText(kind.getName());
						dialogVPanel.add(label);
					}
					dialogVPanel.add(closekindSearchButton);
					dialogBox.setWidget(dialogVPanel);
					dialogBox.center();
					dialogBox.show();
					kindSearchButton.setEnabled(true);
				}
			});
		}
	}

	class SearchByStringHandler implements ClickHandler {

		public void onClick(ClickEvent event) {
			searchByString();
		}

		private void searchByString() {
			String str = frontSearchField.getText();
			searchByStringButton.setEnabled(false);
			catService.searchKindByString(str, new AsyncCallback<List<Kind>>() {
				public void onFailure(Throwable caught) {
				}

				public void onSuccess(List<Kind> result) {
					for (Kind kind : result) {
						Label label = new Label();
						label.setText(kind.getName());
						dialogVPanel.add(label);
					}
					dialogVPanel.add(closekindSearchButton);
					dialogBox.setWidget(dialogVPanel);
					dialogBox.center();
					dialogBox.show();
					searchByStringButton.setEnabled(true);
				}
			});
		}
	}

}


CatService.java

package kijitoraneko.demo.client.service;

import java.util.List;

import kijitoraneko.demo.shared.model.Cat;
import kijitoraneko.demo.shared.model.Kind;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("service.s3gwt")
public interface CatService extends RemoteService {
	List<Kind> searchAllKind();
	List<Kind> searchKindByString(String str);
	List<Cat> searchAllCat();
	Cat insertCat(Cat cat, String kindKey);
	Kind insertKind(Kind kind);
}


CatServiceAsync.java

package kijitoraneko.demo.client.service;

import java.util.List;

import kijitoraneko.demo.shared.model.Cat;
import kijitoraneko.demo.shared.model.Kind;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface CatServiceAsync {

	void insertKind(Kind kind, AsyncCallback<Kind> callback);

	void searchAllKind(AsyncCallback<List<Kind>> callback);

	void searchKindByString(String str , AsyncCallback<List<Kind>> asyncCallback);

	void searchAllCat(AsyncCallback<List<Cat>> asyncCallback);

	void insertCat(Cat cat, String kindKey, AsyncCallback<Cat> callback);

}


CatServiceImpl.java

package kijitoraneko.demo.server.service;

import java.util.List;

import kijitoraneko.demo.client.service.CatService;
import kijitoraneko.demo.server.dao.CatDao;
import kijitoraneko.demo.server.dao.KindDao;
import kijitoraneko.demo.shared.model.Cat;
import kijitoraneko.demo.shared.model.Kind;

public class CatServiceImpl implements CatService {

	KindDao kinddao = new KindDao();
	CatDao catdao = new CatDao();

	@Override
	public Kind insertKind(Kind kind) {
		return kinddao.makePersistentInTx(kind);
	}

	@Override
	public List<Kind> searchAllKind() {
		return kinddao.findAll();
	}

	@Override
	public List<Kind> searchKindByString(String str) {
		return kinddao.findByString(str);
	}

	@Override
	public List<Cat> searchAllCat() {
		return catdao.findAll();
	}

	@Override
	public Cat insertCat(Cat cat , String kindKey) {
		Kind kind = kinddao.find(kindKey);
		cat.setKindKey(kind);
		return catdao.makePersistentInTx(cat);
	}

}


CatDao.java

package kijitoraneko.demo.server.dao;

import java.util.List;
import java.util.logging.Logger;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;

import kijitoraneko.demo.server.meta.CatMeta;
import kijitoraneko.demo.shared.model.Cat;
import kijitoraneko.demo.shared.model.Kind;

import org.slim3.jdo.GenericDao;
import org.slim3.jdo.SelectQuery;

public class CatDao extends GenericDao<Cat> {

	private static final CatMeta catmeta = new CatMeta();

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

	public CatDao() {
		super(Cat.class);
	}

	public CatDao(PersistenceManager pm) {
		super(Cat.class, pm);
	}

	@Override
	protected SelectQuery<Cat> from() {
		return new SelectQuery<Cat>(pm, catmeta.getModelClass());
	}

	public List<Cat> findAll() {
		List<Cat> catlist = from().getResultList();
		for (Cat cat : catlist) {
			cat.setNotpersistkind(JDOHelper.getPersistenceManager(cat)
					.getObjectById(Kind.class, cat.getKindKey()));
		}
		return catlist;
	}
}

KindDao.java

package kijitoraneko.demo.server.dao;

import java.util.List;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;

import kijitoraneko.demo.server.meta.KindMeta;
import kijitoraneko.demo.shared.model.Kind;

import org.slim3.jdo.GenericDao;
import org.slim3.jdo.SelectQuery;

public class KindDao extends GenericDao<Kind> {

    private static final KindMeta kindmeta = new KindMeta();

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

    public KindDao() {
        super(Kind.class);
    }

    public KindDao(PersistenceManager pm) {
        super(Kind.class, pm);
    }

    @Override
    protected SelectQuery<Kind> from() {
        return new SelectQuery<Kind>(pm, kindmeta.getModelClass());
    }

    public List<Kind> findByString(String searchKey) {
    	return from().where(kindmeta.name.startsWith(searchKey)).getResultList();
    }
}


Cat.java

package kijitoraneko.demo.shared.model;

import java.io.Serializable;

import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
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;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
@Version(strategy = VersionStrategy.VERSION_NUMBER, column = "version")
public class Cat implements Serializable {

	private static final long serialVersionUID = 1L;

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

	@Persistent
	private Long version = 1L;

	@Persistent
	private String name;

	@Persistent
	private String kindKey;

	@NotPersistent
	private Kind notpersistkind;

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public Long getVersion() {
		return version;
	}

	public String getName() {
		return name;
	}

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

	/*public Kind getKind() {
		if (kindKey == null) {
			return null;
		}
		return JDOHelper.getPersistenceManager(this).getObjectById(Kind.class,
				kindKey);
	}*/

	public void setKindKey(Kind kind) {
		if (kind == null) {
			kindKey = null;
		}
		kindKey = kind.getKey();

	}
	public String getKindKey() {
		return kindKey;
	}


	public Kind getNotpersistkind() {
		return notpersistkind;
	}
	public void setNotpersistkind(Kind notpersistkind) {
		this.notpersistkind = notpersistkind;
	}

}


Kind.java

package kijitoraneko.demo.shared.model;

import java.io.Serializable;

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;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
@Version(strategy = VersionStrategy.VERSION_NUMBER, column = "version")
public class Kind implements Serializable {

	private static final long serialVersionUID = 1L;

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

	@Persistent
	private Long version = 1L;

	@Persistent
	private String name;

	public String getName() {
		return name;
	}

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

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public Long getVersion() {
		return version;
	}
}

先ほどの画面でいうと、このコードでは『All猫検索』が実行できない。このリンクを押したとき (ちなみにリンクになってるのに意味はないですGWTを思い出すための練習です) CatDao#findAll()が呼ばれます。ここにいままでCatにあった部分を実装して、@NotPersistentのプロパティにKindをセットしてクライアントに戻せばいいのかと思った。


CatDaoではちゃんとKindを取得して、Catのプロパティにセットできた。


それで、slim3のGWTServiceServlet#invokeに処理が戻って、detachCopyAllされるとCatのnotpersistkindプロパティに設定されたKindはなくなってしまう。


根本的に理解してないんだろうな。親子とかグループとか状態とかの関係でしょうかね。その辺どうもわからないな。
またじっくりとドキュメントなど読みたいと思います。