javaの最近の情報



発売日2014年09月

著者/編集ケイ・S.ホーストマン, 柴田芳樹

出版社インプレス

ページ数250p

Java7で多くの機能追加が見送られたが、

Java8では、大きな機能追加となった。

特にラムダ式の追加により、プログラムの手法も大きく

変わってくる部分も今後は増えてくると思うので、

この辺りで最新のJavaの機能を押さえておきたい。

この書籍は、Javaの基本を理解している中級者程度以上を

対象としているため、余分な初心者向けの解説が無いため、

も使えると思う。

Java8に関する書籍は他にもいくつか発売されているが、

この書籍はJava8の新機能の解説がしっかりされているのは

もちろん、Java7での細かな機能追加についてもなされている点が

他の書籍との差となり、私はこの書籍を購入した。

この書籍でJava7、Java8での機能追加の内容をしっかり押さえておきたい。

目次

第1章 ラムダ式とは

第2章 ストリームAPIの使い方

第3章 ラムダ式を使ったプログラミング

第4章 JavaFXによるGUIプログラミング

第5章 日付と時刻の新たなAPI

第6章 並行処理の機能強化

第7章 Nashorn JavaScriptエンジンの活用

第8章 その他のJava 8機能を理解する

第9章 Java 7の機能を復習する

 

Google App Engine上でStruts2.2を動かす場合には、

Struts2を単独で動かす場合よりも、いくつかの設定変更や、

対応が必要になります。

 

今回は、GAE(Google App Engine)上で、Twitter連携アプリの

サンプルをStruts2.2で作成してみました。

Twitter連携には、Twitter4Jというライブラリを利用しています。

 

開発環境は、Eclipse3.4.2

Struts2.2.1

Google App Engineは、1.3.8

GWT(Google Web Toolkit)は、2.1.0

Twitter4J 2.1.6

を利用しています。

 

サンプルアプリは、ここを参照してください。

 パブリックタイムラインまたは、入力したIDのユーザタイムラインを表示します。

これらは全て認証の不要なAPIで作成可能になっています。

 

正常に稼働させるまでには、大きく2点障害がありました。

ローカル環境で、動作させるまでに必要な対応、

そしてデプロイ時のエラーを回避するための対応です。

 

1点目のローカル環境で動作させるまでの対応については、

先日のブログ記事で詳細を記述していますので、

そちらを参照してください。

※そしてさらに 追加でもう一点対応が必要になりました。

これは、<s:form action="sample"></s:from>のタグで、

フォーム入力の画面を作成する場合にGAEではエラーが発生するようです。

原因の詳細は不明なのですが、実行時に以下のエラーが発生します。

 

java.lang.NoClassDefFoundError: javax.swing.tree.TreeNode is a restricted class. Please see the Google  App Engine developer's guide for more details.


対応方法は、上記で見つからないと言われるクラスをソースフォルダに定義する必要があるようです。

詳細は、以下の記事の"Struts2を使うには"の2点目の対応が必要になります。

ふじやん雑記帳 - Google App Engine

 

追加するクラスのソースを念のため、以下にも載せておきます。

/*
 * Copyright (c) 2003 The Visigoth Software Society. All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowledgement:
 *       "This product includes software developed by the
 *        Visigoth Software Society (http://www.visigoths.org/)."
 *    Alternately, this acknowledgement may appear in the software
itself,
 *    if and wherever such third-party acknowledgements normally
appear.
 *
 * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names
of the
 *    project contributors may be used to endorse or promote products
derived
 *    from this software without prior written permission. For written
 *    permission, please contact visigo...@visigoths.org.
 *
 * 5. Products derived from this software may not be called
"FreeMarker" or "Visigoth"
 *    nor may "FreeMarker" or "Visigoth" appear in their names
 *    without prior written permission of the Visigoth Software
Society.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Visigoth Software Society. For more
 * information on the Visigoth Software Society, please see
 * http://www.visigoths.org/
 */

package freemarker.core;

import java.io.IOException;

/**
 * A TemplateElement representing a block of plain text.
 *
 * @version $Id: TextBlock.java,v 1.17 2004/01/06 17:06:42 szegedia Exp $
 */
public final class TextBlock extends TemplateElement {
 private static final char[] EMPTY_CHAR_ARRAY = new char[0];
 static final TextBlock EMPTY_BLOCK = new TextBlock(EMPTY_CHAR_ARRAY, false);
 // We're using char[] instead of String for storing the text block because
 // Writer.write(String) involves copying the String contents to a char[]
 // using String.getChars(), and then calling Writer.write(char[]).By
 // using Writer.write(char[]) directly, we avoid array copying on each
 // write.
 private char[] text;
 private final boolean unparsed;

 public TextBlock(String text) {
 this(text, false);
 }

 public TextBlock(String text, boolean unparsed) {
 this(text.toCharArray(), unparsed);
 }

 private TextBlock(char[] text, boolean unparsed) {
 this.text = text;
 this.unparsed = unparsed;
 }

 /**
 * Simply outputs the text.
 */
 public void accept(Environment env) throws IOException {
 env.getOut().write(text);
 }

 public String getCanonicalForm() {
 String text = new String(this.text);
 if (unparsed) {
 return "<#noparse>" + text + "</#noparse>";
 }
 return text;
 }

 public String getDescription() {
 String s = new String(text).trim();
 if (s.length() == 0) {
 return "whitespace";
 }
 if (s.length() > 20) {
 s = s.substring(0, 20) + "...";
 s = s.replace('\n', ' ');
 s = s.replace('\r', ' ');
 }
 return "text block (" + s + ")";
 }

