GoogleAppEngine+Slim3のファイルアップロードをScalaで書き直す
【変更前】元ネタは、 http://slim3demo.appspot.com/upload/;jsessionid=dBGn20s5q7i28ZwKBGOrFw
package slim3.demo.service; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.slim3.controller.upload.FileItem; import org.slim3.datastore.Datastore; import org.slim3.util.ByteUtil; import slim3.demo.meta.UploadedDataFragmentMeta; import slim3.demo.meta.UploadedDataMeta; import slim3.demo.model.UploadedData; import slim3.demo.model.UploadedDataFragment; import com.google.appengine.api.datastore.Key; import com.google.appengine.api.datastore.Transaction; public class UploadService { //1つのデータの最大値は1MなのでFragmentのサイズを900000に設定 private static final int FRAGMENT_SIZE = 900000; //DataとDataFragmentそれぞれのエンティティへのマッピングクラスを取得 private UploadedDataMeta d = UploadedDataMeta.get(); private UploadedDataFragmentMeta f = UploadedDataFragmentMeta.get(); //アップロードしたDataの一覧を取得 public List<UploadedData> getDataList() { return Datastore.query(d).asList(); } //DataをDataFragmentに分割しながらアップロード public UploadedData upload(FileItem formFile) { //ファイルが空だったら、nullを返す if (formFile == null) { return null; } List<Object> models = new ArrayList<Object>(); UploadedData data = new UploadedData(); //datastoreに保存するデータの models.add(data); //各種Dataのパラメータ指定 data.setKey(Datastore.allocateId(d)); data.setFileName(formFile.getShortFileName()); data.setLength(formFile.getData().length); //formFileをバイト化 byte[] bytes = formFile.getData(); //bytesをFragmentのサイズに分割 byte[][] bytesArray = ByteUtil.split(bytes, FRAGMENT_SIZE); //byteArrayの長さ分のKeyを生成 Iterator<Key> keys = Datastore .allocateIds(data.getKey(), f, bytesArray.length) .iterator(); for (int i = 0; i < bytesArray.length; i++) { //FragmentData用のbyte[] byte[] fragmentData = bytesArray[i]; //インスタンス生成しmodelsに格納 UploadedDataFragment fragment = new UploadedDataFragment(); models.add(fragment); //Fragmentに各種プロパティを設定 fragment.setKey(keys.next()); fragment.setBytes(fragmentData); fragment.setIndex(i); fragment.getUploadDataRef().setModel(data); } //トランザクション開始 Transaction tx = Datastore.beginTransaction(); //Data,Fragmentを含むモデルオブジェクトの一覧をdatastoreに追加していく for (Object model : models) { Datastore.put(tx, model); } //トランザクション終了 tx.commit(); //dataのオブジェクトを返す return data; } //Dataの情報を取得 public UploadedData getData(Key key, Long version) { return Datastore.get(d, key, version); } //取得したDataの情報からFragmentをかき集めて修復 public byte[] getBytes(UploadedData uploadedData) { //Dataが空だった場合にNullPointExceptionを投げる if (uploadedData == null) { throw new NullPointerException( "The uploadedData parameter must not be null."); } //DataからFragmentの一覧を取得 List<UploadedDataFragment> fragmentList = uploadedData.getFragmentListRef().getModelList(); //各々のFragmentからbyteを取得してbyte[][]に格納 byte[][] bytesArray = new byte[fragmentList.size()][0]; for (int i = 0; i < fragmentList.size(); i++) { bytesArray[i] = fragmentList.get(i).getBytes(); } //bite[][]をjoinしてリターン return ByteUtil.join(bytesArray); } //削除するDataのKeyを指定してDataとFragmentの両方を削除 public void delete(Key key) { Transaction tx = Datastore.beginTransaction(); //削除するエンティティのKey一覧 List<Key> keys = new ArrayList<Key>(); //削除するエンティティ一覧にDataとFragmentのKeyを追加 keys.add(key); keys.addAll(Datastore.query(f, key).asKeyList()); //トランザクション内で削除とトランザクション完了 Datastore.delete(tx, keys); Datastore.commit(tx); } }
【変更後】
package slim3.demo.service; import java.util.ArrayList import java.util.Iterator import java.util.List import org.slim3.controller.upload.FileItem import org.slim3.datastore.Datastore import org.slim3.util.ByteUtil import slim3.demo.meta.UploadedDataFragmentMeta import slim3.demo.meta.UploadedDataMeta import slim3.demo.model.UploadedData import slim3.demo.model.UploadedDataFragment import com.google.appengine.api.datastore.Key import com.google.appengine.api.datastore.Transaction import scala.collection.JavaConversions._ class UploadService( //DataとDataFragmentそれぞれのエンティティへのマッピングクラスを取得 var d: UploadedDataMeta = UploadedDataMeta.get(), var f: UploadedDataFragmentMeta = UploadedDataFragmentMeta.get() ){ object UploadService { //1つのデータの最大値は1MなのでFragmentのサイズを900000に設定 val FRAGMENT_SIZE: Int = 900000; } //アップロードしたDataの一覧を取得 def getDataList(): java.util.List[UploadedData] = { Datastore.query(d).asList(); } //DataをDataFragmentに分割しながらアップロード def upload( formFile: FileItem ): UploadedData = formFile match { //★caseにしてみた case null => null case _ => { val models: List[Object] = Nil val data: UploadedData = new UploadedData() //datastoreに保存するデータの models.add(data); //☆この辺のオブジェクトのパラメータを指定してくとこをシンプルにする方法ない? data.setKey(Datastore.allocateId(d)) data.setFileName(formFile.getShortFileName()) data.setLength(formFile.getData().length) //Fragmentのサイズに分割 val bytesArray: Array[Array[Byte]] = ByteUtil.split(formFile.getData, UploadService.FRAGMENT_SIZE); //Key一覧を生成 val keys: Iterator[Key] = Datastore.allocateIds(data.getKey(), f, bytesArray.length).iterator(); for { i <- 0 to bytesArray.length - 1 } { //FragmentData用のbyte[] var fragmentData = bytesArray(i) //インスタンス生成しmodelsに格納 var fragment: UploadedDataFragment = new UploadedDataFragment() models.add(fragment) //★この辺のオブジェクトのパラメータを指定してくとこをシンプルにする方法ない? fragment.setKey(keys.next()) fragment.setBytes(fragmentData) fragment.setIndex(i) fragment.getUploadDataRef().setModel(data) } //トランザクション開始 val tx: Transaction = Datastore.beginTransaction() //★modelsのmodelを全部datastoreに追加 models.map( model => Datastore.put(tx, model) ) //トランザクション終了 tx.commit() //dataのオブジェクトを返す data } } //Dataの情報を取得 def getData(key: Key, version: Long): UploadedData = { Datastore.get(d, key, version) } //取得したDataの情報からFragmentをかき集めて修復 def getBytes(uploadedData: UploadedData): Array[Byte] = uploadedData match { //☆ケースにしてみた case null => throw new NullPointerException( "The uploadedData parameter must not be null." ) //★引数のフラグメントをmapで各々バイトに変換してArrayに格納,Arrayを最後にjoin case _ => ByteUtil.join(uploadedData.getFragmentListRef().getModelList().map( item => item.getBytes() ).toArray ) } //削除するDataのKeyを指定してDataとFragmentの両方を削除 def delete(key: Key): Unit = { val tx: Transaction = Datastore.beginTransaction(); //削除するエンティティのKey一覧 val keys: List[Key] = Nil //削除するエンティティ一覧にDataとFragmentのKeyを追加 keys.add(key); //★全部追加するメソッドとか元々ある keys.addAll(Datastore.query(f, key).asKeyList()); //トランザクション内で削除とトランザクション完了 Datastore.delete(tx, keys); Datastore.commit(tx); } }