#! readMe.txt
#nameJp# Google App Engine用メンテナンスサンプルファイル			ver #ver#  #date#

このzipファイルに格納されているファイルはGoogle App Engine上で動作する
#nameJp#メンテナンスの実行に必要なソースコードなどの各種サンプルファイルです。

このサンプルはJava6以上で動作可能です。

  以下に格納されているファイルの詳細を記します。

  【ファイル詳細】
   1.readMe.txt                 このファイル
   2.web.xml                    サンプルweb定義ファイル
   3.GaeDaoBase.java            GAEデータストア用の共通クラスのソースコード
   4.RecordAction.java          レコード処理共通インターフェースのソースコード
   5.RecordSearch.java          レコード検索共通インターフェースのソースコード
   6.#mntName#.java          	#nameJp#用 Value Objectのソースコード
   7.#mntName#Dao.java       	#nameJp#用データベースアクセス用のjavaソースコード（create table）
   8.#mntName#Insert.html    	#nameJp#用新規挿入画面のHTMLファイル
   9.#mntName#Insert.java    	#nameJp#用新規挿入画面のjavaソースコード
  10.#mntName#List.html      	#nameJp#用検索一覧画面のHTMLファイル
  11.#mntName#List.java      	#nameJp#用検索一覧画面のjavaソースコード
  12.#mntName#Reference.html 	#nameJp#用照会画面のHTMLファイル
  13.#mntName#Reference.java 	#nameJp#用照会画面のjavaソースコード
  14.#mntName#Update.html    	#nameJp#用修正画面のHTMLファイル
  15.#mntName#Update.java    	#nameJp#用修正画面のjavaソースコード
  16.#mntName#StartApp.java  	#nameJp#用WEB画面エントリーポイントjavaソースコード
  17.prototype.js               オープンソースのJavaScriptのライブラリ（ライセンスはこのドキュメントの最後に掲載）
  18.pirka.js                   オープンソースのJavaScriptのフレームワーク
  19.pirkaiop.css               HTMLファイルが使用するcssファイル
  20.log4j-1.2.16.jar           オープンソースのログ出力ライブラリ
  21.log4j.properties           ログ出力の設定ファイル
  22.readMeLog.txt              ログ出力の設定の説明及びライセンスが記載されているファイル


 【サンプル実行方法】
  サンプルの実行はGAE開発環境、WEB画面フレームワークのpirka.jarが必要となります。

  例としてEclipse、Google Plugin for Eclipseを使用しGAE開発環境でのサンプルの実行方法を
  以下に記します。
  GAE本番環境へのデプロィ及び実行はGoogleへの登録が必要となります。
  詳細はGoogleのホームページを参照してください。

  1.Eclipseを起動しWeb Applicationプロジェクト(GAE)を作成します。
    この時パッケージは#package#を設定します。

  2.作成したプロジェクトのwar/WEB-INF/libフォルダーにpirka.jar及びlog4j-1.2.16.jarを
      コピーし、プロジェクトのビルド・パスに追加します。

  3.作成したプロジェクトのWEB-INF/src/#package#に、Javaソースコード（.java）、
    HTMLファイル(.html)をコピーします。
    
  4.作成したプロジェクトのWEB-INF/srcにlog4j.propertiesをコピーします。
    ログの出力形態を変更したい時はreadMeLog.txtを参照してください。

  5.作成したプロジェクトのwar/WEB-INFにweb.xmlをコピーします。

  6.作成したプロジェクトのwarの下にフォルダー（名前をjs）を作成し、prototype.jsとpirka.jsを
    そのフォルダーに格納します。

  7.作成したプロジェクトのwarの下にフォルダー（名前をcss）を作成し、pirkaiop.cssを
    そのフォルダーに格納します。

  8.作成したプロジェクトのwar/WEB-INF/appengine-web.xmlを以下のように編集します。
    <version>1</version>の行の下に以下の行を追加します。
    <sessions-enabled>true</sessions-enabled>

  9.作成したプロジェクトのwar/WEB-INF/appengine-web.xml を以下の様に編集します。

      --- 変更前 -------------------------------------------------------------------------------
      <system-properties>
      <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
      </system-properties>
      -------------------------------------------------------------------------------------------

      --- 変更後 ---------------------------------------------------------------------------------
      <system-properties>
      <property name="java.util.logging.config.file" value="WEB-INF/classes/log4j.properties"/>
      </system-properties>
      -------------------------------------------------------------------------------------------

    これにより、appengine.google.comのlogsに出力されます。

  9.実行の構成に存在する作成したプロジェクト名と同名の項目を選択し起動します。

  10.IE等のブラウザでURL『http://localhost:8888/start』を開くと
    #nameJp#マスターメンテス画面が表示されます。
    （ポート番号はGoogle Plugin for Eclipseのバージョン等で変更される場合があります）


--- prototype.jsのライセンス ----------------------------------------------------------------------

Prototype is freely distributable under the terms of an MIT-style license.
For details, see the Prototype web site: http://www.prototypejs.org/

Copyright (c) 2005-2008 Sam Stephenson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------------------------------------------------
#!

#! startApp
package #package#;

import org.apache.log4j.Logger;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jp.oarts.pirka.core.app.EntryPoint;
import jp.oarts.pirka.core.kernel.TempFileManager;
import jp.oarts.pirka.core.util.converter.ReqCharacterConverter;
import jp.oarts.pirka.core.win.PirkaWindow;

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