 TemplateElement postParseCleanup(boolean stripWhitespace) {
 if (text.length == 0)
 return this;
 int openingCharsToStrip = 0, trailingCharsToStrip = 0;
 boolean deliberateLeftTrim = deliberateLeftTrim();
 boolean deliberateRightTrim = deliberateRightTrim();
 if (!stripWhitespace || text.length == 0) {
 return this;
 }
 if (parent.parent == null && previousSibling() == null)
 return this;
 if (!deliberateLeftTrim) {
 trailingCharsToStrip = trailingCharsToStrip();
 }
 if (!deliberateRightTrim) {
 openingCharsToStrip = openingCharsToStrip();
 }
 if (openingCharsToStrip == 0 && trailingCharsToStrip == 0) {
 return this;
 }
 this.text = substring(text, openingCharsToStrip, text.length
 - trailingCharsToStrip);
 if (openingCharsToStrip > 0) {
 this.beginLine++;
 this.beginColumn = 1;
 }
 if (trailingCharsToStrip > 0) {
 this.endColumn = 0;
 }
 return this;
 }

 /**
 * Scans forward the nodes on the same line to see whether there is a
 * deliberate left trim in effect. Returns true if the left trim was
 * present.
 */
 private boolean deliberateLeftTrim() {
 boolean result = false;
 for (TemplateElement elem = this.nextTerminalNode(); elem != null
 && elem.beginLine == this.endLine; elem = elem
 .nextTerminalNode()) {
 if (elem instanceof TrimInstruction) {
 TrimInstruction ti = (TrimInstruction) elem;
 if (!ti.left && !ti.right) {
 result = true;
 }
 if (ti.left) {
 result = true;
 int lastNewLineIndex = lastNewLineIndex();
 if (lastNewLineIndex >= 0 || beginColumn == 1) {
 char[] firstPart = substring(text, 0,
 lastNewLineIndex + 1);
 char[] lastLine = substring(text, 1 + lastNewLineIndex);
 if (trim(lastLine).length == 0) {
 this.text = firstPart;
 this.endColumn = 0;
 } else {
 int i = 0;
 while (Character.isWhitespace(lastLine[i])) {
 i++;
 }
 char[] printablePart = substring(lastLine, i);
 this.text = concat(firstPart, printablePart);
 }
 }
 }
 }
 }
 if (result) {
 }
 return result;
 }

 /**
 * Checks for the presence of a t or rt directive on the same line. Returns
 * true if the right trim directive was present.
 */
 private boolean deliberateRightTrim() {
 boolean result = false;
 for (TemplateElement elem = this.prevTerminalNode(); elem != null
 && elem.endLine == this.beginLine; elem = elem
 .prevTerminalNode()) {
 if (elem instanceof TrimInstruction) {
 TrimInstruction ti = (TrimInstruction) elem;
 if (!ti.left && !ti.right) {
 result = true;
 }
 if (ti.right) {
 result = true;
 int firstLineIndex = firstNewLineIndex() + 1;
 if (firstLineIndex == 0) {
 return false;
 }
 if (text.length > firstLineIndex
 && text[firstLineIndex - 1] == '\r'
 && text[firstLineIndex] == '\n') {
 firstLineIndex++;
 }
 char[] trailingPart = substring(text, firstLineIndex);
 char[] openingPart = substring(text, 0, firstLineIndex);
 if (trim(openingPart).length == 0) {
 this.text = trailingPart;
 this.beginLine++;
 this.beginColumn = 1;
 } else {
 int lastNonWS = openingPart.length - 1;
 while (Character.isWhitespace(text[lastNonWS])) {
 lastNonWS--;
 }
 char[] printablePart = substring(text, 0, lastNonWS + 1);
 if (trim(trailingPart).length == 0) {
 // THIS BLOCK IS HEINOUS! THERE MUST BE A BETTER
 // WAY! REVISIT (JR)
 boolean trimTrailingPart = true;
 for (TemplateElement te = this.nextTerminalNode(); te != null
 && te.beginLine == this.endLine; te = te
 .nextTerminalNode()) {
 if (te.heedsOpeningWhitespace()) {
 trimTrailingPart = false;
 }
 if (te instanceof TrimInstruction
 && ((TrimInstruction) te).left) {
 trimTrailingPart = true;
 break;
 }
 }
 if (trimTrailingPart)
 trailingPart = EMPTY_CHAR_ARRAY;
 }
 this.text = concat(printablePart, trailingPart);
 }
 }
 }
 }
 return result;
 }

 /*
 * private String leftTrim(String s) { int i =0; while (i<s.length()) { if
 * (!Character.isWhitespace(s.charAt(i))) break; ++i; } return
 * s.substring(i); }
 */
 private int firstNewLineIndex() {
 String content = new String(text);
 int newlineIndex1 = content.indexOf('\n');
 int newlineIndex2 = content.indexOf('\r');
 int result = newlineIndex1 >= 0 ? newlineIndex1 : newlineIndex2;
 if (newlineIndex1 >= 0 && newlineIndex2 >= 0) {
 result = Math.min(newlineIndex1, newlineIndex2);
 }
 return result;
 }

 private int lastNewLineIndex() {
 String content = new String(text);
 return Math.max(content.lastIndexOf('\r'), content.lastIndexOf('\n'));
 }

 /**
 * figures out how many opening whitespace characters to strip in the
 * post-parse cleanup phase.
 */
 private int openingCharsToStrip() {
 int newlineIndex = firstNewLineIndex();
 if (newlineIndex == -1 && beginColumn != 1) {
 return 0;
 }
 ++newlineIndex;
 if (text.length > newlineIndex) {
 if (newlineIndex > 0 && text[newlineIndex - 1] == '\r'
 && text[newlineIndex] == '\n') {
 ++newlineIndex;
 }
 }
 if (new String(text).substring(0, newlineIndex).trim().length() > 0) {
 return 0;
 }
 // We look at the preceding elements on the line to see if we should
 // strip the opening newline and any whitespace preceding it.
 for (TemplateElement elem = this.prevTerminalNode(); elem != null
 && elem.endLine == this.beginLine; elem = elem
 .prevTerminalNode()) {
 if (elem.heedsOpeningWhitespace()) {
 return 0;
 }
 }
 return newlineIndex;
 }

