OSDN Git Service

43d11ec9d4ac9e64718c0e5411361a99529c846b
[wptscs/wpts.git] / Wptscs / Logics / Translator.cs
1 // ================================================================================================\r
2 // <summary>\r
3 //      翻訳支援処理を実装するための共通クラスソース</summary>\r
4 //\r
5 // <copyright file="Translator.cs" company="honeplusのメモ帳">\r
6 //      Copyright (C) 2010 Honeplus. All rights reserved.</copyright>\r
7 // <author>\r
8 //      Honeplus</author>\r
9 // ================================================================================================\r
10 \r
11 namespace Honememo.Wptscs.Logics\r
12 {\r
13     using System;\r
14     using System.IO;\r
15     using System.Net;\r
16     using System.Net.NetworkInformation;\r
17     using System.Reflection;\r
18     using Honememo.Utilities;\r
19     using Honememo.Wptscs.Models;\r
20     using Honememo.Wptscs.Properties;\r
21 \r
22     /// <summary>\r
23     /// 翻訳支援処理を実装するための共通クラスです。\r
24     /// </summary>\r
25     public abstract class Translator\r
26     {\r
27         #region private変数\r
28 \r
29         /// <summary>\r
30         /// 改行コード。\r
31         /// </summary>\r
32         public static readonly string ENTER = "\r\n";\r
33 \r
34         /// <summary>\r
35         /// ログメッセージ。\r
36         /// </summary>\r
37         private string log;\r
38 \r
39         /// <summary>\r
40         /// 変換後テキスト。\r
41         /// </summary>\r
42         private string text;\r
43 \r
44         #endregion\r
45         \r
46         #region イベント\r
47 \r
48         /// <summary>\r
49         /// ログ更新伝達イベント。\r
50         /// </summary>\r
51         public event EventHandler LogUpdate;\r
52 \r
53         #endregion\r
54 \r
55         #region プロパティ\r
56 \r
57         /// <summary>\r
58         /// 言語間の項目の対訳表。\r
59         /// </summary>\r
60         public TranslationDictionary ItemTable\r
61         {\r
62             get;\r
63             set;\r
64         }\r
65 \r
66         /// <summary>\r
67         /// 言語間の見出しの対訳表。\r
68         /// </summary>\r
69         public TranslationTable HeadingTable\r
70         {\r
71             get;\r
72             set;\r
73         }\r
74 \r
75         /// <summary>\r
76         /// ログメッセージ。\r
77         /// </summary>\r
78         public string Log\r
79         {\r
80             // ※ 将来的には、ロジックでログメッセージを出すなんて形を止めて\r
81             //    データとして保持させてメッセージはビューで・・・としたいが、\r
82             //    手間を考えて当面はこの形のまま実装する。\r
83             get\r
84             {\r
85                 return this.log;\r
86             }\r
87 \r
88             protected set\r
89             {\r
90                 this.log = (value != null) ? value : String.Empty;\r
91                 if (this.LogUpdate != null)\r
92                 {\r
93                     this.LogUpdate(this, EventArgs.Empty);\r
94                 }\r
95             }\r
96         }\r
97 \r
98         /// <summary>\r
99         /// 変換後テキスト。\r
100         /// </summary>\r
101         public string Text\r
102         {\r
103             get\r
104             {\r
105                 return this.text;\r
106             }\r
107 \r
108             protected set\r
109             {\r
110                 this.text = StringUtils.DefaultString(value);\r
111             }\r
112         }\r
113 \r
114         /// <summary>\r
115         /// 処理を途中で終了させるためのフラグ。\r
116         /// </summary>\r
117         public bool CancellationPending\r
118         {\r
119             get;\r
120             set;\r
121         }\r
122 \r
123         /// <summary>\r
124         /// 翻訳元言語のサイト。\r
125         /// </summary>\r
126         public Website From\r
127         {\r
128             get;\r
129             set;\r
130         }\r
131 \r
132         /// <summary>\r
133         /// 翻訳先言語のサイト。\r
134         /// </summary>\r
135         public Website To\r
136         {\r
137             get;\r
138             set;\r
139         }\r
140 \r
141         #endregion\r
142 \r
143         #region 静的メソッド\r
144 \r
145         /// <summary>\r
146         /// 翻訳支援処理のインスタンスを作成。\r
147         /// </summary>\r
148         /// <param name="config">アプリケーション設定。</param>\r
149         /// <param name="from">翻訳元言語。</param>\r
150         /// <param name="to">翻訳先言語。</param>\r
151         /// <returns>生成したインスタンス。</returns>\r
152         /// <remarks>\r
153         /// 設定は設定クラスより取得、無ければ一部自動生成する。\r
154         /// インスタンス生成失敗時は例外を投げる。\r
155         /// </remarks>\r
156         public static Translator Create(Config config, string from, string to)\r
157         {\r
158             // 処理対象に応じてTranslatorを継承したオブジェクトを生成\r
159             ConstructorInfo constructor = config.Translator.GetConstructor(Type.EmptyTypes);\r
160             if (constructor == null)\r
161             {\r
162                 throw new NotImplementedException(config.Translator.FullName + " default constructor is not found");\r
163             }\r
164 \r
165             // 設定に指定されたクラスを、引数無しのコンストラクタを用いて生成する\r
166             Translator translator = (Translator)constructor.Invoke(null);\r
167 \r
168             // Webサイトの設定\r
169             translator.From = config.GetWebsite(from);\r
170             translator.To = config.GetWebsite(to);\r
171 \r
172             // 対訳表(項目)の設定\r
173             translator.ItemTable = config.GetItemTableNeedCreate(from, to);\r
174 \r
175             // 対訳表(見出し)の設定、使用する言語は決まっているので組み合わせを設定\r
176             translator.HeadingTable = config.HeadingTable;\r
177             translator.HeadingTable.From = from;\r
178             translator.HeadingTable.To = to;\r
179 \r
180             return translator;\r
181         }\r
182 \r
183         #endregion\r
184 \r
185         #region publicメソッド\r
186 \r
187         /// <summary>\r
188         /// 翻訳支援処理実行。\r
189         /// </summary>\r
190         /// <param name="name">記事名。</param>\r
191         /// <returns><c>true</c> 処理成功</returns>\r
192         public virtual bool Run(string name)\r
193         {\r
194             // ※必須な情報が設定されていない場合、InvalidOperationExceptionを返す\r
195             if (this.From == null || this.To == null)\r
196             {\r
197                 throw new InvalidOperationException("From or To is null");\r
198             }\r
199 \r
200             // 変数を初期化\r
201             this.Initialize();\r
202 \r
203             // サーバー接続チェック\r
204             string host = new Uri(this.From.Location).Host;\r
205             if (!String.IsNullOrEmpty(host) && !Settings.Default.IgnoreError)\r
206             {\r
207                 if (!this.Ping(host))\r
208                 {\r
209                     return false;\r
210                 }\r
211             }\r
212 \r
213             // 翻訳支援処理実行部の本体を実行\r
214             // ※以降の処理は、継承クラスにて定義\r
215             return this.RunBody(name);\r
216         }\r
217         \r
218         #endregion\r
219 \r
220         #region protectedメソッド\r
221 \r
222         /// <summary>\r
223         /// 翻訳支援処理実行部の本体。\r
224         /// </summary>\r
225         /// <param name="name">記事名。</param>\r
226         /// <returns><c>true</c> 処理成功</returns>\r
227         /// <remarks>テンプレートメソッド的な構造になっています。</remarks>\r
228         protected abstract bool RunBody(string name);\r
229 \r
230         /// <summary>\r
231         /// ログメッセージを1行追加出力。\r
232         /// </summary>\r
233         /// <param name="log">ログメッセージ。</param>\r
234         protected void LogLine(string log)\r
235         {\r
236             // 直前のログが改行されていない場合、改行して出力\r
237             if (this.Log != String.Empty && this.Log.EndsWith(ENTER) == false)\r
238             {\r
239                 this.Log += ENTER + log + ENTER;\r
240             }\r
241             else\r
242             {\r
243                 this.Log += log + ENTER;\r
244             }\r
245         }\r
246 \r
247         /// <summary>\r
248         /// ログメッセージを1行追加出力(入力された文字列を書式化して表示)。\r
249         /// </summary>\r
250         /// <param name="format">書式項目を含んだログメッセージ。</param>\r
251         /// <param name="args">書式設定対象オブジェクト配列。</param>\r
252         protected void LogLine(string format, params object[] args)\r
253         {\r
254             // オーバーロードメソッドをコール\r
255             this.LogLine(String.Format(format, args));\r
256         }\r
257 \r
258         /// <summary>\r
259         /// ログメッセージを出力しつつページを取得。\r
260         /// </summary>\r
261         /// <param name="title">ページタイトル。</param>\r
262         /// <param name="notFoundMsg">取得できない場合に出力するメッセージ。</param>\r
263         /// <returns>取得したページ。ページが存在しない場合は <c>null</c> を返す。</returns>\r
264         /// <remarks>通信エラーなど例外が発生した場合は、別途エラーログを出力する。</remarks>\r
265         protected Page GetPage(string title, string notFoundMsg)\r
266         {\r
267             try\r
268             {\r
269                 // 取得できた場合はここで終了\r
270                 return this.From.GetPage(title);\r
271             }\r
272             catch (WebException e)\r
273             {\r
274                 // 通信エラー\r
275                 if (e.Status == WebExceptionStatus.ProtocolError\r
276                     && (e.Response as HttpWebResponse).StatusCode == HttpStatusCode.NotFound)\r
277                 {\r
278                     // 404\r
279                     this.Log += notFoundMsg;\r
280                 }\r
281                 else\r
282                 {\r
283                     // それ以外のエラー\r
284                     this.LogLine(Resources.RightArrow + " " + e.Message);\r
285                     if (e.Response != null)\r
286                     {\r
287                         this.LogLine(Resources.RightArrow + " " + String.Format(Resources.LogMessage_ErrorURL, e.Response.ResponseUri));\r
288                     }\r
289                 }\r
290             }\r
291             catch (FileNotFoundException)\r
292             {\r
293                 // ファイル無し\r
294                 this.Log += notFoundMsg;\r
295             }\r
296             catch (Exception e)\r
297             {\r
298                 // その他の想定外のエラー\r
299                 this.LogLine(Resources.RightArrow + " " + e.Message);\r
300             }\r
301 \r
302             // 取得失敗時いずれの場合もnull\r
303             return null;\r
304         }\r
305 \r
306         #endregion\r
307 \r
308         #region privateメソッド\r
309 \r
310         /// <summary>\r
311         /// 翻訳支援処理実行時の初期化処理。\r
312         /// </summary>\r
313         private void Initialize()\r
314         {\r
315             // 変数を初期化\r
316             this.log = String.Empty;\r
317             this.Text = String.Empty;\r
318             this.CancellationPending = false;\r
319         }\r
320 \r
321         /// <summary>\r
322         /// サーバー接続チェック。\r
323         /// </summary>\r
324         /// <param name="server">サーバー名。</param>\r
325         /// <returns><c>true</c> 接続成功。</returns>\r
326         private bool Ping(string server)\r
327         {\r
328             // サーバー接続チェック\r
329             Ping ping = new Ping();\r
330             try\r
331             {\r
332                 PingReply reply = ping.Send(server);\r
333                 if (reply.Status != IPStatus.Success)\r
334                 {\r
335                     this.LogLine(Resources.ErrorMessageConnectionFailed, reply.Status.ToString());\r
336                     return false;\r
337                 }\r
338             }\r
339             catch (Exception e)\r
340             {\r
341                 this.LogLine(Resources.ErrorMessageConnectionFailed, e.InnerException.Message);\r
342                 return false;\r
343             }\r
344 \r
345             return true;\r
346         }\r
347 \r
348         #endregion\r
349     }\r
350 }\r