OSDN Git Service

06d432c14de46b04030aeaa2b3cbea9a2222b4dd
[mikutoga/Pmd2XML.git] / src / main / java / jp / sfjp / mikutoga / pmd2xml / Pmd2Xml.java
1 /*
2  * pmd 2 xml converter main entry
3  *
4  * License : The MIT License
5  * Copyright(c) 2010 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.pmd2xml;
9
10 import java.io.BufferedInputStream;
11 import java.io.BufferedOutputStream;
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.io.PrintStream;
20 import java.nio.channels.FileChannel;
21 import java.text.MessageFormat;
22 import java.util.Properties;
23 import jp.sfjp.mikutoga.bin.parser.MmdFormatException;
24 import jp.sfjp.mikutoga.pmd.IllegalPmdDataException;
25 import jp.sourceforge.mikutoga.xml.TogaXmlException;
26 import org.xml.sax.SAXException;
27
28 /**
29  * PMDモデルファイルとXMLとの間で変換を行うアプリケーション。
30  */
31 public final class Pmd2Xml {
32
33     /** 正常系。 */
34     public static final int EXIT_OK     = 0;
35     /** 内部エラー。 */
36     public static final int EXIT_INTERR = 1;
37     /** 実行環境に起因するエラー。 */
38     public static final int EXIT_ENVERR = 2;
39     /** オプション指定に起因するエラー。 */
40     public static final int EXIT_OPTERR = 3;
41     /** ファイル入出力に起因するエラー。 */
42     public static final int EXIT_IOERR  = 4;
43     /** XMLフォーマットに起因するエラー。 */
44     public static final int EXIT_XMLERR = 5;
45     /** PMDフォーマットに起因するエラー。 */
46     public static final int EXIT_PMDERR = 6;
47
48     /** アプリ名。 */
49     public static final String APPNAME;
50     /** バージョン識別子。 */
51     public static final String APPVER;
52     /** ライセンス種別。 */
53     public static final String APPLICENSE;
54     /** 開発元URL。 */
55     public static final String APPURL;
56
57     private static final Class<?> THISCLASS;
58     private static final String RES_VER = "resources/version.properties";
59
60     private static final PrintStream ERROUT = System.err;
61     private static final String MSG_ERR = "ERROR:\n{0}\n(-h for help)";
62     private static final String MSG_HELP =
63               "{0} {1}\n"
64             + "\u0020\u0020License\u0020:\u0020{2}\n"
65             + "\u0020\u0020{3}\n";
66     private static final String MSG_NOINFILE = "Can't find input file:{0}";
67     private static final String MSG_ABNFILE = "{0} is not file.";
68     private static final String MSG_OWOUTFILE =
69               "{0} already exists.\n"
70             + "If you want to overwrite, use -f.";
71
72     private static final String MSG_OLDJRE = "You need JRE {0} or later.";
73     private static final String REQUIRED_JRE = "1.6";
74
75     static{
76         THISCLASS = Pmd2Xml.class;
77         InputStream ver = THISCLASS.getResourceAsStream(RES_VER);
78         Properties verProps = new Properties();
79         try{
80             try{
81                 verProps.load(ver);
82             }finally{
83                 ver.close();
84             }
85         }catch(IOException e){
86             throw new ExceptionInInitializerError(e);
87         }
88
89         APPNAME    = verProps.getProperty("app.name");
90         APPVER     = verProps.getProperty("app.version");
91         APPLICENSE = verProps.getProperty("app.license");
92         APPURL     = verProps.getProperty("app.url");
93
94         new Pmd2Xml().hashCode();
95     }
96
97
98     /**
99      * ダミーコンストラクタ。
100      */
101     private Pmd2Xml(){
102         super();
103         assert this.getClass().equals(THISCLASS);
104         return;
105     }
106
107
108     /**
109      * VMを終了させる。
110      * @param code 終了コード
111      * @see java.lang.System#exit(int)
112      */
113     private static void exit(int code){
114         System.exit(code);
115         assert false;
116         throw new AssertionError();
117     }
118
119     /**
120      * 共通エラーメッセージを出力する。
121      * @param text 個別メッセージ
122      */
123     private static void errMsg(String text){
124         String msg = MessageFormat.format(MSG_ERR, text);
125         ERROUT.println(msg);
126         return;
127     }
128
129     /**
130      * 標準エラー出力へ例外情報出力。
131      * @param ex 例外
132      * @param dumpStack スタックトレースを出力するならtrue
133      */
134     private static void thPrintln(Throwable ex, boolean dumpStack){
135         if(dumpStack){
136             ex.printStackTrace(ERROUT);
137         }else{
138             String text = ex.toString();
139             ERROUT.println(text);
140         }
141
142         return;
143     }
144
145     /**
146      * 標準エラー出力へ例外情報出力。
147      * @param ex 例外
148      */
149     private static void thPrintln(Throwable ex){
150         thPrintln(ex, false);
151         return;
152     }
153
154     /**
155      * 入出力エラー処理。
156      * 例外を出力してVM終了する。
157      * @param ex 例外
158      */
159     private static void ioError(IOException ex){
160         thPrintln(ex);
161         exit(EXIT_IOERR);
162     }
163
164     /**
165      * XML構文エラー処理。
166      * 例外を出力してVM終了する。
167      * @param ex 例外
168      */
169     private static void xmlError(Throwable ex){
170         thPrintln(ex);
171         exit(EXIT_XMLERR);
172     }
173
174     /**
175      * PMDファイルフォーマットエラー処理。
176      * 例外を出力してVM終了する。
177      * @param ex 例外
178      */
179     private static void pmdError(MmdFormatException ex){
180         thPrintln(ex, true);
181         exit(EXIT_PMDERR);
182     }
183
184     /**
185      * 内部エラー処理。
186      * 例外を出力してVM終了する。
187      * @param ex 例外
188      */
189     private static void internalError(Throwable ex){
190         thPrintln(ex, true);
191         exit(EXIT_INTERR);
192     }
193
194     /**
195      * JREのバージョン判定を行う。
196      * 不適切ならVMごと終了。
197      */
198     private static void checkJRE(){
199         Package jrePackage = java.lang.Object.class.getPackage();
200         if( ! jrePackage.isCompatibleWith(REQUIRED_JRE)){
201             String msg = MessageFormat.format(MSG_OLDJRE, REQUIRED_JRE);
202             ERROUT.println(msg);
203             exit(EXIT_ENVERR);
204         }
205         return;
206     }
207
208     /**
209      * ヘルプメッセージを出力する。
210      */
211     private static void putHelp(){
212         String msg =
213                 MessageFormat.format(MSG_HELP,
214                 APPNAME, APPVER, APPLICENSE, APPURL);
215         ERROUT.println(msg);
216         ERROUT.println(OptSwitch.getConsoleHelp());
217         return;
218     }
219
220     /**
221      * ファイルサイズを0に切り詰める。
222      * <p>ファイルが存在しなければなにもしない。
223      * <p>通常ファイルでなければなにもしない。
224      * @param file ファイル
225      * @throws IOException 入出力エラー
226      */
227     private static void trunc(File file) throws IOException{
228         if( ! file.exists() ) return;
229         if( ! file.isFile() ) return;
230
231         if(file.length() <= 0L) return;
232
233         FileOutputStream foStream = new FileOutputStream(file);
234         try{
235             FileChannel channnel = foStream.getChannel();
236             try{
237                 channnel.truncate(0L);
238             }finally{
239                 channnel.close();
240             }
241         }finally{
242             foStream.close();
243         }
244
245         return;
246     }
247
248     /**
249      * 入力ストリームを準備する。
250      * <p>入力ファイルが通常ファイルとして存在しなければエラー終了。
251      * @param fileName 入力ファイル名
252      * @return 入力ストリーム
253      */
254     private static InputStream openInfile(String fileName){
255         File inFile = new File(fileName);
256
257         if( (! inFile.exists()) || (! inFile.isFile()) ){
258             String absPath = inFile.getAbsolutePath();
259             String msg = MessageFormat.format(MSG_NOINFILE, absPath);
260             errMsg(msg);
261             exit(EXIT_IOERR);
262         }
263
264         InputStream is;
265         try{
266             is = new FileInputStream(inFile);
267         }catch(FileNotFoundException e){
268             ioError(e);
269             assert false;
270             throw new AssertionError(e);
271         }
272
273         is = new BufferedInputStream(is);
274
275         return is;
276     }
277
278     /**
279      * 出力ストリームを準備する。
280      * <p>出力ファイルが通常ファイルでない場合はエラー終了。
281      * <p>既存の出力ファイルに上書き指示が伴っていなければエラー終了。
282      * @param fileName 出力ファイル名
283      * @param overWrite 頭から上書きして良ければtrue
284      * @return 出力ストリーム
285      */
286     private static OutputStream openOutfile(String fileName,
287                                             boolean overWrite) {
288         File outFile = new File(fileName);
289
290         if(outFile.exists()){
291             String absPath = outFile.getAbsolutePath();
292             if( ! outFile.isFile() ){
293                 String msg = MessageFormat.format(MSG_ABNFILE, absPath);
294                 errMsg(msg);
295                 exit(EXIT_IOERR);
296             }else if( ! overWrite ){
297                 String msg = MessageFormat.format(MSG_OWOUTFILE, absPath);
298                 errMsg(msg);
299                 exit(EXIT_IOERR);
300             }
301         }
302
303         try{
304             trunc(outFile);
305         }catch(IOException e){
306             ioError(e);
307         }
308
309         OutputStream os;
310         try{
311             os = new FileOutputStream(outFile);
312         }catch(FileNotFoundException e){
313             ioError(e);
314             assert false;
315             throw new AssertionError(e);
316         }
317
318         os = new BufferedOutputStream(os);
319
320         return os;
321     }
322
323     /**
324      * Mainエントリ。
325      * @param args コマンドパラメータ
326      */
327     public static void main(String[] args){
328         checkJRE();
329
330         OptInfo optInfo;
331         try{
332             optInfo = OptInfo.parseOption(args);
333         }catch(CmdLineException e){
334             String optErrMsg = e.getLocalizedMessage();
335             errMsg(optErrMsg);
336             exit(EXIT_OPTERR);
337             return;
338         }
339
340         if(optInfo.needHelp()){
341             putHelp();
342             exit(EXIT_OK);
343         }
344
345         String inputFile  = optInfo.getInFilename();
346         String outputFile = optInfo.getOutFilename();
347         boolean overwrite = optInfo.overwriteMode();
348
349         InputStream  is = openInfile(inputFile);
350         OutputStream os = openOutfile(outputFile, overwrite);
351
352         Pmd2XmlConv converter = new Pmd2XmlConv();
353
354         converter.setInType (optInfo.getInFileType());
355         converter.setOutType(optInfo.getOutFileType());
356
357         converter.setNewline(optInfo.getNewline());
358         converter.setGenerator(optInfo.getGenerator());
359
360         try{
361             converter.convert(is, os);
362         }catch(IOException e){
363             ioError(e);
364         }catch(IllegalPmdDataException e){
365             internalError(e);
366         }catch(MmdFormatException e){
367             pmdError(e);
368         }catch(TogaXmlException e){
369             xmlError(e);
370         }catch(SAXException e){
371             xmlError(e);
372         }
373
374         try{
375             is.close();
376             try{
377                 os.close();
378             }catch(IOException e){
379                 ioError(e);
380             }
381         }catch(IOException e){
382             ioError(e);
383         }
384
385         exit(EXIT_OK);
386
387         return;
388     }
389
390 }