 /**
 * figures out how many trailing whitespace characters to strip in the
 * post-parse cleanup phase.
 */
 private int trailingCharsToStrip() {
 String content = new String(text);
 int lastNewlineIndex = lastNewLineIndex();
 if (lastNewlineIndex == -1 && beginColumn != 1) {
 return 0;
 }
 String substring = content.substring(lastNewlineIndex + 1);
 if (substring.trim().length() > 0) {
 return 0;
 }
 // We look at the elements afterward on the same line to see if we
 // should strip any whitespace after the last newline
 for (TemplateElement elem = this.nextTerminalNode(); elem != null
 && elem.beginLine == this.endLine; elem = elem
 .nextTerminalNode()) {
 if (elem.heedsTrailingWhitespace()) {
 return 0;
 }
 }
 return substring.length();
 }

 boolean heedsTrailingWhitespace() {
 if (isIgnorable()) {
 return false;
 }
 for (int i = 0; i < text.length; i++) {
 char c = text[i];
 if (c == '\n' || c == '\r') {
 return false;
 }
 if (!Character.isWhitespace(c)) {
 return true;
 }
 }
 return true;
 }

 boolean heedsOpeningWhitespace() {
 if (isIgnorable()) {
 return false;
 }
 for (int i = text.length - 1; i >= 0; i--) {
 char c = text[i];
 if (c == '\n' || c == '\r') {
 return false;
 }
 if (!Character.isWhitespace(c)) {
 return true;
 }
 }
 return true;
 }

 boolean isIgnorable() {
 if (text == null || text.length == 0) {
 return true;
 }
 if (!isWhitespace()) {
 return false;
 }
 // trick here
 boolean atTopLevel = true;
 TemplateElement prevSibling = previousSibling();
 TemplateElement nextSibling = nextSibling();
 return ((prevSibling == null && atTopLevel) || nonOutputtingType(prevSibling))
 && ((nextSibling == null && atTopLevel) || nonOutputtingType(nextSibling));
 }

 private boolean nonOutputtingType(TemplateElement element) {
 return (element instanceof Macro || element instanceof Assignment
 || element instanceof AssignmentInstruction
 || element instanceof PropertySetting
 || element instanceof LibraryLoad || element instanceof Comment);
 }

 private static char[] substring(char[] c, int from, int to) {
 char[] c2 = new char[to - from];
 System.arraycopy(c, from, c2, 0, c2.length);
 return c2;
 }

 private static char[] substring(char[] c, int from) {
 return substring(c, from, c.length);
 }

 private static char[] trim(char[] c) {
 if (c.length == 0) {
 return c;
 }
 return new String(c).trim().toCharArray();
 }

 private static char[] concat(char[] c1, char[] c2) {
 char[] c = new char[c1.length + c2.length];
 System.arraycopy(c1, 0, c, 0, c1.length);
 System.arraycopy(c2, 0, c, c1.length, c2.length);
 return c;
 }

 boolean isWhitespace() {
 return text == null || trim(text).length == 0;
 }

}

 

次に、2点目ですが、ローカルでの実行に問題が無くても

デプロイ時に不明なエラーが発生しました。エラーの内容は、

こちらの内容を参照してください。

私の環境では、web.xml および、appengine-web.xml で、

ファイルがパース出来ないという意味合いのエラーの内容です。

 

Received IOException parsing the input stream for <該当のxmlファイルのパス>

 

上記のページでも最後の方で解決していますが、

結局のところ、該当のxmlファイル内のコメントを全て削除することで解決しました。

納得はいきませんが、とりあえず動作させる事を優先で対応しました。

 

以上で、やっと・・なんとか、

GAE+Struts2.2(Zero Configuration、Convention-Plugin)+Twitter連携アプリが

完成しました。

サンプルのアプリは、ここを参照してください。

 

Twitter連携用のAPIとしては、

 Twitter4J#getPublicTimeline メソッド

 Twitter4J# showUser メソッド

 Twitter4J#showStatus メソッド

を利用しています(いずれも認証不要)

 

今後も、様々なTwitter連携APIのサンプルを作成してみたいと思います。

 

Struts2の大きな特徴である、

Zero Configuration(アクションマッピング等の設定をファイルに記述しない)

ですが、2.0系で使用していた、Codebehindプラグインが非推奨なった。

 

現時点(2010/11/3)での、Struts2のバージョンも2.2.1であるため、

最新のバージョンへの更新および、Codebehindプラグインをやめ、

Conventionプラグインへの切換えをおこなってみた。

しかも、GAE(Google App Engine)環境で。

 

仕組み自体はそう大して変わっていないと思っていたが・・・

やはり簡単には移行できなかったので、あれこれと調べる羽目になり、

時間も結構かかったが、なんとか動作するようになり、

Conventionプラグインについても見えてきた。

 

とりあえず、つまづき度が大きかった順に・・・

※これはGAE(Google App Engine)でテストしていたのも重なり、障害の

切り分けに時間がかかってしまったような気もするが・・・

障害としては、URLで該当のアクションwp呼び出すURLを入力しても、

「アクションが見つからない」とのメッセージ。

 

"There is no Action mapped for namespace /"

 

Codebehindプラグインを使用していた時にもハマったエラー。

その際は次のように、"actionPackages"というパラメータを

web.xmlで設定すれば、指定した名前空間の下にあるアクションクラスを

参照してくれるようになった。

 

 <filter>
  <filter-name>struts2</filter-name>
  <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
  <init-param>
   <param-name>actionPackages</param-name>
   <param-value>com.pg2se.sample.action</param-value>
  </init-param>
 </filter>

