2006年05月12日

MVC型Frameworkを理解してみる - 3.

 只今JavaScriptのPrototypeオブジェクト指向と格闘中.

 JavaScriptって使えば使うほど意外と奥が深いかも…と思い始める.
 今作っているのは、「JavaScriptでクライアントアプリケーションみたいな感じのUIをどこまで再現できるのさ」と言う物.
 …ダサダサ orz

 素直にこういうの使った方がいいのかなあ、と思い始めてます.

  -> RAIALT http://rialto.application-servers.com/wiki/
  -> Echo2 http://www.nextapp.com/platform/echo2/echo/
  -> qooxdoo http://qooxdoo.oss.schlund.de/


 話は戻って本題へ.

 [htdocs(apache document root)]
  +- index.php(フロントコントローラ)
 [Framework(apacheが読み込めるDirectory. Document root下でも可)]
  +-[application directory]
    +-[model]
    +-[template]
    +-[view]
  +-[classes]
    +-[各class]
  +-[controller]
    +- controller.php(コントローラ)


 前回の記録で

 ・ControllerはModel/Viewを呼び出す
 ・Modelは処理を実行する
 ・Viewは描画処理を実行する

 という役割分担が見えてきた訳ですが、それをディレクトリ構成とシンクロしてみます.
 ちょっと前回と異なります.

 [より現実的なディレクトリ構成]
 [htdocs(apache document root)]
  +- index.php(フロントコントローラ)
 [Framework]
  +-[application directory]
    +-[class] … Application毎のClass
    +-[conf] … Application毎のFramework用設定
      +- Framework.config.php
      +- Framework.stringtable.php
    +-[model] … Application毎のModel
      +-[common]
        +- index.model.php
    +-[template] … 描画用Template
    +-[view] … 描画用View
      +-[common]
        +- index.view.php
    +-[tmp] … Applicationで使用するTmp
  +-[classes]
    +-[各class]
    +-[model]
      +- Model.class.php
    +-[view]
      +- View.class.php
  +-[conf]
    +- Framework.config.php
    +- Framework.header.php
    +- Framework.stringtable.php
  +-[controller]
    +- Controller.php


 …実際の画像を見た方が早いか orz

 MVC004.png
 ※図はEclipseのWindow画面です.

 不要なディレクトリも多々ありますが、基本的に理解すべきディレクトリは、赤く囲った場所だと思います.
 この構成と、前回の覚書を照らし合わせてみます.
 ※あくまで理解する為にやっているので、分かり易い名前にしています.
  例えばindex処理のModelの場合は「index.model.php」w
  でも、正直こんな風に名前を付けた方が分かり易いです.

 [それぞれの役割(必要な物のみ)]
 [htdocs]
  +- index.php … フロントコントローラ
            (ユーザーがアクセスするファイル)
 [KtFramework]
  +-[application] … Applicationディレクトリ
  |  +-[example] … Application毎のディレクトリ
  |    |      (例では「example」と言うApplication)
  |    +-[model] … 各Model処理用ディレクトリ
  |    |  +-[common]
  |    |    +- index.model.php … index処理用Model
  |    +-[view] … 各View処理用ディレクトリ
  |      +-[common]
  |        +- index.view.php … index処理用View
  +-[class] … Framework用Classディレクトリ
  |  +-[KtModel]
  |  |  +- _KtModel.class.php … Model雛形
  |  +-[KtView]
  |    +- _KtView.class.php … View雛形
  |     ※KtView.error.phpはエラー時用. 正直不要w
  +-[controller] … Framework用Controllerディレクトリ
    +- KtController.php … FrameworkContorller
     ※KtController.php5.php等はKIMAGUREが気まぐれで作った各
      PHPバージョン用ファイル.


 以降、このディレクトリ構成を基準として話を進めます.

