OSDN Git Service

1f9a4b031910366dfb0d42f02a8de5873e8cef5a
[mikutoga/Pmd2XML.git] / src / main / java / jp / sfjp / mikutoga / pmd / model / xml / SaxListener.java
1 /*
2  * PMD-SAX element listsner
3  *
4  * License : The MIT License
5  * Copyright(c) 2013 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.pmd.model.xml;
9
10 import java.lang.annotation.Annotation;
11 import java.lang.reflect.InvocationTargetException;
12 import java.lang.reflect.Method;
13 import java.lang.reflect.Modifier;
14 import java.util.Collection;
15 import java.util.EnumMap;
16 import java.util.LinkedList;
17 import java.util.Map;
18 import jp.sfjp.mikutoga.pmd.model.PmdModel;
19 import jp.sfjp.mikutoga.xml.DatatypeIo;
20 import org.xml.sax.Attributes;
21
22 /**
23  * XML要素出現の通知受信部の共通実装。
24  */
25 class SaxListener {
26
27     private final Map<PmdTag, Method> openDispatcher;
28     private final Map<PmdTag, Method> closeDispatcher;
29
30     private PmdModel pmdModel = null;
31     private Attributes currentAttribute = null;
32
33
34     /**
35      * コンストラクタ。
36      */
37     protected SaxListener(){
38         super();
39
40         Class<?> thisClass = this.getClass();
41         this.openDispatcher  = getOpenDispatcher(thisClass);
42         this.closeDispatcher = getCloseDispatcher(thisClass);
43
44         return;
45     }
46
47
48     /**
49      * 指定された注釈がマークされたインスタンスメソッド群を返す。
50      * @param klass クラス
51      * @param filter 注釈
52      * @return インスタンスメソッド群
53      */
54     private static Collection<Method> filtMethod(Class<?> klass,
55                                    Class<? extends Annotation> filter ){
56         Collection<Method> result = new LinkedList<Method>();
57
58         for(Method method : klass.getDeclaredMethods()){
59             int modifiers = method.getModifiers();
60             if(Modifier.isStatic(modifiers)) continue;
61             if(Modifier.isPrivate(modifiers)) continue;
62             if(method.getParameterTypes().length > 0) continue;
63
64             Annotation anno = method.getAnnotation(filter);
65             if(anno == null) continue;
66
67             result.add(method);
68         }
69
70         return result;
71     }
72
73     /**
74      * 注釈でマークされた開始タグ通知用ディスパッチテーブルを返す。
75      * @param klass 対象クラス
76      * @return ディスパッチテーブル
77      */
78     private static Map<PmdTag, Method> getOpenDispatcher(Class<?> klass){
79         Map<PmdTag, Method> result =
80                 new EnumMap<PmdTag, Method>(PmdTag.class);
81
82         for(Method method : filtMethod(klass, OpenXmlMark.class)){
83             Annotation anno = method.getAnnotation(OpenXmlMark.class);
84             OpenXmlMark mark = (OpenXmlMark) anno;
85             PmdTag tag = mark.value();
86             result.put(tag, method);
87         }
88
89         return result;
90     }
91
92     /**
93      * 注釈でマークされた終了タグ通知用ディスパッチテーブルを返す。
94      * @param klass 対象クラス
95      * @return ディスパッチテーブル
96      */
97     private static Map<PmdTag, Method> getCloseDispatcher(Class<?> klass){
98         Map<PmdTag, Method> result =
99                 new EnumMap<PmdTag, Method>(PmdTag.class);
100
101         for(Method method : filtMethod(klass, CloseXmlMark.class)){
102             Annotation anno = method.getAnnotation(CloseXmlMark.class);
103             CloseXmlMark mark = (CloseXmlMark) anno;
104             PmdTag tag = mark.value();
105             result.put(tag, method);
106         }
107
108         return result;
109     }
110
111
112     /**
113      * ディスパッチテーブルに従いディスパッチする。
114      * @param map ディスパッチテーブル
115      * @param tag タグ種
116      * @return ディスパッチが行われなければfalse
117      */
118     private boolean dispatch(Map<PmdTag, Method> map, PmdTag tag){
119         Method method = map.get(tag);
120         if(method == null) return false;
121
122         try{
123             method.invoke(this);
124         }catch(IllegalAccessException ex){
125             assert false;
126         }catch(InvocationTargetException ex){
127             Throwable cause = ex.getTargetException();
128             if(cause instanceof RuntimeException){
129                 throw (RuntimeException) cause;
130             }else if(cause instanceof Error){
131                 throw (Error) cause;
132             }
133         }
134
135         return true;
136     }
137
138     /**
139      * 開始タグ登場を通知する。
140      * @param tag タグ種別
141      * @param attr 属性群
142      * @return ディスパッチが行われなければfalse
143      */
144     boolean openDispatch(PmdTag tag, Attributes attr){
145         this.currentAttribute = attr;
146         return dispatch(this.openDispatcher, tag);
147     }
148
149     /**
150      * 終了タグ登場を通知する。
151      * @param tag タグ種別
152      * @return ディスパッチが行われなければfalse
153      */
154     boolean closeDispatch(PmdTag tag){
155         return dispatch(this.closeDispatcher, tag);
156     }
157
158     /**
159      * CharData出現の通知。
160      * @param ch 文字配列
161      * @param start 開始位置
162      * @param length 長さ
163      */
164     void addCharData(char[] ch, int start, int length){
165         return;
166     }
167
168     /**
169      * ビルド対象オブジェクトの登録。
170      * @param model ビルド対象オブジェクト
171      * @throws NullPointerException 引数がnull
172      */
173     void setPmdModel(PmdModel model) throws NullPointerException{
174         if(model == null) throw new NullPointerException();
175         this.pmdModel = model;
176         return;
177     }
178
179     /**
180      * ビルド対象オブジェクトの取得。
181      * @return ビルド対象オブジェクト。未登録の場合はnull。
182      */
183     protected PmdModel getPmdModel(){
184         return this.pmdModel;
185     }
186
187     /**
188      * xsd:string型属性値の読み込み。
189      * @param attr 属性名
190      * @return 属性値。該当する属性が無ければnull。
191      * @see "http://www.w3.org/TR/xmlschema-2/#string"
192      */
193     protected String getStringAttr(PmdAttr attr){
194         String attrName = attr.attr();
195         String result = this.currentAttribute.getValue(attrName);
196         return result;
197     }
198
199     /**
200      * xsd:boolean型属性値の読み込み。
201      * @param attr 属性名
202      * @return 属性値。
203      * @throws IllegalArgumentException boolean型表記ではない
204      * @see "http://www.w3.org/TR/xmlschema-2/#boolean"
205      */
206     protected boolean getBooleanAttr(PmdAttr attr)
207             throws IllegalArgumentException{
208         String attrName = attr.attr();
209         String attrVal = this.currentAttribute.getValue(attrName);
210         boolean bVal;
211         bVal = DatatypeIo.parseBoolean(attrVal);
212         return bVal;
213     }
214
215     /**
216      * xsd:float型属性値の読み込み。
217      * @param attr 属性名
218      * @return 属性値。
219      * @throws NumberFormatException float型表記ではない
220      * @see "http://www.w3.org/TR/xmlschema-2/#float"
221      */
222     protected float getFloatAttr(PmdAttr attr)
223             throws NumberFormatException {
224         String attrName = attr.attr();
225         String attrVal = this.currentAttribute.getValue(attrName);
226         float fVal;
227         fVal = DatatypeIo.parseFloat(attrVal);
228         return fVal;
229     }
230
231     /**
232      * xsd:int型属性値の読み込み。
233      * @param attr 属性名
234      * @return 属性値。
235      * @throws NumberFormatException int型表記ではない
236      * @see "http://www.w3.org/TR/xmlschema-2/#int"
237      */
238     protected int getIntAttr(PmdAttr attr)
239             throws NumberFormatException {
240         String attrName = attr.attr();
241         String attrVal = this.currentAttribute.getValue(attrName);
242         int iVal;
243         iVal = DatatypeIo.parseInt(attrVal);
244         return iVal;
245     }
246
247 }