しかし、今回は同様のパラメータ設定をしていてもうまくアクションが呼び出されない・・

そして、どこかのページで、Struts.xml の配置が必要で、

"<constant name="struts.devMode" value="true" />"の設定をしろ!のようなページを

見てしまったため、

"access denied (java.io.FilePermission jar:file:\C:\Projects\gae\war\WEB-INF\lib\struts2-core-2.2.1.jar read)"

というエラーも出るようになったりで、Struts2が悪いのか、GAEか、どこがどう悪いかが見当つかなくなった。

 

もう1点が、Resultのjspファイルが見つからない旨のエラーが発生したこと。

 

"No result defined for action "のエラーメッセージ。

 

アクションは実行されたようだだが、ビューファイルが見つからない。

これも今までは普通にjspを配置すれば動いていたのだが・・・

 

結局、順番にひとつづつ試していってわかったこと。

1.Struts.xml は無くても動作はした。

 

2.Struts.xml の"<constant name="struts.devMode" value="false" />"でvalueはfalseにする。

  ※これはGAE環境だからかもしれない・・

 

3.GAE環境では、セキュリティマネージャを無効にする必要がある

  ※web.xmlにリスナーを設定してセキュリティマネージャを無効にする。

 

     <listener><!-- GAE関連で必要なListenerを設定 -->

         <listener-class>com.pg2se.google.InitListener</listener-class>

     </listener>

 

    public class InitListener implements ServletContextListener, HttpSessionListener, HttpSessionAttributeListener {

        @override

        public void contextInitialized(ServletContextEvent arg0) {
            OgnlRuntime.setSecurityManager(null);
        }

    }

  こんな感じ

 

4.これもGAE環境でのエラーのはず。

  クラスが見つからない旨のエラー。→xalan関連のクラス。

  こちらはxalanのライブラリをダウンロードして手動で追加する必要があった。

 

5.アクションクラスが見つからない件

  上記の設定で、すべて再起動、再ビルドするとアクションは実行されるようになった。

  ※因みにConventionプラグインでは、web.xmlでの、"actionPackages"パラメータは

  記述しなくて良く、アクションクラスの格納されたパッケージは自動検出される。

  →action,actions,struts,struts2の名前のついたパッケージが対象

 

6.ビューファイルが見つからない件

  Conventionプラグインでは、ビューファイル(jsp等)の配置場所もデフォルトで設定

  されている。それが、/WEB-INF/content/ です。

  ※そりゃ、今までどおりでは、resultのファイルが呼び出されない訳だ。

  取り急ぎ、jspのビューファイルを、上記場所に移動。

 

以上で、なんとかこれまでどおり、Struts2が動作するようになった。(しかもGAE上で)

Conventionプラグインン・・・なかなか癖があり、手ごわかった。

 

さて、これまでは、Conventionプラグインのデフォルトの設定を生かしたが、

カスタマイズするには?だけど・・・、方法はあります。

 

struts.xmlファイルに<constant>タグで設定を記述することによって、既定値を変更することが可能です。

例)<constant name="struts.convention.result.path" value="/WEB-INF/jsp/"/>

  <constant name="struts.convention.package.locators" value="act"/>

 

他にも設定変更の詳細や、今回ハマった内容のほとんどについては、

以下のページで詳しく解説されています。

Struts 2入門(6)?XML不要のZero Configuration?

Google App Engine/Struts2の連携

 

今後、Struts2.2、GAEを連携させてより深いところまで、

Struts2を追及していこうと思います。

 

 著者: 竹添 直樹

発行人: 佐々木 幹夫

発行所: 株式会社 翔泳社

発行日: 2010年 4月 19日

601ページ

3,800円+税

 

 内容

Seasar2による現場のノウハウを詰め込んだWeb開発バイブル決定版

SAStruts、S2JDBCから周辺プロダクト、携帯Webアプリまで、

Seasar2のすべてを徹底解説。

Javaベースの国産DIコンテナ「Seasar2」と、Seasar2をベースにしたWebフレームワーク

「SAStruts」、データベースアクセスフレームワーク「S2JDBC」の解説書。DIコンテナとしての

Seasar2の基礎から、SAStrutsやS2JDBCといったフレームワークを徹底的に使いこなすために

必要となる情報までを一冊にまとめている。

 

ポイント

JavaのWeb開発フレームワークとしては定番のひとつとなっているSeasar2。

Seasar2は、すでに確立されたフレームワークとして今後大きな機能拡張は

されない(もちろん不具合の対応などはきっちりとされている)となっている。

 

DIコンテナ、SAStruts、S2JDBCを利用した開発をおこなうにあたり、安心して利用でき、

フレームワークのバージョンアップにおける、大きな互換性の問題もなく利用できそうなので

今後学習する内容が、長く活用できると思われる。

 

また、Seasar2は、国産のフレームワークであることから、日本語のドキュメントや、

メーリングリストでのやりとりも活発であることから、学習や、問題の解決のための

情報収集も比較的簡単にできる。

 

本書は、「Seasar2徹底入門」となっているが、フレームワークの仕組みという根幹の

部分の解説だけではなく、システムの開発における、必要な部分すべてを網羅した形で

構成されている。

例えば、Seasarの核となるS2Containerはもちろん、Webのフレームワークである、

S2Struts、データベースを利用するためのS2JDBCについてもたくさんのページを割いて

おり、またそれ以外の周辺の技術、ユニットテストや、ユーティティ、メールやバッチ処理、

設定情報の外部化、CSVファイル、Excelファイルの操作、携帯Webアプリの開発まで、

Seasar2を様々な形で応用できる部分まで触れられている。

基本のフレームワーク部分の仕組みの解説についてもう少し厚く解説が欲しかった

気もするので、Seasar2のフレームワークの内部に興味がある方は少し物足りないかも。

 

目次