※ここで示されている構成、処理等々はKIMAGUREが自分で認識している範囲の内容、および自分の好みの書き方で書いています. 余り参考にしないで下さいw

 ユーザーにアクセスしてもらうのは

  /htdocs/index.php

 です(フロントコントローラ).
 「/htdocs/index.php」の中身は次の通り.

 [/htdosc/index.php]
 require_once('../KtFramework/controller/KtController.php');
 $KtController = new KtController('example', 'common/index_Action');


 「/htdocs/index.php」はFrameworkのControllerを呼び出すためのフロントコントローラと位置づけていますので(例の場合ですが)、当然Framework用ControllerファイルをInclude(require)し、続いてControllerクラスを宣言しています.

  /** ---------------------------------------------------------
   * @param string ApplicationName [Application名]
   * @param string ActionName [Action名(※前回記録参照)]
   * @param string CallbackViewName [強制処理View]
   */
  $KtController = new KtController('example', 'common/index_Action');

 この時点で処理はFramework用Controller、今回の例では「/Framework/controller/KtController.php」に移ります.
 ※自分で作っておいて何ですが、「*.php5.php」等は話が複雑になるの
  で省きます. 中身も必要な部分のみ抜粋.

 [/Framework/controller/KtFramework.php]

 /** ===========================================================
  * Framework Constructor.
  *
  * @internal Framework用Controller
  * @param string $szAppName
  * @param string $szActionName
  * @param string $szCallbackViewName
  */
 function KtController($szAppName,
       $szActionName, $szCallbackViewName = '') {
  /** ---------------------------------------------------------
   * Application名セット
   */
  $this->_KTF_APPLICATION = $szAppName;

  /** ---------------------------------------------------------
   * Include classes.
   *
   * @todo エラー処理未実装
   */
  if ($this->doClassInclude() == false) {
   require_once($this->_KTF_ERROR_VIEW);
   exit;
  }

  /** ---------------------------------------------------------
   * Set request action.
   *
   * @internal Constructor引数よりREQUESTを優先
   */
  $this->setRequestAction($szActionName, $szCallbackViewName);

  /** ---------------------------------------------------------
   * Execute trigger.
   */
  $this->doTrigger($szActionName, $szCallbackViewName);
 }

 [かなり省略]

 /** ===========================================================
  * doTriggerWWW(※2)
  *
  * @access private
  * @param string $szActionName
  * @param string $szCallbackViewName
  * @return mixed 成功 = True / エラー = KT_ERROR_*
  */
 function doTriggerWWW($szActionName, $szCallbackViewName) {
  /** ---------------------------------------------------------
   * Local valiable.
   */
  $isSuccess  = false;

  /** ---------------------------------------------------------
   * Include model.
   *
   * @todo Model処理後の成否判定処理があやふや
   */
  $isSuccess = $this->doModel($szActionName);
  if ($this->isModelSuccess) $isSuccess = true;

  /** ---------------------------------------------------------
   * Switch view.
   */
  $this->forwardView($isSuccess, $szActionName, $szCallbackViewName);
 }

 [省略]

 /** ===========================================================
  * doModel
  *
  * @internal Model処理を実行
  * @access private
  * @param string $szActionName
  * @return mixed 成功 = true / エラー = KT_ERROR_*
  */
 function doModel($szActionName) {
  /** ---------------------------------------------------------
   * Local valiable.
   */
  $isSuccess  = false;
  $szForwarPath  = '';
  $szClassName  = '';

  /** ---------------------------------------------------------
   * Set model path.
   *
   * @internal 処理の仕方が手抜き…もとい分かり易くw
   *  単純にしているので、Action名を置換処理+加工してPATH
   *  としてセットしています.
   *  ※補足)index_Actionをindex.model.phpに置換し、
   *      Applicationまでのパスを追加しています.
   */
  $szForwarPath = $this->_KTF_BASEDIRECTORY . '/' .
   $this->_KTF_DIRECTORY['application'] . '/' .
   $this->_KTF_APPLICATION . '/' .
   $this->_KTF_DIRECTORY['model'] . '/' .
   str_replace('_Action', '.model.php', $szActionName);

  /** ---------------------------------------------------------
   * Set class name.
   *
   * @internal 単純にAction名とModelのクラス名を類似させて
   *  index_Action->index_Model(Class名)に変換.
   */
  $szClassName =
   basename(str_replace('_Action', '_Model', $szActionName));

  /** ---------------------------------------------------------
   * Check file exist and declare class.
   */
  if ((is_file($szForwarPath))&&(is_readable($szForwarPath))) {
   require_once($szForwarPath);
   //-> Class宣言
   if (class_exists($szClassName)) {
    $this->_KTF_MODEL =& new $szClassName($this);
    $isSuccess = true;
   }
  }

  /** ---------------------------------------------------------
   * Check I/O error.
   */
  if ($isSuccess == false) {
   require_once($this->_KTF_ERROR_VIEW);
   exit;
  }

  /** ---------------------------------------------------------
   * Set return value.
   */
  return $isSuccess;
 }

 [省略]

 /** ===========================================================
  * forwardView
  *
  * @internal View処理を実行
  * @access private
  * @param boolean $isSuccess
  * @param string $szActionName
  * @param string $szCallbackViewName
  * @return mixed 成功 = True / エラー = KT_ERROR_*
  */
 function forwardView($isSuccess, $szActionName, $szCallbackViewName) {
  /** --------------------------------------------------------
   * Local valiable.
   */
  $szForwardName = $szCallbackViewName;
  $szForwarPath  = '';
  $szClassName  = '';

  /** ---------------------------------------------------------
   * Set view path.
   *
   * @internal 処理の仕方が手抜き…もといModelと同じ.
   *  単純にしているので、Action名を置換処理+加工してPATH
   *  としてセットしています.
   *  ※補足)index_Actionをindex.view.phpに置換し、
   *      Applicationまでのパスを追加しています.
   */
  if (strlen($szCallbackViewName) == 0) {
   $szForwardName = str_replace('_Action', '.view', $szActionName);
  }
  //-> エラー描画の場合「.error」へ置換
  if ($isSuccess == false) {
   $szForwardName =
    str_replace('.view', '.error', $szForwardName);
  }
  //-> フルパス代入
  $szForwarPath = $this->_KTF_BASEDIRECTORY . '/' .
   $this->_KTF_DIRECTORY['application'] . '/' .
   $this->_KTF_APPLICATION . '/' .
   $this->_KTF_DIRECTORY['view'] . '/' .
   $szForwardName . '.php';

  /** ---------------------------------------------------------
   * Set class name.
   */
  $szClassName =
   basename(str_replace('_Action', '_View', $szActionName));

  /** ---------------------------------------------------------
   * Check file exist and declare class.
   */
  $isSuccess = false;
  if ((is_file($szForwarPath))&&(is_readable($szForwarPath))) {
   require_once($szForwarPath);
   //-> Class宣言
   if (class_exists($szClassName)) {
    $this->_KTF_VIEW =& new $szClassName($this);
    $isSuccess = true;
   }
  }

  /** ---------------------------------------------------------
   * Check I/O error.
   */
  if ($isSuccess == false) {
   require_once($this->_KTF_ERROR_VIEW);
   exit;
  }
 }


 うっ…行数多くなってきた(汗

 「$this->doClassInclude()」の部分に於いて、Controller内で全てのFramework用付属クラスをIncludeしてしまいます.
 実際にユーザーコードから呼び出す場合は
  KtController->Kt****->[FunctionName]
 と成ります(ClassLibrary等と同じ).

 次に「$this->setRequestAction()」でREQUESTからActionを渡されていた場合に、今処理で実行すべきActionとしてREQUESTからAction名をセットします.
 後々書きますが、Model->Viewと処理した際、ViewでTemplateに「次に処理すべきAction」をINPUT(要するにREQUESTで渡される何かしら)で指定します.
 「$this->setRequestAction()」はこの指定されたActionを取得する為に実行する様にしました.
 現時点では「単純にindex.php(フロントコントローラ)から呼び出されただけ」ですので、初期値の「common/index_Action」がAction名になります.

※注)この「common/index_Action」は非常に変な書き方ですが、パス構成を自分で分かり易くする為にこの様な特殊な書き方をしています. この様な書き方は他では殆ど見かけません.

 次に「$this->doTrigger」ですが、これは多少細かく処理を分けた結果出来た(と言うよりEthnaをパクったりしてw)Functionです.
 「$this->doTrigger」から呼び出された後の不要な処理を省いて、実際に何をやっているのか抽出.
  [doTriggerWWW参照]
 要するに、細かい処理(Model呼び出し前/後の処理等々)を省いた上述を見ると
  1. Modelを呼び出す.
  2. 必要であれば何らかの方法でModel処理の結果を取得
    ※例では分かり易く「$isSuccess」に戻る様に表記しています.
  3. Modelの処理結果を踏まえてViewを呼び出す.
 と成ります.

 ようやくModelに処理を移行します.
  [doModel参照]
 基本的にView移行処理と同じ流れです.
 今回の例ではAction名を直接パス名に変更し、そのファイルをIncludeして直後にClass宣言しています.
 呼び出されたModelでは、
  ・REQUEST処理(Validate(入力内容が正当か)等)
  ・データ処理(DBアクセス等含む)
  ・データ加工/整形
   ※サニタイズはControllerから予めまとめて処理した方が良いと個
    人的には思うのですが、Smarty等ではTemplateへ値をセットする
    際に処理するのでお好みで.
 処理結果として、値を戻すかControllerの変数(またはGLOBALS)に戻します.
 ま、Viewで判定してエラー用の描画をするのでも良いと思います.

 最後にView.
 Modelの処理結果、データ処理後の値を描画する為の処理を行います.
 Modelで一通り必要な処理をしてあれば、Template Engineへ値をセットするだけで終了します(それが本来の姿?).

 一通りザックリと流れを見てみた訳ですが(省きすぎて分からないと言う話も有りw)、基本的には

 1. フロントコントローラをユーザーに読み込んでもらう
 2. フロントコントローラからControllerを読み込む
 3. ControllerでActionを取得し、事前処理を行う
 4. ControllerからActionに対応したModelを呼び出す
 5. Modelで処理を行う
 6. ModelからControllerに戻る
 7. ControllerからActionに対応したViewを呼び出す
 8. Viewで処理して描画出力

 と言う流れですね.
 そして前回備忘した様に、ControllerからModel/Viewを参照し、Model/ViewからControllerを参照する事で、Modelで処理されたデータをViewでセットする事が可能となります.

 [Controller]
  KtController->DATA;
 [Model]
  $this->Controller =& KtController;
  KtModel->Excecute() {
   $this->Controller->Data = 1;
  }
 [View]
  $this->Controller =& KtController;
  KtView->Excecute() {
   描画 = $this->Controller->Data;
  }

 で、MVC型Frameworkを使う理由は?
 …何となくw
 では無く、次の利点があります.

  1. 基本機能が統一的に提供される(Framework全般に言える)
    処理の流れやFrameworkに内包されたClass機能等.
  2. ロジックと描画を分離出来る為、ロジックコードを書くプログラマ
    とデザインするデザイナの作業分担が楽.
  3. メンテナンス製に優れている.
    変更点やバグFIX時の切り分け等が分かり易い.
  4. 再利用性の向上.
    確実に部品化されますので、再利用には向いています.
    極端な話、View/Temlateは同じでModelだけ変更するとかもありw
  5. Model/Viewが雛形から派生されるClassである為、書いたコードに
    統一性がある(メンテナンス時は機能の統一性よりもこちらの方が
    大事かもしれません)
  6. 書いたコードが気付かない内にオブジェクト指向(っぽく)になる.
    正直、KIMAGUREの様な底辺中の底辺の人間には、この恩恵は計り知
    れません. 書いている時は苦痛でも、後々非常にスマートなコード
    である事を実感するはずです.

 さて、次回は実際のコードで最終的な流れの確認です.

 話は変わりますが、最近急激にコードの書き方が変わってきていますw
 勉強すればする程、自分の底辺さ加減が分かり、且つ以前のコードが如何に無駄の多いコードであったかに気付き、且つ再利用性に乏しいコードであったかに気付かされます orz
 ま、後数ヵ月後には今書いているコードも同じ様に「底辺は底辺. 底辺で試行錯誤してたな」と思うんでしょうがw


 取り敢えず一気に書いたので不足、間違いが多々ありそうな悪寒.
 後日修正ですな.
posted by KIMAGURE at 00:59| 雨| Comment(41) | TrackBack(5) | PHP | このブログの読者になる | 更新情報をチェックする

