View Javadoc

1   package rydeen;
2   
3   import rydeen.spi.ProcessorService;
4   
5   /**
6    * <p>
7    * 抽象処理器クラスです.{@link Processor <code>Processor</code>}にライフサイクルの概念が導入されています.
8    * </p><p>
9    * ライフサイクルは{@link Stage}クラスで表され,以下のように状態が遷移します.
10   * <pre> UNINITIALIZED
11   *     ↓ {@link #init() <code>init</code>}
12   * INITIALIZED
13   *     ↓ <em>{@link #prepare(Arguments) <code>prepare</code>}</em>
14   *     ↓ {@link #execute(TargetSource, Destination) <code>execute</code>}
15   * PROCESSING
16   *     ↓ <em>{@link #perform(TargetSource, Destination) <code>perform</code>}</em>
17   * PROCESSED
18   *     ↓ {@link #finish() <code>finish</code>}
19   *     ↓ <em>{@link #summarize() <code>summarize</code>}</em>
20   * FINISHED</pre>
21   * <p>
22   * 矢印の右に書かれている文字はメソッドを表しており,
23   * そのメソッドが呼び出されることで,ライフサイクルの状態が遷移します.
24   * 斜体で示されているメソッドが抽象メソッドであり,サブクラスでオーバーライドしなければならないメソッドです.
25   * その他のメソッドはfinal宣言されているため,オーバーライドできません.
26   * なお,状態は以降,ステージ,もしくはstageとして表記されます.
27   * </p><p>
28   * このオブジェクトが作成された直後のステージはUNINITIALIZEDです.
29   * initメソッドが呼び出されることにより,INITIALIZEDに移行します.
30   * なお,initメソッドからprepareメソッドを呼び出しますが,
31   * prepareメソッド呼び出しの直前にINITIALIZEDにステージは移行します.
32   * 続いて,executeメソッドが呼び出され,PROCESSINGステージに移行し,
33   * 自動的にperformメソッドが呼び出されます.
34   * そして,performメソッドの呼び出しが終了すると,PROCESSEDステージに移行します.
35   * 最後にfinishメソッドが呼び出され,finishメソッドからsummarizeメソッドが呼び出されます.
36   * summarizeメソッドの呼び出しが終了すると,FINISHEDステージに移行します.
37   * </p><p>
38   * この処理器には5つのステージが存在しますが,それぞれのステージで呼び出せるメソッドは限定されています.
39   * 呼び出し可能か否かを表したのが以下の表です.
40   * </p><p>
41   * 縦の列がステージを表しており,横の行が各メソッドを表しています.
42   * ○のセルがあるのは,その行にあるメソッドがその列のステージのときに呼び出せることを表しています.
43   * ×のセルの場合は,IllegalStateException が投げられます.
44   * </p>
45   * <table border="1">
46   *   <thead>
47   *     <th></th>
48   *     <th></th>
49   *     <th>UNINITIALIZED</th>
50   *     <th>INITIALIZED</th>
51   *     <th>PROCESSING</th>
52   *     <th>PROCESSED</th>
53   *     <th>FINISHED</th>
54   *   </thead>
55   *   <tbody>
56   *     <tr>
57   *       <td rowspan="6">情報取得</td>
58   *       <td>{@link #getProcessorName <code>getProcessorName</code>}</td>
59   *       <td>○</td>
60   *       <td>○</td>
61   *       <td>○</td>
62   *       <td>○</td>
63   *       <td>○</td>
64   *     </tr>
65   *     <tr>
66   *       <td>{@link #getProvider <code>getProvider</code>}</td>
67   *       <td>○</td>
68   *       <td>○</td>
69   *       <td>○</td>
70   *       <td>○</td>
71   *       <td>○</td>
72   *     </tr>
73   *     <tr>
74   *       <td>{@link #getCurrentStage <code>getCurrentStage</code>}</td>
75   *       <td>○</td>
76   *       <td>○</td>
77   *       <td>○</td>
78   *       <td>○</td>
79   *       <td>○</td>
80   *     </tr>
81   *     <tr>
82   *       <td>{@link #getId <code>getId</code>}</td>
83   *       <td>○</td>
84   *       <td>○</td>
85   *       <td>○</td>
86   *       <td>○</td>
87   *       <td>○</td>
88   *     </tr>
89   *     <tr>
90   *       <td>{@link #getArguments <code>getArguments</code>}</td>
91   *       <td>○</td>
92   *       <td>×</td>
93   *       <td>×</td>
94   *       <td>×</td>
95   *       <td>×</td>
96   *     </tr>
97   *     <tr>
98   *       <td>{@link #getSummary <code>getSummary</code>}</td>
99   *       <td>×</td>
100  *       <td>○</td>
101  *       <td>○</td>
102  *       <td>○</td>
103  *       <td>○</td>
104  *     </tr>
105  *     <tr>
106  *       <td rowspan="2">情報設定</td>
107  *       <td>{@link #setId <code>setId</code>}</td>
108  *       <td>○</td>
109  *       <td>×</td>
110  *       <td>×</td>
111  *       <td>×</td>
112  *       <td>×</td>
113  *     </tr>
114  *     <tr>
115  *       <td>{@link #putEntry <code>putEntry</code>}</td>
116  *       <td>×</td>
117  *       <td>○</td>
118  *       <td>○</td>
119  *       <td>○</td>
120  *       <td>×</td>
121  *     </tr>
122  *     <tr>
123  *       <td rowspan="3">処理メソッド</td>
124  *       <td>{@link #init <code>init</code>}</td>
125  *       <td>○</td>
126  *       <td>×</td>
127  *       <td>×</td>
128  *       <td>×</td>
129  *       <td>×</td>
130  *     </tr>
131  *     <tr>
132  *       <td>{@link #execute <code>execute</code>}</td>
133  *       <td>×</td>
134  *       <td>○</td>
135  *       <td>×</td>
136  *       <td>×</td>
137  *       <td>×</td>
138  *     </tr>
139  *     <tr>
140  *       <td>{@link #finish <code>finish</code>}</td>
141  *       <td>×</td>
142  *       <td>×</td>
143  *       <td>×</td>
144  *       <td>○</td>
145  *       <td>×</td>
146  *     </tr>
147  *     <tr>
148  *       <td rowspan="3">オーバーライド</td>
149  *       <td>{@link #prepare <code>prepare</code>}</td>
150  *       <td>×</td>
151  *       <td>○</td>
152  *       <td>×</td>
153  *       <td>×</td>
154  *       <td>×</td>
155  *     </tr>
156  *     <tr>
157  *       <td>{@link #perform <code>perform</code>}</td>
158  *       <td>×</td>
159  *       <td>×</td>
160  *       <td>○</td>
161  *       <td>×</td>
162  *       <td>×</td>
163  *     </tr>
164  *     <tr>
165  *       <td>{@link #summarize <code>summarize</code>}</td>
166  *       <td>×</td>
167  *       <td>×</td>
168  *       <td>×</td>
169  *       <td>○</td>
170  *       <td>×</td>
171  *     </tr>
172  *   </tbody>
173  * </table>
174  * 
175  * @author Haruaki Tamada
176  */
177 public abstract class AbstractProcessor implements Processor{
178     private Arguments arguments;
179     private Summary summary;
180     private ProcessorService provider;
181     private Stage stage = Stage.UNINITIALIZED;
182     private String id;
183 
184     /**
185      * 指定されたサービスプロバイダをもとに処理器オブジェクトを作成します.
186      * 
187      * @param provider サービスプロバイダ
188      */
189     protected AbstractProcessor(ProcessorService provider){
190         this.provider = provider;
191         this.arguments = provider.getDefaultArguments();
192     }
193 
194     /**
195      * この処理器の名前を返します.
196      * 
197      * @see ProcessorService#getProcessorName
198      */
199     @Override
200     public final String getProcessorName(){
201         return getProvider().getProcessorName();
202     }
203 
204     /**
205      * 現在のステージを返します.
206      * @return 現在のステージ.
207      */
208     public final Stage getCurrentStage(){
209         return stage;
210     }
211 
212     /** 
213      * <p>
214      * Idを設定します.
215      * </p><p>
216      * Idは1セッションの間に,処理器を互いに区別するための文字列です.
217      * </p><p>
218      * このメソッドはステージがUNINITIALIZEDの時だけ呼び出せます.
219      * ステージがUNINITIALIZED以外のときには,IllegalStateException が投げられます.
220      * </p>
221      *
222      * @throws IllegalStateException 状態がUNINITIALIZED以外のときに,このメソッドが呼び出された場合.
223      */
224     public final void setId(String id){
225         if(stage != Stage.UNINITIALIZED){
226             throw new IllegalStateException("expects UNINITIALIZED, but " + stage);
227         }
228         this.id = id;
229     }
230 
231     /**
232      * <p>
233      * 設定されたIdを返します.
234      * Idが設定されていない場合({@link #setId <code>setId</code>}
235      * が一度も呼び出されていない場合)はnullを返します.
236      * </p><p>
237      * このメソッドは例外を投げません.
238      * </p>
239      */
240     public final String getId(){
241         return id;
242     }
243 
244     /**
245      * <p>
246      * 初期設定を行います.
247      * ユーザ独自の初期設定を行う場合は {@link #prepare(Arguments) <code>prepare</code>}
248      * メソッドをオーバーライドしてください.
249      * このメソッドはfinal宣言されていますので,オーバーライドできません.
250      * </p><p>
251      * このメソッド呼び出し前は{@link Stage#UNINITIALIZED <code>UNINITIALIZED</code>}であり,
252      * 呼び出し後は {@link Stage#INITIALIZED <code>INITIALIZED</code>}になります.
253      * そうでない場合は,<code>IllegalStateException</code>が投げられます.
254      * </p>
255      * 
256      * @throws IllegalStateException 適切な状態でないときにこのメソッドが呼び出された場合.
257      */
258     @Override
259     public synchronized final void init() throws ProcessorException{
260         if(stage != Stage.UNINITIALIZED){
261             throw new IllegalStateException("expects UNINITIALIZED, but " + stage);
262         }
263         summary = new Summary(getId());
264         stage = Stage.INITIALIZED;
265         prepare(arguments);
266     }
267 
268     /**
269      * <p>
270      * ユーザ定義の初期設定を行うメソッドです.引数に与えられた{@link Arguments <code>Arguments</code>}
271      * に従って処理を行うよう処理器を設定しなければいけません.
272      * </p><p>
273      * 初期設定時に例外が起こった場合は,ProcessorExceptionを投げるよう実装してください.
274      * なお,このメソッドが呼び出される直前にステージはINITIALIZEDに変更されています.
275      * </p>
276      * @param args 処理器に与えるパラメータ.
277      */
278     protected abstract void prepare(Arguments args) throws ProcessorException;
279 
280     /**
281      * <p>
282      * 処理を行うためのメソッドです.
283      * </p><p>
284      * 具体的な処理内容は{@link #perform <code>perform</code>}メソッドを
285      * オーバーライドしてください.
286      * </p>
287      * 
288      * @throws IllegalStateException 適切な状態でないときにこのメソッドが呼び出された場合.
289      */
290     @Override
291     public void execute(TargetSource source, Destination dest) throws ProcessorException{
292         if(stage != Stage.INITIALIZED){
293             throw new IllegalStateException("expects INITIALIZED, but " + stage);
294         }
295         stage = Stage.PROCESSING;
296         try{
297             perform(source, dest);
298         } catch(ProcessorException e){
299             throw e;
300         } finally{
301             stage = Stage.PROCESSED;
302         }
303     }
304 
305     /**
306      * サブクラスでこのメソッドをオーバーライドして実際の処理を実装してください.
307      */
308     protected abstract void perform(TargetSource source, Destination dest) throws ProcessorException;
309 
310     /**
311      * ユーザ定義の終了処理を行うメソッドです.この処理器で使用したリソースを適切に開放しなければいけません.
312      * 終了処理時に例外が起こった場合は,ProcessorExceptionを投げるよう実装してください.
313      */
314     protected abstract void summarize() throws ProcessorException;
315 
316     /**
317      * <p>
318      * 終了処理を行います.
319      * </p><p>
320      * ユーザ独自の終了処理を行う場合は {@link #summarize() <code>summarize</code>}
321      * メソッドをオーバーライドしてください.
322      * </p><p>
323      * このメソッドはfinal宣言されていますので,オーバーライドできません.
324      * </p>
325      */
326     @Override
327     public synchronized void finish() throws ProcessorException{
328         if(stage != Stage.PROCESSED){
329             throw new IllegalStateException("expects PROCESSED, but " + stage);
330         }
331         summarize();
332         stage = Stage.FINISHED;
333     }
334 
335     /**
336      * サービスプロバイダを返します.
337      * コンストラクタに与えられたサービスプロバイダをそのまま返します.
338      */
339     @Override
340     public ProcessorService getProvider(){
341         return provider;
342     }
343 
344     /**
345      * <p>
346      * 処理器の設定項目を返します.
347      * ステージがUNINITIALIZEDの場合は,
348      * このメソッドで返されたオブジェクトの値を変更して,
349      * この処理器の設定を変えられます.
350      * </p><p>
351      * ステージがUNINITIALIZEDでない場合は,IllegalStateExceptionが投げられます.
352      * </p>
353      */
354     @Override
355     public Arguments getArguments(){
356         if(stage != Stage.UNINITIALIZED){
357             throw new IllegalStateException(
358                 "current stage is " + stage + ". Initialization is already done."
359             );
360         }
361         return arguments;
362     }
363 
364     /**
365      * <p>
366      * この処理器のサマリを返します.
367      * サマリとは処理内容を提示するためのオブジェクトです.
368      * </p><p>
369      * サマリに情報を追加するには{@link #putEntry <code>putEntry</code>}
370      * メソッドを使います.このメソッドに渡された項目がサマリオブジェクトに追加されます.
371      * </p><p>
372      * ステージがUNINITIALIZEDの場合は,IllegalStateExceptionが投げられます.
373      * </p>
374      * @see Summary
375      */
376     @Override
377     public Summary getSummary(){
378         if(stage == Stage.UNINITIALIZED){
379             throw new IllegalStateException(
380                 "current stage is UNINITIALIZED. Summary is not constructed."
381             );
382         }
383         return summary;
384     }
385 
386     /**
387      * <p>
388      * Summaryに出力するためのエントリを追加します.
389      * </p><p>
390      * 引数に与えられた{@link Arguments <code>Arguments</code>}にある全ての
391      * {@link Argument <code>Argument</code>}が{@link Summary <code>Summary</code>}
392      * に追加されます.Argumentのnameがkeyに割り当てられます.
393      * ただし,Argumentのvalueがnullの場合は追加されず,無視されます.
394      * </p><p>
395      * 現在の状態がFINISHEDのとき,もしくは,UNINITIALIZEDのときに,
396      * このメソッドが呼び出された場合,IllegalStateException が投げられます.
397      * </p>
398      *
399      * @param args
400      * @throws IllegalStateException 現在の状態がFINISHEDもしくはUNINITIALIZEDのとき.
401      * @see Summary
402      */
403     protected synchronized void putEntry(Arguments args){
404         for(Argument arg: args){
405             String value = arg.getValue();
406             if(value != null){
407                 putEntry(arg.getName(), value);
408             }
409         }
410     }
411 
412     /**
413      * <p>
414      * Summaryに出力するためのエントリを追加します.
415      * </p><p>
416      * 現在の状態がFINISHEDのとき,もしくは,UNINITIALIZEDのときに,
417      * このメソッドが呼び出された場合,IllegalStateException が投げられます.
418      * </p>
419      * @param key エントリのキー
420      * @param value エントリのキーに対応する値
421      * @throws IllegalStateException 現在の状態がFINISHEDもしくはUNINITIALIZEDのとき.
422      * @see Summary
423      */
424     protected synchronized void putEntry(String key, String value){
425         if(stage == Stage.FINISHED){
426             throw new IllegalStateException("current stage is FINISHED. Summary is already closed.");
427         }
428         if(stage == Stage.UNINITIALIZED){
429             throw new IllegalStateException("current stage is UNINITIALIZED. Summary is not constructed.");
430         }
431         summary.putEntry(key, value);
432     }
433 }