1 Seasar2 の世界へようこそ!

  • 1.1  Seasar2 の歩み
  • 1.2  Dependency Injection
  • 1.3  開発環境のセットアップ


2 S2Container

  • 2.1  はじめての S2Container
  • 2.2  コンポーネントの定義
  • 2.3  インジェクションの種類
  • 2.4  OGNL
  • 2.5  インクルードと名前空間
  • 2.6  AOP
  • 2.7  自動登録
  • 2.8  アノテーション
  • 2.9  Web アプリケーションでの利用
  • 2.10 環境ごとの切り替え
  • 2.11 SMART deploy
  • 2.12 dicon ファイルの構成
  • 2.13 dicon ファイルリファレンス


3 SAStruts 入門

  • 3.1  SAStruts とは?
  • 3.2  SAStruts で Hello World!
  • 3.3  SAStruts の設定


4 アクションとアクションフォーム

  • 4.1  アクション
  • 4.2  アクションフォーム
  • 4.3  入力チェック


5 ビュー

  • 5.1  JSP の基礎知識
  • 5.2  Struts のカスタムタグ
  • 5.3  JSTL のカスタムタグ
  • 5.4  SAStruts のタグライブラリ
  • 5.5  SAStruts が提供する EL 関数
  • 5.6  JSP ファイルの共通化
  • 5.7  JSP へのダイレクトアクセスの禁止
  • 5.8  Tiles によるレイアウト
  • 5.9  独自のタグライブラリを作る
  • 5.10 ビューとして Mayaa を使う


6 SAStruts 応用編

  • 6.1  トランザクショントークン
  • 6.2  ファイルのアップロードとダウンロード
  • 6.3  Ajax
  • 6.4  アプリケーションの共通処理を実装する
  • 6.5  認証機能を実装する
  • 6.6  エラー処理
  • 6.7  ポートレット対応


7 S2JDBC 入門

  • 7.1  S2JDBC とは?
  • 7.2  はじめての S2JDBC
  • 7.3  S2JDBC の設定


8 エンティティ

  • 8.1  エンティティ定義のためのアノテーション
  • 8.2  エンティティの定義
  • 8.3  主キーの設定
  • 8.4  関連の定義
  • 8.5  列挙型の利用
  • 8.6  エンティティの継承
  • 8.7  エンティティのマッピングルールの変更


9 JdbcManager

  • 9.1  検索
  • 9.2  挿入
  • 9.3  更新
  • 9.4  削除
  • 9.5  SQL の実行
  • 9.6  外部 SQL ファイル
  • 9.7  イテレーション検索
  • 9.8  検索結果のページング
  • 9.9  楽観的排他制御
  • 9.10 ストアドの呼び出し


10 S2JDBC-Gen

  • 10.1 S2JDBC-Gen とは?
  • 10.2 ソースコード生成のカスタマイズ
  • 10.3 タイプセーフな S2JDBC
  • 10.4 テストケースの生成
  • 10.5 S2JDBC-Gen の Ant タスクリファレンス


11 SAStruts と S2JDBC の連携

  • 11.1 SAStruts と S2JDBC の連携
  • 11.2 トランザクションの制御
  • 11.3 Dolteng による自動生成


12 Seasar2 が提供するユーティリティ

  • 12.1 JavaBean の値をコピーする (S2BeanUtils)
  • 12.2 HttpServletRequest などを取得する
  • 12.3 基本的な処理のためのユーティリティ
  • 12.4 入出力関係のユーティリティ
  • 12.5 クラスパス内のリソースに関するユーティリティ
  • 12.6 リフレクション関係のユーティリティ
  • 12.7 その他の便利なクラス


13 ユニットテスト

  • 13.1 ユニットテストとは?
  • 13.2 S2Unit
  • 13.3 S2JUnit4
  • 13.4 EasyMock のサポート
  • 13.5 SAStruts + S2JDBC におけるユニットテスト


14 その他のプロジェクト

  • 14.1 S2Mai によるメール送信
  • 14.2 S2Chronos によるパッチ処理
  • 14.3 S2Config による設定情報の外部化
  • 14.4 S2CSV による CSV ファイルの入出力
  • 14.5 Fisshplate による Excel ファイルの生成
  • 14.6 mobylet による携帯 Web アプリ開発

 

 

編者:日経ソフトウェア

発行人:桔梗原 富夫

編集長:田島 篤

発行:日経BP社

178ページ

1,886円+税

 

内容

2010年10月2日にHTC Desire(X06HTII)が発売されました。

Android2.1搭載のスマートフォンで、iPhone4に次ぎ、評判は上々のようです。

さすがにiPhone4の勢いほどではないけど、アプリケーションの開発という点では、

より柔軟・オープンであり、今後に期待できます。

 

さらにHTC Desire(X06HTII)は、2010年10月8日には、Andoroid2.2へアップデート

可能で、加速度的にiPhoneを凌ぐ勢いとなりそうです。

 

さて、前置きが長くなりましたが、この書籍では、こういった状況を踏まえてかどうか、

アプリケーションの開発について、2大スマートフォン(もちろんIPhoneとAndroid)の

両方のプログラミングについて書かれた最新の書籍になります。

 

私の場合は、Mac環境、Apple製品を好んで利用しないため、必然的に、Javaでの

開発が手軽にできるAndroidとなった訳ですが、スマートフォンの開発については、

やはり、iPhone、Android両方の知識について理解する事も大切です。

 

この書籍ではタイトルのとおり、"入門"ではありますが、こうした2大スマートフォンの

アプリケーション開発について、両者を比較しながら、体系的に、手軽に学べるという

点では、とても有用なバイブルとなると思います。

 

日経ソフトウェアの過去の記事から作られているムック本ではありますが、

基本的な知識と、技術がしっかり学べると思います。

今の時代の、システムエンジニア、プログラマの基礎知識としても、