/**
 * GAE用のエントリーポイント
 *
 */
@SuppressWarnings("serial")
public class #mntName#StartApp extends EntryPoint {

	// GAEのデフォルトのキャラクタセット
	public final static String DEFAULT_CHARSET = "UTF-8";

	// GAE用のリクエストのキャラクタコンバータ
	private static final ReqCharacterConverter reqCharacterConverter = new ReqCharacterConverterGAE();

	// ロガー
	private static Logger logger = Logger.getLogger(#mntName#StartApp.class);

	@Override
	public void serviceMain(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		// 　認証されていなければログイン画面を呼ぶ
		UserService userService = UserServiceFactory.getUserService();
		User user = UserServiceFactory.getUserService().getCurrentUser();
		if (user == null) {
			res.sendRedirect(userService.createLoginURL(req.getRequestURI()));
		} else {
			super.serviceMain(req, res);
		}
	}

	/**
	 * 初画面の取得
	 *
	 * @param パラメータ
	 * @return 初画面オブジェクト
	 */
	@Override
	protected PirkaWindow getInitWindow(Map<String, String[]> reqMap) {
		User user = UserServiceFactory.getUserService().getCurrentUser();
		logger.info("アプリケーション開始  user-ID = " + user.getEmail() + " client IP-Address = " + getHttpServletRequest().getRemoteAddr());
		return new #mntName#List();
	}

	/**
	 * ブラウザーに送信するHTMLイメージのキャラクターセットを取得します
	 *
	 * @return キャラクターセット名
	 */
	@Override
	public String getHtmlStringCharset() {
		return DEFAULT_CHARSET;
	}

	/**
	 * ブラウザーに送信するレスポンスヘッダのキャラクタセットを取得します
	 *
	 * @return キャラクターセット名
	 */
	@Override
	public String getResponsHeaderCharset() {
		return DEFAULT_CHARSET;
	}

	/**
	 * リクエストキャラクタの変換オブジェクト取得<BR>
	 * GAE用のリクエストキャラクタの変換オブジェクトを返します
	 *
	 * @return リクエストキャラクタの変換オブジェクト
	 */
	@Override
	public ReqCharacterConverter getReqCharacterConverter() {
		return reqCharacterConverter;
	}

	/**
	 * テンポラリファイルマネージャーの取得<br>
	 * GAE用のテンポラリファイルマネージャーのオブジェクトを返します
	 *
	 * @return テンポラリファイルマネージャー
	 */
	@Override
	public TempFileManager getTempFileManager() {
		return MemTempFileManager.getInstance();
	}

	/**
	 * GAE用のテンポラリファイルマネージャークラス<br>
	 * アップロードされたファイルをメモリー上で管理します
	 */
	public static class MemTempFileManager implements TempFileManager {

		// 唯一の自クラスのオブジェクト
		private static final MemTempFileManager obj = new MemTempFileManager();

		// ファイルイメージを保持するマップ
		private HashMap<Long, byte[]> tempMap;

		/**
		 * new禁止のコンストラクタ
		 */
		private MemTempFileManager() {
			tempMap = new HashMap<Long, byte[]>();
		}

		/**
		 * 自オブジェクトを取得
		 *
		 * @return 唯一の自クラスのオブジェクト
		 */
		public static MemTempFileManager getInstance() {
			return obj;
		}

		@Override
		public OutputStream getOutputStream(long fileId) throws IOException {
			return new MemOutputStream(fileId);
		}

		@Override
		public InputStream getInputStream(long fileId) throws IOException {
			synchronized (tempMap) {
				return new ByteArrayInputStream(tempMap.get(fileId));
			}
		}

		@Override
		public void delete(long fileId) throws IOException {
			synchronized (tempMap) {
				tempMap.remove(fileId);
			}
		}

		/**
		 * GAE用のテンポラリファイルマネージャー用のOutputStream
		 */
		public class MemOutputStream extends ByteArrayOutputStream {

			// ファイルID
			long fileId;

			/**
			 * コンストラクタ
			 *
			 * @param fileId
			 *            ファイルID
			 */
			public MemOutputStream(long fileId) {
				this.fileId = fileId;
			}

			@Override
			public void close() throws IOException {
				super.close();
				synchronized (tempMap) {
					tempMap.put(fileId, toByteArray());
				}
			}
		}
	}

	/**
	 * GAE用のリクエストのキャラクタコンバータクラス
	 */
	public static class ReqCharacterConverterGAE implements ReqCharacterConverter {

		// シリアルバージョンID
		private static final long serialVersionUID = 1L;

		// エンコード・キャラクタセット
		private String encodeCharset = "UTF-8";

		@Override
		public String convertKanji(String arg0) {
			return arg0;
		}

		@Override
		public String convertKanji(byte[] arg0) {
			try {
				return new String(arg0, encodeCharset);
			} catch (UnsupportedEncodingException e) {
				throw new RuntimeException(e);
			}
		}
	}
}
#!

#! web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
	version="2.4">

	<servlet>
		<servlet-name>StartApp</servlet-name>
		<servlet-class>#packageMntName#StartApp</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>StartApp</servlet-name>
		<url-pattern>/start</url-pattern>
	</servlet-mapping>
</web-app>
#!