2006年05月09日

Java + HTMLのみ? - Wicket

 仕事中なので純粋なメモ.

 Java + HTMLでWebアプリケーションを作るフレームワークがあるらしい.

 -> Wicket入門 - JavaとHTMLだけで作るWebアプリケーション
  ※MYCOM PCのサイト、連休明けからMYCOMジャーナルに変わっ
   ていた. レイアウトが見難くなった…のは気のせいですw

 通常、JavaでWebアプリケーションを作ると言えばJava(Servlet)+JSPだと思っていたのですが、どうもこのWicketと言うFrameworkは、純粋にJava(Servlet)+HTMLで構築出来る模様.
 これでロジックとデザインを(ほぼ)完全に分離可能.

 興味があるので後で記事を詳しく見てみる予定.

 どうでも良いですが、最近急にJavaなんて勉強し始めたもんだから、頭の中が「何?VB?VB.Net?Java?PHP?JavaScript?C?むしろC#?」的なゴチャゴチャになっております orz
 複数言語を完全マスターしてる人の頭の中が見てみたい orz
posted by KIMAGURE at 09:35| 曇り| Comment(0) | TrackBack(0) | Javaを一から勉強 | このブログの読者になる | 更新情報をチェックする

2006年05月08日

MVC型Frameworkを理解してみる - 2.

 う〜ん…前回ビール飲みながら書いたが為に、意味が分かりにくい orz
 そう言いつつ今日もビール飲んで書いてるし orz
 しかも意味不明の「空腹のはずなのに満腹感」というか「胃が膨らんでいる様な感じ」で具合悪いので半分寝込み気味 orz

 ま、所詮は自己記録.
 気にせずテキトーに続けます.

 先ずは前回の補足から.

 前回、MVCとは

  Model … Javaで言うならJavaBeans
  View … Javaで言うならJavaServer Page(MyFaces)
  Controller … Javaで言うならJava ServerFace
  ※翌朝追記:MyFacesはApacheのJSP Project.

 の3パーツでアプリケーションを構築する考え方だ、と書きました.
 が、この3つのパートの関係性ってどうなっているのか. それ以前にそもそも、ControllerからModel/Viewをどの様に呼び出すのか、という事に一切触れずにディレクトリ構成に話が飛んでしまっていました orz

 前回の最後に少し書きましたが、Frameworkは基本的にrequire(include)+Class宣言の連鎖(?)で成り立っています.
 これを補足して、Class概念を踏まえて書くと次の通りです.

[フロントコントローラ]
 | (require)
 +- [class Controller]
   | (require + class宣言 + 参照)
   +- [class Model]
   |  | (require + extends class宣言)
   |  +- [class UsersModel]
   | (require + class宣言 + 参照)
   +- [class View]
      | (require + extends class宣言)
      +- [class UsersView]


 中身を極簡素に(パス等は一切考えずに)書くと

 [index.php](フロントコントローラ)
 require_once('controller.php');
 new Controller();
 // ※↑実際のindex.phpも記述はrequireとClass宣言だけ.
 //  ただし、実際にはcontrollerの引数として「action」等を
 //  指定.


 [controller.php]
 class Controller
 {
  var $MODEL; //-> Framework Model
  var $VIEW; //-> Framework View
  //-> constructor
  function controller() {
   require_once('model.php');
   $this->MODEL =& new Model($this);
   require_once('view.php');
   $this->VIEW =& new View($this);
  }
 }


 [model.php]
 class Model
 {
  var $CONTROLLER;
  //-> constructor
  function &model($controller) {
   $this->CONTROLLER =& $controller;
  }
 }


 [view.php]
 class View
 {
  var $CONTROLLER;
  //-> constructor
  function &view($controller) {
   $this->CONTROLLER =& $controller;
  }
 }


 ※「function &〜」は参照渡し. オブジェクトを扱う場合は参照渡しが
  基本です.
  ここで言うオブジェクトはmodel/view等のClassを意味します.
  詳しくは
   -> Zend Japan コーディング指針
  参照が吉.

 と言う様な関係です.
 Controllerは自分自身の変数にModel/Viewのオブジェクトを保持し、各Model/Viewは自分自身の変数に親であるControllerを保持しています(共に参照).
 親(Controller)は子(Model/View)を参照し、子は親を参照する.
 非常に強い依存関係を持っています.
 こうする事で、Application全体がFramework(目に見える様に書くとController)と言う器の中で生成/実行される事になり、ある程度の統一的なコードが保証される事になります.


 では…index.php(例の場合です)の不思議について考えて見ます.
 ユーザーから呼び出されるPHPファイルは、フロントコントローラである「index.php」のみで問題無く動作します(勿論複数のファイルを用意しても問題ありませんが).
 何故か?
 以下の極簡素にしたコードで例を.
 ※以下の例では短くする為に、Model/Viewを基底Classとユーザー定義
  Classの別なく書いています.

 [index.php](フロントコントローラ)
 require_once('controller.php');
 new controller('index_Action');
 // ※↑今日は無理ですが、必要に応じて更にApplication名も
 //  セットしたりします.


 [controller.php]
 class Controller
 {
  var $MODEL; //-> Framework Model
  var $VIEW; //-> Framework View
  //-> constructor
  function controller($szActionName) {
   /**
    * Set action.
    * 否定の!を使わずfalseを使っているのは、VB等の他言語を
    * 同時に書く場合に見やすいから. 単なる好みですw
    */
   if ((isset($_REQUEST['action']))&&
     (empty($_REQUEST['action']) == false))
    $szActionName = $_REQUEST['action'];
   /**
    * Set model and view name.
    */
   $szModelName = str_replace('_Action', '_Model', $szActionName);
   $szViewName = str_replace('_Action', '_View', $szActionName);
   /**
    * Include and declare.
    * 見難いですが、宣言するClass名は変数の値を参照.
    * new $szModelName <-> new index_Model
    */
   require_once($szModelName . '.php');
   $this->MODEL =& new $szModelName($this);
   require_once($szViewName . '.php');
   $this->VIEW =& new $szViewName($this);
  }
 }


 [index_Model.php](Modelクラス継承)
 class index_Model extends Model
 {
  var $CONTROLLER;
  //-> constructor
  function &model($controller) {
   $this->CONTROLLER =& $controller;
  }
 }


 [index_View.php](Viewクラス継承)
 class index_View extends View
 {
  var $CONTROLLER;
  var $ACTION;
  //-> constructor
  function &view($controller) {
   $this->CONTROLLER =& $controller;
   //-> Rendering
   $this->renderingTemplate();
  }

  function renderingTemplate() {
   $this->ACTION = 'test_Action';
  }
 }


 [template.php(とかtemplate.tpl等)]
 ※以下面倒なのでかなり省略w
 <html>
  <body>
   <form target="_self" method="post">
    <input type="hidden" name="action"
     value="<?php echo $this->Action; >">
   </form>
  </body>
 </html>


 あくまでもMVC型Frameworkの構造を理解する為の記録ですので、極簡素な流れになっていますが、実際のFrameworkの中身はもっと複雑です.
 と言うか、Template Engineの記述を使って書くと余計な説明が増えるので、ダイレクトにPHPで出力と言う無茶振りw
 一番最初にユーザーからフロントコントローラが呼び出された際は、単純に「このアプリケーションで一番最初に実行すべき処理 = 一番最初のアクション」をControllerClassの引数として指定します.

 MVC003.png

 最初のAction(例ではindex_Action)に呼び出されたControllerは、index_Actionに対応したModelとViewを呼び出し、Viewは次のActionを指定します(例ではtest_Action).
 で、結局この「test_Action」が指定され、Viewによって描画された元ファイルは「index.php」な訳です.
 test_Actionの次の処理が呼び出されても、結局index.phpです.
 その為、ユーザーから直接読み込まれるPHPファイルを意図的に複数用意しないのであれば、直接読み込まれるのは1ファイルで十分、という事になる訳です.

 ここまで来て、ようやく前回のディレクトリ構成に繋がりましたw

 [htdocs(apache document root)]
  +- index.php(フロントコントローラ)
 [Framework(apacheが読み込めるDirectory. Document root下でも可)]
  +-[application directory]
    +-[model]
    +-[template]
    +-[view]
  +-[classes]
    +-[各class]
  +-[controller]
    +- controller.php(コントローラ)


 上記例の場合、直接読み込まれるのは「index.php」のみですから、把握しやすい様に[htdocs]と[Framework]ディレクトリに分離しています.


 と、具合悪いしそろそろ寝ます.
 …って前回の補足で終わってしまった orz