知っておくべき内容がたくさん詰まっていると言えます。

 

目次

 

第1章 作って楽しい!

  • Part1 iPhoneプログラミング入門 効率的に始めるための4大ポイント!
  • Part2 iPad専用のスプリットビューとポップオーバーでRSSリーダーを作る
  • Part3 Androidで作って楽しむ弾幕系シューティングゲーム
  • Part4 iPadプログラミング入門 高速動作と大画面を生かす!パーティクルによる電光掲示板アプリを作る
  • Part5 開発者が明かすニコニコ生放送のiPhoneアプリはこうして生まれた

 

第2章 Androidの基礎を極める!

  • Part1 最も重要な「Activity」を理解する
  • Part2 音声読み上げアプリケーションを作る
  • Part3 Intentで超簡単アプリケーション連携
  • Part4 実例で学ぶIntentの使い方
  • Part5 Androidの秘密兵器、Serviceを理解する
  • Part6 Serviceに独自のinterfaceを持たせる
  • Part7 データ共有に必須のContentProvider
  • Part8 アプリにContentProviderを実装する

 

第3章 達人への第一歩

  • Part1 16個のサンプルで一目瞭然高度な機能がすぐに使える!
  • Part2 最速で学ぶObjective-C メモリー管理をマスターすればObjective-Cがわかる!
  • Part3 最速で学ぶObjective-C GUIプログラム作成に必要な概念をマスターしよう
  • Part4 iPhone実践プログラミング 電子コンパスを使ったアプリを実機で動かそう
  • Part5 iPhone実践プログラミング MapKitで地図アプリを作ろう
  • Part6 Phone実践プログラミングGameKitを使ってBluetooth通信対戦ゲームを作ろう
  • Part7 Javaエンジニアから見たiPhone/Androidアプリ開発記

 

付録 開発環境のセットアップ

 

ポイント

2大スマートフォンのアプリ開発が同時にわかる!

世界的なブームとなっているiPhone/iPadとAndroidのプログラミングを同時に

学びましょう。iPhoneプログラミングの基本、Objective-C、iPadの画面サイズを

生かすアプリの作り方、Androidの4大構成要素(Activity,Intent、Service、

ContentProvider)、Androidで作る弾幕系シューティングゲームなど、多彩な内容

を詰め込みました。iPhone/iPadとAndroidの類似点と相違点を把握しながら学べ、

それぞれのOSに対する理解も深まります。

 

補足

iPhone/iPadの開発は、通常Mac上での開発となりますが、

C#環境でも開発することがが可能なようです(Mono環境)

これは、開発の生産性においても、Windowsプログラマにとっても、

とても可能性の広がる事だと思います。Appleの対応についても、

もっともっとオープンになればうれしいことです。

 

 

 

twitterと連携するアプリケーション作成のためのAPI群です。

 

OAuthというツイッターの認証機能を利用できる仕組みがあるので、

お手軽に、しかもユーザにとっても安心・安全に利用できる仕組みになってる。

 

OAuthを利用するためには、アプリケーションを登録しないといけないので、

http://twitter.com/apps

上記より、登録します。

 

登録すると、Consumer key、Consumer secret という情報を取得できるので、

その情報を利用して、ユーザを、twitterの認証ページに誘導し、アプリの利用の

同意を頂くと、アプリから、そのユーザができる操作を代行できるようになる。

 

今回は、好きな"お酒"のことに特化したつぶやきをするためのアプリ、

「つい飲み」というWebアプリを作成してみた。

"いまなにのんだ?"をコンセプトに、飲んだお酒と"つぶやき"を投稿するアプリ。

(また、#sake というカテゴリが自動で設定されるようになってます)

 

1.ログインボタンを押す

2.Consumer key、Consumer secretを 設定しtwitterの認証ページにリダイレクト

3.認証が成功すると、事前に設定したアプリのページに自動で戻ってくる

4.AccessTokenという、認証が成功したユーザを操作するための権限を取得する

5.AccessTokenを利用して、"つぶやく" など、必要な処理を呼び出す。

 

今回は、Java(Struts2)を利用して、Webアプリケーションを作成した。

twitter4jというOAuthも手軽に利用できるライブラリがあったので。

 

要点のコードを抜粋

//最初にtwitterのサイトへ誘導し認証させる

Twitter twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer("xxxxxxxxxx", "yyyyyyyyyy");
RequestToken token = twitter.getOAuthRequestToken();
sessionMap.put("twitter", twitter);
response.sendRedirect(token.getAuthenticationURL());

 

//次に認証が成功すると任意のページへリダイレクトされるので権限を取得

Twitter twitter = (Twitter)sessionMap.get("twitter");
if (twitter != null) {
 AccessToken token = twitter.getOAuthAccessToken();
 sessionMap.put("token", token);

}

 

//権限を利用してアプリから"つぶやき"を投稿

AccessToken token = (AccessToken)sessionMap.get("token");
if (token != null) {
 Twitter twitter = (Twitter)sessionMap.get("twitter");
 twitter.updateStatus("つぶやきを投稿");
}

 

※これでひととおりの操作が可能です。

つぶやき以外にも様々な操作がAPIで提供されてます。

 

※携帯からの利用についてですが、twitterの認証機能は、https対応ですが

携帯で表示時にtwitterの証明書ではエラーになるようです。

なので、HTTPリクエストのヘッダーで、携帯からのアクセスかを判断して、

携帯からの場合は、HTTPSを、HTTPへ書き換えてあげるとうまくいきます。

セキュリティが弱くなるけれど、twitterで通常の携帯ログインもHTTPのよう

なので、とりあえず問題はないかと...。


 とりいそぎ最低限のラインで作成してみたので、

また機能アップしていきたいと思います。

 

続 Struts 2入門

| コメント(0) | トラックバック(0)

CodeZineで、Struts2入門(1)?(8) の続編、

続 Struts 2入門が始まりました!!

 

Strutsは以前から利用しているので、Struts 2になった今後も是非とも

発展し続けていってほしいと思う。

自分自身でもStrtuts2でWebアプリケーションを作っているので、

いろいろと情報発信して、Struts2の発展に貢献できればなと思う。

 

Strutsの時よりも、情報源が少なく感じ、なかなか活用しきれていない

面があるので、こういった連載が始まるのはありがたい!!

記事を見てもらうほうが詳細に理解できますが、さわりだけわかれば

良い方は以下を参照してください。

 

続 Struts 2入門

基本機能のおさらいから2.1系で採用された機能の説明や実装例を紹介

(1)Struts 2の同期処理を手助けするExecuteAndWaitインターセプタ

 

処理に時間がかかるActionクラスの処理状況を監視し、その結果を自動的に

判断するためのExecuteAndWaitインターセプタの使用例を解説。

 

Actionクラスにはメインのロジックを記述するだけで、あとは設定のみで、

同期処理を実現することが可能になります。

 

具体的な手法としては、

ブラウザの自動リフレッシュ機能を利用し、Actionクラス内の時間の

かかる処理を、自動で途中中断して、リフレッシュを設定したページを表示。

(Actionの実行は継続されセッションに維持される)

 

再度リフレッシュしてサーバにアクセスすると、中断したActionの状況を

再度監視できるようになっている。

まだ処理中の場合は、再度リフレッシュページへ、処理が完了した場合は

完了用のページが表示されるという仕組みです。

 

これらを、上記のExecuteAndWaitインターセプタ(アノテーションの機能)

を利用することで設定をおこなうことで、簡単に利用することができます。

 

インターセプタ(汗)

まだぜんぜん利用できていないので、実用できるように勉強します。

次回もインターセプタの機能についての記事のようです。

 

 Google App Engine for Java「実践」クラウドシステム構築

 

著者: 株式会社グルージェント

発行日: 2009年10月10日

発行者: 片山 巌

発行所: 株式会社技術評論社

310ページ

2,480円+税

 

 内容

Googleのスケーラビリティを案件で使い切る。活用の秘訣は、「制約」を正しく

理解すること。割り当てと制限、BigTableによるDB構築、課金のしくみ、

Google Apps、GDataとの連携、Memcache、Mail・・・API活用

 

ポイント

Window Azureサービスも開始され、クラウドサービスもビジネスだけではなく、個人的な

利用についても十分現実的なものになっていきている。Windows Azureも魅力的であるが

まだまだ情報も少なく、個人的に試してみるのは、まだ先かなぁと思う。

 

そんな中、やはり無料で使用でき、導入が容易、機能も豊富なサービスといえば、

Google App Engine for Javaでしょう。特にJava Webアプリケーションサーバの

実行環境が無料で利用できるというのは、Javaユーザにとっては、特にありがたい

でしょう(レンタルサーバでもJavaの実行環境が提供されるのは稀なので)

一定の使用量を超えると課金になるが、そこそこヘビーなアプリケーションでなければ、

制限を超えることはないと思う。ぜひ一度試してください。

 

本書では、こういった、サービスの基本的な内容、課金について、導入手順などはもちろん、

サービスの各機能の使用方法のポイントを、わかりやすく説明されているので、このサービス

の素晴らしさが実感できると思う。

 

とりあえず、触ってみたいという方は、Eclipse環境で導入可能なので以下参照してください。

http://pg2se.com/site/2009/07/google-app-engine-for-java.html

 

内容詳細

第1章 クラウド時代のシステムインテグレーション

1.1 クラウドコンピューティング

1.2 Google App Engine

1.3 Google App Engine for Java

 

第2章 制約

2.1 Quota(割り当て)とLimit(制限)

2.2 Java APIに対する制約

 

第3章 クラウド時代のシステムインテグレーション

3.1 GAEアカウントの作成とデプロイの準備

3.2 開発環境の構築

3.3 アプリケーションの作成とデプロイ

3.4 アプリケーションの設定

3.5 アプリケーションの管理

 

第4章 データストア

4.1 BigTable

4.2 JDOによるデータストアの操作

4.3 インデックス

4.4 トランザクション

4.5 JDO以外のデータストアAPI

4.6 データストア設計上の注意点

 

第5章 サービスAPI

5.1 Memcache API

5.2 URLフェッチ API

5.3 Images API

5.4 Mail API

 

第6章 テスト

6.1 ユニットテスト

6.2 ローカル環境でのテスト

6.3 実環境でのテスト

6.4 パフォーマンスの確認

 

第7章 GAEが提供するサービスとの連携

7.1 GAEが連携可能なGoogleアプリケーション

7.2 アカウント認証サービスとの設定

7.3 Google Calendarとの連携

7.4 GAE/Jアプリケーションを独自ドメインで運用

7.5 Secure Data Connector

 

第8章 追加リソースの購入

8.1 Billingの体系

8.2 Billingの設定

8.3 課金量の予測

 

2009年9月7日、オープンソース給与・勤怠システム「MosP」の

フレームワークとAPIが公開された。

MosPは、Mind Open Source Project の略で、「モスプ」と呼ぶ。

 

MosPはマインドが開発し公開しているJava Webアプリケーションであり、

Strutsと同様にMVCアーキテクチャをとる構造となっている。

 

画面サンプル

mosp0.jpg

mosp1.jpg

 

フレームワークの特徴

Action基本クラスは簡易ワンタイムパスワード機能や認証情報確認機能等を備えて

おり、データベースにアクセスするためのクラスとしてDaoとDtoクラスがある。

またjOpenDocumentを利用したOpenOffice.org帳票作成クラスと、Apachi POIを

利用したMicrosoft Excel帳票作成クラスがある。OpenOfficeまたはExeclで作成

したテンプレートに値を埋め込んで帳票を作成できる。

 

ドキュメントとして、アプリケーションの作成方法を記述した「MosPフレームワーク

手順書」と、APIのドキュメントが用意されている。 また、開発者向けにコミュニティ

MosP Developer's Communityを開設されており、情報を入手することができる。

 

標準機能(給与計算)
・SaaS基盤対応    ・賞与計算
・勤怠データ取込   ・個別賞与計算
・給与計算       ・賞与情報一覧
・個別給与計算    ・賞与明細出力
・給与情報一覧    ・賞与データ出力
・給与明細出力    ・社員賞与情報管理
・給与明細出力    ・賞与項目管理
・給与データ出力   ・MosP連携
・社員給与情報管理
・給与計算情報管理
・給与項目管理

標準機能(勤怠管理)

・SaaS基盤対応    ・個人情報登録
・出勤入力       ・MosP連携
・退社入力
・休暇入力
・有休管理
・確認変更
・承認機能
・帳票印刷
・スケジュール登録
・エクスポート
・基本情報登録

 

勿論、業務としてMospを採用するのは、それぞれの会社や、個人個人で、

意見は分かれるだろうが、オープンソースでどのように、給与システムや

勤怠管理システムが作られているかは技術者としては気になるところです。

 

 

Googleのインフラでウェブサービス(ウェブアプリケーション)が利用できる、

「Google App Engine for Java」が2009年4月に遂に公式発表された。

(最初の言語としてにPythonが2008年に公開されています)

 

スクリプト言語ではなく、JavaのWebコンテナ上でのバイトコードでの動作が

提供されるのは驚きです(もちろんセキュリティ上の制限はあるようです)

 

JSP、Servletはもちろん、JavaVMで動作することから、JRuby、Jython、Groovy、

Scala、Quercusなどを利用して、各種スクリプト言語も動作させることができそうです。

 

まずは、「Google App Engine for Java」を利用するまで進めてみたいと思います。

 

1.必要な環境

  Eclipse3.3、または、Eclipse3.4

  Google App Engine のアカウント

  ※インストール・取得方法は割愛します。

 

2.Eclipseへのプラグイン追加

    • [ヘルプ]-[ソフトウェア更新] メニューを開きます。
    • [使用可能なソフトウェア] タブを選択し、[サイトの追加] ボタンを押します。
    • [ロケーション] に、次の内容を入力し、[OK] ボタンを押します。
    • [Google Updates Site for Eclipse] が追加されるので、チェックボックス
      に、チェックを入れ、[インストール] ボタンをクリックします。
    • [次へ]で進み、ライセンス確認をすると、インストールが開始されます。
      ※インストール後、Eclipseを再起動をするようになります。
    • Eclipseのツールバーに、次のような、Google App Engine のツールが
      表示されていると準備完了です。
    • 20090705.jpg 

 

3.プロジェクトの作成

    • Google App Engine ツールの、左端のボタンをクリックすると、
      新規プロジェクト作成のウィザードが開始されます。
    • [Project Name] [package] を任意で指定して、[終了] ボタンを押します。
      ワークスペースに、[Project Name] で指定したプロジェクトが作成されま
      す。

 

4.プロジェクトの実行

    • ワークスペースの、プロジェクト名を右クリックして表示されるメニューの、
      [実行]-[3.Web Application] をクリックします。
    • ウィンドウが2つ起動されます。
      a)AppEngine server ...デバッグ実行用のサーバコンテナ
      b)デフォルトアプリケーションの画面(簡易ブラウザ)
    • デフォルトアプリケーションはGWTで実装されたAjaxのサンプルです。
      ->ボックスに入力し[Send]ボタンを押すとAjaxでメッセージが表示されます