posted by KIMAGURE at 23:27| 曇り| Comment(0) | TrackBack(0) | PHP | このブログの読者になる | 更新情報をチェックする

MVC型Frameworkを理解してみる - 1.

 何事もなかったかの様に久しぶりに書き込み.

 …と言いつつも愚痴.
 実際は仕事も楽になりつつある訳ですが、精神的にはダメージが回復し切れていなかったりして、連休中は引きこもりの様に家で寝たきり生活 orz

 と、やはり愚痴から始まってしまった事は気にせず本題.

 前回の投稿でも書きましたが、やはりPHPのコードを書く際に型に嵌める、汎用性の高いコード、スマートなコードを書くにはFrameworkを使うのが一番です.
※PHPの様なスクリプト言語は、簡単に、適当に書いても動く素晴らしい言語分野ですが、逆に言えば「コードに統一性が無くなり易くもある」という事です.

 勿論Template Engineを使う、簡単に表現するなら「表示と処理を分離する処理」も非常に効果的ですが、根本的にFrameworkを使わなければTemplate Engineの性能を最大限に生かす事が出来ません.
 何より表示と処理(ロジック)を分離しても、処理部分のコードに統一性が無ければスマートなコードを書く事が出来ません.
 更に言えば、FrameworkはFrameworkでも、本当の意味でのFrameworkを使う事で、Classライブラリには無い統一性を得る事が出来ます.

 Class Libraryとは、複数のClass(ある関連性を持った処理を一つのオブジェクトとして捉え、複数の処理を一つの部品として扱う書き方)をまとめ、ツリー状に構成したコードの集まり.

 [Classライブラリ1]
  +-[ClassA]
  +-[ClassB]
  +-[ClassC]

 または

 [Classライブラリ2]
  +-[親Class]
    +-[ClassA]
    +-[ClassB]
    +-[ClassC]

 ClassライブラリとFrameworkは非常に近しい関係で、一部Classライブラリと等価に定義される事もある様です(KIMAGURE自身、底辺中の底辺なので理解しきってませんがw).

 [Framework]
  +-[ClassA]
  +-[ClassB]
  +-[ClassC]

 上記がClassライブラリと被っているケースです.
 真の意味ではFrameworkでは無いと思うのですが、Webに転がっているコードの中には、上記の様な構成でFrameworkと呼ばれている物もあります(Zend Frameworkもこれ?).
 この例およびClassライブラリと本体コードの関係は

 [本体コード] - [Classライブラリ/Framework]
          +-[ClassA]
          +-[ClassB]
          +-[ClassC]

 です.
 一方の被っていないケースは

 [Framework]
  +-[ClassA]
  +-[ClassB]
  +-[ClassC]

 こう見ると同じですが、本体コードとの関係を見ると違いが分かります.

 [Framework]
  +-[ClassA]
  +-[ClassB]
  +-[ClassC]
    +-[本体コード(またはClassA等と同位置)]

 …違いが分かりにくいか orz
 Classライブラリに近しいFrameworkは、「本体コードからFrameworkを使う」のに対し、Classライブラリと明らかに異なるFrameworkは「Frameworkから本体コードを派生させる」という違いです.
 つまり、ClassライブラリおよびClassライブラリに近しいFrameworkは、本体コードが親ですが、一方のFrameworkはFrameworkが親で、本体コードが子となります.

 …こ、これ以上KIMAGUREには解説不能なので、ここを偶然見た方は「Frameworkとは」で検索して下さいw
 面倒な方は

 -> Frameworkとはなんぞや?

 を見ると吉.
 非常に簡潔、且つ分かり易く説明されていらっしゃいます.
 正直、KIMAGUREの説明を読むより数百倍分かり易いですw


 で、実際にPHPでFramework(後述MVC型)を使うとなると

  ・Mojavi(モハビ)
  ・Struts
   ※追記:失礼.
       現在Java勉強中で頭がゴッチャになってました orz
       Struts自体はJavaのMVC型Frameworkです.
       元々、WebアプリケーションにおけるMVCは、Javaが
       盛んです.
  ・Ethna(Struts派生の国産Framework!)

 当たりでしょうか.
 これらを使うのが一番賢い訳ですが、KIMAGUREの様に底辺レベルの人間には、いきなり「Frameworkを使うぜ!」と意気込んでも構造事態を理解していないが為に、その利便性を使い切る事が出来ません orz


 …と言う事で、自分で簡単なFramworkを作ってみれば理解出来るんじゃね?という安易な考えの下、構造だけのFrameworkを作ってみる事に.
 勿論単純なのでDIコンテナなんて考慮しません.
 と言うか、JavaではDI[Dependency Injection](依存性注入)が大流行中の様ですが、KIMAGUREには全然理解出来ません orz

 特に今回はコードの統一性、メンテナンス性、スマートなコード、と言う事を考えて「MVC型Framework」を作ってみます.

 [MVCって何さ?]
  MVCとは、アプリケーションを
   ・Model
   ・View
   ・Controller
  という3つのパーツに分けて考えるコードの構成方法です.
  それぞれの意味は
   ・Model    … ロジック部分. 要するに実際の処理を行う部分.
            DBへの接続や計算、実行処理を司るコードです.
   ・View    … 描画処理部分. Modelで処理したデータを描画用
            に加工したり、Template Engineに値をセットし
            たりするコードです.
   ・Controller … ユーザーから要求された際に、最初に処理され
            る部分.
            Controllerが読み込まれ、どのModelを呼び出し、
            どのViewで描画するのかを振り分ける入り口に
            なります.

 MVC001.png

 簡単に書くと、上図の様になりますが、実際には各処理毎にModelおよびViewが存在し、それらの行方を指揮するのがControllerとなります.

 MVC002.png

 また、各Model/ViewはFrameworkが定義する親Model/Viewから派生させて作成します.
 例えば、

 [class - ModelClass(親)]
  class ModelClass
  {
   /**
    * class constructor.
    */
   function ModelClass() {
    startModel();
   }

   function startModel() {
   }
  }

 [user class - UserModelClass(子)]
  class UserModelClass extends ModelClass
  {
   function startModel() {
    echo 'TEST';
   }
  }

 ※「extends」はClassの「継承」を意味します.
  継承とは、親Classを子Classに引き継ぐ事を意味します.
  上記の場合、[UserModelClass]と言う子Classが[ModelClass]と言う
  親Classを継承しています.
  詳しくはPHPのヘルプを参照して下さい.


 と言う様に、あくまでも「Frameworkが親で、本体コードは子」という関係を崩さずにアプリケーションを構築する事に意味があります.
 この決まりを厳守する事で、破綻が比較的少ないスマートっぽいコードが書けます.
 ※「比較的」とか「っぽい」とか曖昧な表現を使っているのは、結局
  最終的に実コードを書く際に、面倒がらずにキチンと書く様にしな
  ければ意味が無いから.

 それら(MVCの構造・流れ)を踏まえて、まず最初にディレクトリ構造を考えて見ます.
 通常のPHPアプリケーションの構造を考えてみると(Webサーバーがapacheの場合)、

 [htdocs(apache document root)]
  +-[application directory]
    +-[source code]
      +-[class library(include_dirに設置する場合もあり)]

 です.
 Frameworkでも基本的に同等の構成で実現出来ますが、KIMAGUREの様な底辺人には、次の様な構成が分かり易いかと.

 [htdocs(apache document root)]
  +- index.php(フロントコントローラ)
 [Framework(apacheユーザーが読み込めるDirectory. Document root下でも可)]
  +-[application directory]
    +-[model]
    +-[template]
    +-[view]
  +-[classes]
    +-[各class]
  +-[controller]
    +- controller.php(コントローラ)

 ※フロントコントローラ…要するにControllerを呼び出す最初のページ

 何もFrameworkのディレクトリにアプリケーション用のディレクトリを入れる必要はありませんが、こちらの方がパッと見分かり易いので、今回はこの構成に.
 因みに「アプリケーション用のディレクトリ」と書いてますが、実際にブラウザから呼び出されるページは「/htdocs/index.php」であり、「/Framework/application directory」ではありません.
 つまりこうです.

  index.php(フロントコントローラ)
   ↓[require]
  Framework/controller/controller.php
   ↓[require]
  Framework/application directory/model/A.php
   ↓[controllerに戻る]
  Framework/controller/controller.php
   ↓[require]
  Framework/application directory/view/A.php
   ↓[require]
  Framework/application directory/template/A.php

 index.phpからすべてrequire(include)で読み込まれる訳で、ダイレクトにFramework配下にアクセスする訳では無い、と言う事です.


 …と、そろそろ寝る時間が orz
 続きは後日時間のある時に記録.