※このデフォルトのソースを変更して、自分のアプリケーションを開発していきます。

※[デバッグ]メニューで実行すると、クライアント、サーバどちらもデバッグできます。

※簡易ブラウザでなく、同じURLをほかのブラウザに入力しても実行できます。
   ->コンパイルが必要です(ツールの真ん中のボタンをクリック)

 

5.アプリケーションの公開(デプロイ)

    • Google App Engine のアカウントを取得してログインします。
    • [Create an Application] ボタンを押します。
    • [Application Identifier] [Application Ttitle] を入力し、[Save] を押す。
      ->IDはGoogle Appspotのサブドメインなので世界でユニークな設定になります
    • 次に、Eclipseの設定です。ワークスペースのプロジェクトを右クリックし、
      [Google]-[App Engine Settings] メニューを開き、以下を入力します。
      [Application ID]-> 先に設定した[Application Identifier]を入力します。
      [Version]-> ユニークな番号を指定し、[OK]ボタンを押します。
    • デプロイを実行します。同じく[Google]メニューから、[Deploy to App Engine]
      を選択するか、ツールの右端のボタンを押します。
    • Google App Engineで登録した[Email]、と[Password]を入力し、[Deploy]
      ボタンを押すとデプロイが実行されます。
    • [コンソール] ウィンドウの最後に"Deployment completed successfully"
      と表示されればデプロイの完了です。

 

6.アプリケーションの実行

    • アプリケーションはインターネットを通じて、世界中に公開されます。
    • 公開されるアドレスは、http://[Application Identifier].appspot.com/ です。
      ->[Application Identifier] は、先に設定したIDです。
      ※ちなみに私の場合、http://appcontents.appspot.com/ で公開してます。
      ※GWTのUIを利用する際に日本語を設定すると文字化けしますので、
      ソースコード(リソース)の設定をUTF8にすると回避できます。


以上、Google App Engine for Java を利用する方法を書きました。

※とっても簡単にGoogleのインフラを利用したWebアプリケーションの開発ができる

ことが分かってもらえたかと思います。

 

JavaVMの環境が提供されているので、これを利用して、様々なサービスを

提供できる可能性が広がっています!!