posted by KIMAGURE at 00:15| 曇り| Comment(0) | TrackBack(0) | PHP | このブログの読者になる | 更新情報をチェックする

2006年04月24日

PDFLibのライセンスファイル指定が再起動で再読み込みされないのをどうにかしてみる.

 と言う事で、PDFLibのライセンスファイルを指定する場合は、

 1. PDF_set_parameterで指定
 2. export PDFLIBLICENSEFILEで指定(Linuxサーバー上の場合)
 ※Windows版はPATH環境変数に追加するんでしょうか?

 の方法がある訳ですが、一々記述するのが面倒なのと、後で別のシステムを入れる事になった場合に楽だという事で、初めて2番目のexportで指定する方法を選択.
 コードを書き書きする必要が無いので非常に楽!

 がしかし、この方法には落とし穴がありました orz
 通常、exportコマンドで環境変数を追加した場合は、ログアウトすると消えてしまいますので~/.bash_profileや~/.bashrcに追記したりします(サーバーを再起動する度に客先に行く訳にもいきませんしw).
 KIMAGUREもこの方法で

  export PDFLIBLICENSEFILE=/[path]

 と~/.bash_profileに追加してやりました.
 そして徐にサーバーを再起動.

 ……だ、駄目じゃん orz

 何故か駄目です.
 ちゃんと echo $PDFLIBLICENSEFILE とコマンドするとパスが表示されますし、source ~/.bash_profile してあげれば(←再読込)正常にライセンスファイルを認識してデモスタンプが消えるのですが(PDFLibはライセンスを購入していない場合、デモ用のスタンプが表示される)、sourceしないと.bash_profileだけではログイン時に自動認識してくれません.

 -> .bash_profileに記述する事でShellにはパスが正常に認識
 -> Shellはパスを認識しているが、PDFLibには認識されていない
 -> ログイン後source ~/.bash_profileでPDFLibに認識される

 …何故??
 さてどうした物か…と考えてみるものの、KIMAGUREのうす〜い知識では何も出て来ませんw
 そこで他力本願.
 知人に電話して何か良い方法が無いか聞いてみた所、『Apacheの起動スクリプトに直接書いてあげれば?』という答えが帰ってきました.
 ※知人はPDFLibを触った事がありません.

 成るほど……KIMAGUREには一切思いつかない方法です orz
 言われてみれば確かに.
 PDFLibがメモリに読み込まれるのは、

  Apache -> PHP -> PDFLib

 という流れですから、最初のプロセスであるApacheが起動する段階でパスを認識させてあげれば、最終的にPDFLibが読み込まれる時点で認識されるのでは?という考えです.
 で、早速試しに

 [unknown@redhat]# vi /etc/init.d/httpd

  export PDFLIBLICENSEFILE=/[path]

 と追記してサーバーを再起動してみると…華麗に認識!!
 流石です.
 流石です○○さん!!

 ……って、KIMAGUREが駄目過ぎか… orz

 しかし今回は勉強になりました.
 起動プロセスの流れを考慮する事が大事!と身に凍みた備忘録.
posted by KIMAGURE at 19:29| 曇り| Comment(1) | TrackBack(0) | PHP | このブログの読者になる | 更新情報をチェックする

2006年04月21日

地獄期間の名残.

 orz


 という訳でこの一週間、朝8時半から夜12時まで働く生活を送っていたという密かな苦しみを味わいつつ思い至る.

 『しっかりしたコード書けよ』

 Javaがあーだこーだ言う前に、しっかりしたコードを書ける様に成りなさい、と誰かから言われているかの如く、自分で書いたコードに自分で苦しむ一週間.
 明日・明後日(土日)も家で仕事をする羽目になりましたが、何とか収拾がつきそうです(本当は家で仕事なんてしたらいけませんが).

 で、効率的にコードが書ける様にするにはどうしたら良い物か…

 結論は出ています.
 しっかりした仕様書、設計書、UML図に従って書いていけば、それなりのコードが出来上がります.
 しかしながら、KIMAGUREの勤める会社は最低ランク(他業務の片手間
部署)なので、しっかりした仕様書等を書くレベルなど持ち合わせていません orz
 おまけにKIMAGURE自身、仕様書等を書くのが苦手というか下手過ぎるので、自分でもどうこう出来そうにもありません(書くと必ず必要な部品が抜ける→継ぎ足して矛盾発生→修正→矛盾発生…エンドレス).
 正に底辺中の底辺ですw
 仕様書・設計書・UML図の勉強もしなければ…
 正直、最近では仕事で案件のみに取り憑かれた様に盲進するより、転職して趣味でやっていた方が色々と覚えられるんじゃないかと思えてきましたw

 と言う事で仕方なし.
 レベルの低い設計でも矛盾無く作り上げるには、『型に嵌める』しかないのでは無いかと.
 そうなるとFramework?
 でもFrameworkだけでは実コード部分でまた、矛盾というか無駄というか汚いコードが出来上がりそうだし、かと言ってFramework+Templateエンジンで書くと、逆に制限が邪魔になりそう.

 あ〜シンプルかつ効率的かつ美しいコードが書ける頭が欲…し……100%文系頭のKIMAGUREには無理か orz


 といういつにも増した愚痴.

 コツコツと自分なりに型の嵌め方を見つけて行くしかなさそうな予感がします.
 取り敢えず、入り乱れた汚いコードになるよりましだと思うので、完全にコードとデザインのロジックを分離する為に、自分に合ったTemplateエンジンを探しますか…
posted by KIMAGURE at 20:14| 雨| Comment(0) | TrackBack(0) | 雑記 | このブログの読者になる | 更新情報をチェックする

2006年04月16日

で、結局Java環境って何なのさ.

 やはり妥協してインスタントを飲むなら香味焙煎がいい.

 はい.
 一切関係ありません.

 Javaとは何ぞや、という事を調べずにJavaを触ってみて玉砕した訳ですが、ここに来てようやくJavaについて調べてみようかと.


>> Javaとは

 今更KIMAGUREが書かずとも、至る所に「Javaとは」というタイトルで情報が転がっています.

 散在した情報をさらっと読んで勝手に要約すると、Javaとは(Sun Microsystems社が)『C言語を参考にしてオブジェクト指向、クロスプラットフォームを実現した実行環境・開発言語』らしい.

 Javaはある主のインタープリタの様です.
※インタープリタとは、C言語等の様に完全にコンパイルされたアプリケーションでは無く、アプリケーション実行時にRuntime等によりコンパイルしながら実行される方式.

 KIMAGUREの今までのJavaに対する知識は、「JavaってJava本体がミドルウェア的な緩衝材になって、OSに関係なく同一のプログラムが動作するんだよね」という、実に単純な知識のみでした.
 じゃあ、どうやってJavaは同一のコード(※正確には同一コードで動かないケースが殆ど. 各OSに合わせて多少の改変が必要らしいです)を各OS上で走らせているのか、なんて考えても居ませんでした.

 Java製アプリケーション自体は、コンパイル処理によって作り出された中間ファイルであり、アプリケーションを配布する場合は、それら中間ファイルを配布しているそうです.
 利用者は配布された中間ファイルを実行するために、各OS用のJava Runtimeを導入し、そのJava Runtimeが中間ファイルを各OSに沿った形でコンパイルして実行する様です.
 …一回は否定しましたが、やっぱり.Net Frameworkと概要は同じ様ですw

 これで、Javaの大概要は何となく分かってきました.
 ……ん?じゃあ、よく見るJREとかJ2SEとかJ2EEって何なのさ?という事で調べてみた.


>> Java環境

 よく目にする、Javaランタイムという言葉.
 上にも書いた様に、Javaで開発されたアプリケーションを実行するには、各OS上で動作するRuntime(ランタイム)が必要です.
 このランタイムに当たるのがJREです.
 正式名称はそのままJava2 Runtime Environmentです.
 ん?
 Java2って事は、Java1とJava2があるのか?
 と思いますが、現時点で使用されている物は殆どJava2の様です(本当かどうかは曖昧…).
 ただ、JDK(Java Development Kit)はJDK1.xだったりします.

 それにしてもJavaのバージョン表記が紛らわしい.
 Java2 1.5って… orz
 Javaを知らないKIMAGUREから言わせると、「で、それってバージョン2なの?バージョン1なの?」って事になりますw
 結果的に、JavaとJava2は全くの別物と考えて、「Java2」という環境のバージョン1.5、と深く考えずに把握する事にしました.
 深く調べていくと、更に時間がかかりそうですし、これから始めるのに関係するのは「Java2」だけですから.
 ただこのJavaのバージョン名称、周囲の評判が悪かったらしく、最近名称変更した様です.

  -> J2SE 5.0

 ……余計分からなくなったよ orz
 何ですか、そのいきなりバージョン5って.
 あれですか、ソースネクストのいきなりシリーズですか? orz
 という事で、次期バージョン(バージョン6)から更に名称変更になる様です.

  -> Java SE 6

 ……余計分からなくなったよ orz
 何ですか、そのいきなりJava2からJavaに戻るって.
 あれですか、ソースネクストのいきなりシリーズですか? orz
 結局バージョンについてはもう少し勉強が必要なようです.

 じゃあ、JREとJ2SE、JDK、J2EEって何が違うのさ?という本題.
 調べてみた所、余計混乱している訳ですが、KIMAGUREは次の様に理解(間違えてるかも).

  ・JRE  … Java 2 Runtime Environment, Standard Edition.
        Java実行環境. Javaアプリケーションを利用する
        環境に於いて必須.
  ・J2SE … Java 2 Platform Standard Edition.
        標準Javaアプリケーションの機能を実現する為の
        環境.
        J2SEにはJ2REが含まれている.
  ・JDK  … Java Development Kit.
        Java2開発環境.
        今までJDK1.4とかって言う名称からJDK 5.0に変更
        したらしい.
        正確にはJ2SE JDKとかJ2EE JDKとかある様です.
  ・J2EE … Java 2 Platform Enterprise Environment.
        エンタープライズ用Java2環境.
        Webアプリケーションを作る場合に必要な様です.
        これで作られたシステムはJSP(Java Server Pages)
        になる.
        J2EEにはJ2REが含まれている.

 こんな所ですか.
 J2REとJ2SEの違いがいまいち分かりません.
 標準のJavaアプリケーションはJ2REが導入されていれば良い様ですが…?
 どうも、J2SE/J2EEとJDKは位置づけが異なる様です.

  J2SE
   ・JRE(Java SE Runtime Environment)
   ・JDK(Java SE Development Kit)

 という様にJ2SEは枠組みの名称らしい.
 Sunのダウンロードサイトを見ると、



 [省略] download sites for the versions of the Java Platform, Standard Edition (Java SE, formerly known as J2SE) platform that are currently available. At each of the sites, you can download the Java SE Development Kit (JDK), Java SE Runtime Environment (JRE)[以下略]



 あれ?JREってJava 2 Runtime Environment, Standard Editionじゃ…
 分かりにくいなぁ(泣

 頭が混乱してきたので、本日はここまでで終了.
 先が思いやられます orz



 関係ありませんが、知人に昔VB/Accessでプログラムをしていた人が居て、先日その人と電話で「オブジェクト指向」という言葉が出てくる会話の流れになったのですが、明らかに「オブジェクト指向」を「グラフィカルに開発できる何か」的な思い込みをしている様でした.

 …そ、それ違いますからぁぁぁぁ! orz

 とは言えず(プログラム歴数年のKIMAGUREが、限定的とは言え10年以上プログラム歴を持つ人にあーだこーだ言えません)、遠まわしに「オブジェクト指向」について調べてみましょうと伝えました.
 だって、その考え方だとVBこそがオブジェクト指向の代表になってしまいますw
 しかし、実際にはJavaがオブジェクト指向の代表格です.
 ま、VBをClassメインで書いていくと、ある程度オブジェクト指向になりますが.


※以下、底辺なKIMAGUREの乏しい知識から書いてるので、間違っている可能性大.

 『オブジェクト指向』って何さ…
   C++に代表される、一つの構成要素を「オブジェクト」として
  扱い、プログラムはそれらのオブジェクトを使用する.
   分かりにくい.
   例えば、コーヒーまたは珈琲(同じ).
   ペーパードリップで珈琲を飲もうと思えば、

    1. 淹れる量を決める
    2. コーヒーミルに豆を入れる
    3. ミルを手動で動かす
    4. 豆を自分好みに挽く
    5. ドリップペーパーに挽いた豆を入れる
    6. ケトルに水を入れる
    7. ケトルをコンロにかける
    8. 沸騰したらひと冷まし
    9. ドリッパーに豆が湿る程度にお湯を注ぐ(時計回しに)
    10.30秒〜45秒後に必要な量のお湯を注ぐ(時計回しに)
    11.完成

  という結構な手間がかかります.
   この珈琲を飲むまでの一連の流れをオブジェクト指向的に捉えて

    ・ミルオブジェクト
    ・ケトルオブジェクト
    ・ドリッパーオブジェクト

  に分け、豆、水を引数としてみると面白…い?
   ミルオブジェクトには

    ミルオブジェクト
     - 使用可能量
     - 挽く方法(手動・電動)
     - 挽き方(細挽き、中挽き、粗挽き)

  という要素が浮き上がってきます.
   こうした要素を一つのオブジェクトとして考え、プログラム
  本体(ここでは人)はオブジェクト単位で利用します.

    ミルオブジェクト
    ミルオブジェクト.使用可能量を取得
    ミルオブジェクト.使用可能量内の豆を入れる
    ミルオブジェクト.挽き方指定
    ミルオブジェクト.挽く

   こうしてミルオブジェクトに渡された豆は、適切に処理され
  た結果として出力されます.
   別にオブジェクト指向的に考えなくても、最終的に同じ結果
  をもたらす事が出来ますが、オブジェクト指向的に考える事で、
  流用性、統一性、把握しやすさが格段に向上します.
   ……ますます分かりにくい orz


 『クラス』って何さ…
   珈琲をクラス化って…
   全自動コーヒーメーカー登場.
   オブジェクト指向的に考えると、「全自動コーヒーメーカー
  クラス」になり、デザインパターンで言う所のIteratorに当た
  る…のかは不明.
   コーヒーメーカーだと
    1. 淹れる量を決める
    2. 豆を入れる
    3. 水を入れる
    4. スイッチを入れる
    5. 完成
  という至って単純な構成になります.
   内部を見ていきましょう.
   全自動コーヒーメーカークラスには

    ・ミルオブジェクト
    ・ケトルオブジェクト
    ・ドリッパーオブジェクト

  が内包されています(インスタンス).
   内包されてはいますが、利用者は中身を殆ど気にする事はあり
  ません.
   全自動コーヒーメーカーの使い方さえ知っていれば、別にミル
  オブジェクトの使い方なんて知らなくてもいいですから(全自動
  コーヒーメーカークラスはIteratorっぽいので).
   これこそ、オブジェクト指向/クラス化の利点です.
   中身であれこれやっていますが、利用側は簡単な手順を踏むだ
  けで複雑な処理が可能になります.
posted by KIMAGURE at 18:44| 曇り| Comment(0) | TrackBack(0) | Javaを一から勉強 | このブログの読者になる | 更新情報をチェックする

2006年04月11日

JavaでPDFに電子署名してみる.

 「Javaとはなんぞや」を調べるって言ってたのに、やってる事違います orz

 ちょっとPDFへの電子署名について調べる必要があって、色々と調べていたのですが、どれもこれもビシっとしたシステム導入パックになっていて、100万円前後の高価なシステムばかり.
//※帰宅後追記:↑はLinuxサーバー上で動作する物を意味しています.
// クライアント用やWindowsサーバー上で動く物であれば、ある程度
// 低い価格で購入できる様です.

 当然KIMAGUREが居る会社の様な、極小会社には高嶺の花……と思っていたのですが、「開発用途」に絞ってみるとJavaで面白そうなライブラリが販売されていました.

 -> Big Faceless PDF Library(以下BFOPDF)

 このJavaライブラリ(と言うのかどうか、Java経験2時間弱のKIMAGUREには不明w)を使うと、新規にPDFは作れるし、既存のPDFに電子署名する事まで出来るとか.
 …あくまで、KIMAGUREの幼稚園レベルの英語力を信じるのであれば、ですが.

 そこで、早速フリートライアルをダウンロード.
 と、Javaのライブラリ導入方法を知らない事に気付く orz
 検索してみると、Eclipseで導入するには、

  1. Javaプロジェクトを作る
  2. パッケージエクスプローラで作ったJavaプロジェクトを右クリック
    →[プロパティ]
  3. プロパティウィンドウで
    [Javaのビルドパス]
     →[ライブラリ]タブ
      →[外部JARの追加]

Eclipse010.JPG

 で、プロジェクトエクスプローラにbfopdf.jar(今回見つけたPDFのライブラリ)が追加されました.

Eclipse011.JPG

 ちなみに、前回までEclipseの各ペインの呼称が分かりませんでしたが、左のツリー部分が「プロジェクトエクスプローラ」、メインのコード表示部分が「エディタ」、右ペインが「アウトライン」でした.
 …はいそうです. 思い切り各ペインのタブに書いてありました orz

 これでBFOPDFが使える様になりました.
 …で、どうやって?(汗

 どうも、Javaは独自(自分で作ったか、他人が作ったかはともかく)のライブラリは「org」で始まる名前空間(なのかクラス名なのかまだ知りません)で使えるという情報を検索で見つけ出しました.
 orgってoriginalの事でしょうかね?

 で、まずライブラリのヘルプから、電子署名部分のリファレンスを見てみると、先にJ2SE(JDK?)に付属している「keytool」というツールを使って、キーストアを作ってあげる必要があるとの事(今回はテストなので、当然Self-Signを使います. ベリサイン等を使う場合はkeytoolは不要かもしれません).
 Javaを導入しているのであれば、

  C:\Program Files\Java\jdk1.5.0_06\bin
  ※帰宅後追記: Runtimeのみ導入している場合は↓
   C:\Program Files\Java\jre1.5.0_06

 等に入っています.
 今回は全くJavaの事もkeytoolの事も理解していないので、ほぼリファレンスの通り、

  keytool -genkey -keyalg RSA -sigalg MD5withRSA
   -keystore C:\testkeystore -alias mykey
  ※↑本当は1行
 とタイプしてキーストアを作りました. 保存場所指定を変更しただけです.

 再びEclipse.
 先日の「Javaを初めて触ってみた.」で作った様に、メインファイルを作ります.
 今回は「test.java」としてみました. 何の捻りもないですw

Eclipse012.JPG

 あ、こんな事してないでさっさと帰宅しないと orz
 手短に続けます.

 今回書いたコードはサンプルを少し変えただけです.
 流用しないと何も書けませんのでw
 ただ、Eclipseはエラー処理していないと五月蝿いので、エラー処理も追加してみました(正しいかは別として).

/**
* Imports
*/
import java.security.KeyStore;
import java.security.GeneralSecurityException;
import java.io.*;
import org.faceless.pdf2.*;

public class test {
 /**
  * ほぼサンプルのまま宣言
  */
private static String pdfpass, keystorename, file;
private static char[] storepass, keypass;

private static String keystoretype="JKS", keystoreprovider=null, keyalias="mykey";
private static SignatureHandlerFactory handler = FormSignature.HANDLER_ACROBATSIX;

/**
* メイン
* @param args
* @throws IOException
* @throws GeneralSecurityException
*/
public static void main(String[] args)
throws IOException, GeneralSecurityException
{
  /**
   * 変数セット(サンプルを変更. 変数名はサンプルのまま)
   */
  keystorename = "C:\\testkeystore";
  keypass = "KIMAGURETEST".toCharArray();
  storepass = "KIMAGURETEST".toCharArray();
  file = "C:\\pdf.pdf";
  
  /**
   * キーストア存在チェック
   */
  File flKeystore = new File(keystorename);
  if (flKeystore.exists() == false) {
   System.err.println("Keystore isn't exist...");
   System.exit(0);
  }
 
  /**
   * キーストア読み込み
   */
  KeyStore keystore;
  if (keystoreprovider==null) {
   keystore = KeyStore.getInstance(keystoretype);
  } else {
   keystore = KeyStore.getInstance(keystoretype, keystoreprovider);
  }
  try {
   keystore.load(new FileInputStream(keystorename), storepass);
  } catch (IOException e) {
   System.err.println("Keystore didn't read...");
   System.exit(0);
  }
  
  /**
   * キーストアからサイン作成
   */
  FormSignature sig = new FormSignature(keystore, keyalias, keypass, handler);
  PKCS7SignatureHandler pkcs7 = (PKCS7SignatureHandler)sig.getSignatureHandler();
  sig.setName(FormSignature.getSubjectField(pkcs7.getCertificates()[0], "CN"));
 
  /**
   * PDF作成(指定ファイルが存在する場合は読み込み、無ければ新規作成)
   */
  PDF pdf;
  PDFPage page;
  try {
   InputStream in = new FileInputStream(file);
   pdf = new PDF(new PDFReader(in, pdfpass));
   in.close();
  } catch (IOException e) {
   pdf = new PDF();
   page = pdf.newPage(PDF.PAGESIZE_A4);
  }
  
  /**
   * サイン追加
   */
  sig.addAnnotation(pdf.getPage(0), 10, 800, 210, 700);
  pdf.getForm().addElement("Test Signature", sig);
  try {
   OutputStream out = new FileOutputStream("C:\\Sign.pdf");
   pdf.render(out);
   out.close();
  } catch (IOException e) {
   System.err.println("PDF didn't replace...");
   System.exit(0);
  }
 
} /*[ End - main ]*/
} /*[ End - CLASS ]*/


 このコードで、

Eclipse013.JPG

 こんな感じの電子署名付きPDFが作成出来てしまいました!
 素直に驚き.
 実物は[これ].

 実際に使えるかどうかは、サイトが全て英語、購入も全て英語、という厳しい環境なので分かりませんが、価格的には100万円前後する高価なシステムより遙かに安い10万円弱という点は魅力的です.


 さて、さっさと帰ろう orz

 次回こそは、「Javaとはなんぞや」という所から勉強します.

//===============================================
// 帰宅後追記
//===============================================
 よくよく考えると、PDFLibやFOPよりいい!
 FOPはフリーなので別次元かもしれませんが、Javaを使える環境であれば、PDFLibよりBFOPDFの方が良いかもしれません.
 価格的にも同等で、既存PDFの編集も出来そうですし(良く確認して無いので分かりませんが、少なくとも既存PDFを読み込める)、電子署名も追加出来ますので.
 PDFLibもPDIを使えば既存PDFを編集出来ますが、価格が15万弱です orz
 これでBFOの日本代理店があれば最高なのですが.

 取り敢えずもっと早くJava勉強を始めれば良かったと後悔中.
posted by KIMAGURE at 22:14| 曇り| Comment(0) | TrackBack(0) | Javaを一から勉強 | このブログの読者になる | 更新情報をチェックする

2006年04月08日

独学Java実習その2 - ボタンを付けてみた.

 先日、初めてJavaを触ってみた訳ですが(素のWindowを出しただけですw)、確かにコードに一部特徴的な所はある物の、他の言語をやっていたら、左程戸惑わないかも、と思っていました.
 ついさっきまでは orz

 先ほど帰宅して、また晩御飯を食べながら触ってみました(行儀が悪いですが、帰宅から就寝まで2時間程度しか起きていられないので…).

 本当は、「Javaとは何ぞや」という基本中の基本、本来触る前に調べるべき事を知ろうと思っていたのですが、その前にボタンだけでも表示してみたい!と、欲を出して先日のコードにボタン表示コードを追加してみました.

 書いたコードは

/**
* Imports.
*/
import java.awt.Frame;
import java.awt.Button;
// ↑ボタン用に追加. java.awt.*で宣言すると、個別に宣言しなくて
// も↓java.awt.event.*の様に大丈夫みたいです.
import java.awt.event.*;

public class TestWindow {
 /*[ 定数の宣言方法すら知らないので取り敢えず ]*/
 static int nWndHeight = 300;
 static int nWndWidth = 500;

 /**
 * @param args
 */
 public static void main(String[] args) {
  // TODO 自動生成されたメソッド・スタブ

  /*[ メインウィンドウとなるFrameを宣言 ]*/
  Frame frmMain = new Frame();

  /*[ ボタン宣言 ]*/
  Button btnTest = new Button("TEST");

  /*[ Frameからの情報取得用Listnerを宣言 ]*/
  frmMain.addWindowListener(
   new WindowAdapter() {
    public void windowClosing(WindowEvent wndEvent) {
     System.exit(0);
    }
   }
  );

  /*[ ウィンドウサイズ指定 ]*/
  frmMain.setSize(nWndWidth, nWndHeight);

  /*[ ボタン位置指定 ]*/
  btnTest.setSize(50, 25);
  btnTest.setLocation(10, 35);

  /*[ ウィンドウにボタン追加 ]*/
  frmMain.add(btnTest);
  //※上のfrmMain.addですが、最初普通にbtnTest.show()とやって
  // 見事に失敗しましたw
  // VB.Net的に考えて見て何とか実装出来ました.
  // VB.Netの場合は
  // frmMain.Controls.Add(btnTest)
  // です(同じ名称で宣言していた場合).
  frmMain.show();
 }
}

 で、ボタンが表示されるは…ず……

 Eclipse007.JPG

 ……な、何ぃぃぃ〜〜!! orz
 何故かボタンがWindowいっぱいに表示されています…何故?
 ちなみに、ボタンを追加する前は

 Eclipse006.JPG

 ↑この状態ですから、完全にWindowいっぱにフィットしています.
 VB.Netで言う所の、DockでFill設定している様な感じです.
 何か……とんでも無い事が起きましたw

 そこで検索してみると、どうもFrameクラスのsetLayoutメソッドでレイアウト情報を指定してあげないと駄目みたいです.
 良く分かりませんが、Javaの場合、オブジェクトは標準でWindowにフィットする仕様になっているのかもしれません.
 この辺は他の言語には無い特徴では?

 と言う事で、早速コード変更です.

/**
* Imports.
*/
import java.awt.Frame;
import java.awt.Button;
import java.awt.FlowLayout; //-> レイアウト用に追加
import java.awt.event.*;

public class TestWindow {
 /*[ 定数の宣言方法すら知らないので取り敢えず ]*/
 static int nWndHeight = 300;
 static int nWndWidth = 500;
 
 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO 自動生成されたメソッド・スタブ
  
  /*[ メインウィンドウとなるFrameを宣言 ]*/
  Frame frmMain = new Frame();

  /*[ ボタン宣言 ]*/
  Button btnTest = new Button("TEST");
  
  /*[ Frameからの情報取得用Listnerを宣言 ]*/
  frmMain.addWindowListener(
   new WindowAdapter() {
    public void windowClosing(WindowEvent wndEvent) {
     System.exit(0);
    }
   }
  );
  
  /*[ ウィンドウサイズ指定 ]*/
  frmMain.setSize(nWndWidth, nWndHeight);

  /*[ ウィンドウにボタン追加 ]*/
  frmMain.setLayout(new FlowLayout());
  frmMain.add(btnTest);

  /*[ ウィンドウ表示 ]*/
  frmMain.show();

  /*[ ボタン位置指定 ]*/
  // ※Frame表示前に位置指定しても反映されません.
  //  また、ウィンドウタイトルの縦幅が除外されないので、TOP
  //  位置を0にするとボタンがタイトルバーに隠れてしまいます.
  btnTest.setSize(50, 25);
  btnTest.setLocation(10, 35); 
 }
}

 これで普通に表示されました. 一安心ですw

 Eclipse008.JPG

 ちなみに、コード中のコメントで書いた、タイトルバーの縦幅を考慮せずに、TOP位置を10に指定した場合は↓こんな感じです.

 Eclipse009.JPG

 ま、この辺は他の言語でもある現象なのでいいのですが…タイトルバーの縦幅を取得する方法も調べないと駄目ですね orz

 しかし、次回からの自習は「Javaとは何ぞや」という所から勉強するつもりですので、しばらく実際にコードを書く事からは遠ざかるかもしれません.
 何せ、Javaの事は一切分かっていませんのでw


 という、備忘録というよりは記録.
posted by KIMAGURE at 00:26| 曇り| Comment(0) | TrackBack(0) | Javaを一から勉強 | このブログの読者になる | 更新情報をチェックする

2006年04月06日

JavaとVB.Net.

 昨晩、ちろちろとJavaを触ってみた、というのはビールを飲みながら書くという禁断の行為で既に投稿ずみです orz

 昨晩の記事「Javaを初めて触ってみた.

 あの後気付きましたが、普通に最小化、最大化出来ましたw
 Java2プラットフォームSEのヘルプページを見ていた時に、最小化が〜、Window状態が〜と書かれていたので、てっきり最小化・最大化も手動でやるのかと思っていました.
 で、よくよく見ると「Window状態を取得するには」というヘルプだったと.
 これはwindowListnerでは無くwindowStateListnerメソッドを使って、windowStateChangeを取得する……らしいですw
 ※ここに書いてある -> Javaヘルプの「WindowStateListner

 で、一晩経って昨日のJavaを触ってみた感想とVB.Netとの似ている点、違う点を今朝知人に送ったメールで代用.



※以下、言葉遣いが違うのは単純にメールをコピーしたからです.
///////////////////////////////////////////////////////
 おはようございまくもにーぐる.

 超能力捜査官ですよっ!!(意味不明

 昨晩帰ってから1時間ほど飯食いながらJavaをいじる.

 Eclipse起動.
 Eclipse使いにくい.
 何をどう作ったらいいのか不明.
 何かWindow出た.
 閉じるボタン押す.
 終了出来ない.
 タスクマネージャでjava何とかを終了.
 あ、Eclipseが終了した.
 半笑いでEclipse再起動.
 Eclipse実は使いやすい事に気付く.
 同時にJava無知のせいで使いにくいと思っていた事に気付く.
 頭をJavaJavaしてみる.
 addWindowListner?
 WindowAdapter?
 windowClosing?
 あ、終了出来た.

 以上。
 …なんじゃそりゃ?w

 Javaはそのままクラスを使えないらしい.
 VB.Netだと

 System.IO.File.Delete("C:\aa.txt")

 で通るけど、Javaは

 java.io.File file = new java.io.File("C:\aa.txt");
 file.delete(); //-> boolean

 って宣言してやらんと使えないと.

 Dim file As System.IO.File
 file.Delete("C:\aa.txt") '//-> boolean

 VB.Netでも上みたいに出来るけど、宣言せんでも使えるから
普段宣言してないし、Newも出来ない. StreamReaderとか使う場合は宣言するけど.
/*
※注釈) メールには書きませんでしたがこんな感じです.
 Dim srFile as System.IO.StreamReader = New System.IO.StreamReader("C:\aa.txt")
 srFile.ReadToEnd()
*/

 しかし、Eclipseのコード補完機能が結構優秀なんで、それなり
に書けてしまうかも…と思うのは気のせいだった orz

 インポートは酷似.

 import java.io.*;
 Imports System.IO

 この調子で(どんな調子だ?)隔日で1時間程度の学習を続け
るつもりです.
 そして5年後には初歩をマスターしてる予定です。
 5年後にJavaがまったく違う言語に遷移しているかも知れない
悪寒はストーブで解消.
///////////////////////////////////////////////////////
posted by KIMAGURE at 09:40| 曇り| Comment(9) | TrackBack(0) | Javaを一から勉強 | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。