View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.uruma.component.factory.handler;
17  
18  import org.seasar.framework.beans.BeanDesc;
19  import org.seasar.framework.beans.PropertyDesc;
20  import org.seasar.framework.beans.factory.BeanDescFactory;
21  import org.seasar.framework.util.StringUtil;
22  import org.seasar.framework.xml.TagHandlerContext;
23  import org.seasar.uruma.component.UIComponent;
24  import org.seasar.uruma.component.UIElement;
25  import org.seasar.uruma.component.UIElementContainer;
26  import org.seasar.uruma.component.factory.UrumaTagHandler;
27  import org.seasar.uruma.core.UrumaMessageCodes;
28  import org.seasar.uruma.exception.NotFoundException;
29  import org.seasar.uruma.exception.ParseException;
30  import org.seasar.uruma.renderer.Renderer;
31  import org.seasar.uruma.renderer.RendererFactory;
32  import org.seasar.uruma.util.ClassUtil;
33  import org.seasar.uruma.util.PathUtil;
34  import org.xml.sax.Attributes;
35  
36  /**
37   * 汎用のタグハンドラクラスです。<br />
38   * 
39   * @author y-komori
40   */
41  public class GenericTagHandler extends UrumaTagHandler {
42      private static final long serialVersionUID = 4075680211563734762L;
43  
44      private Class<? extends UIElement> uiElementClass;
45  
46      /**
47       * 生成するクラスを指定してインスタンスを構築します。
48       * 
49       * @param uiElementClass
50       *            生成するクラス
51       */
52      public GenericTagHandler(final Class<? extends UIElement> uiElementClass) {
53          this.uiElementClass = uiElementClass;
54      }
55  
56      /*
57       * @see org.seasar.framework.xml.TagHandler#start(org.seasar.framework.xml.TagHandlerContext,
58       *      org.xml.sax.Attributes)
59       */
60      @Override
61      public void start(final TagHandlerContext context,
62              final Attributes attributes) {
63          UIElement uiElement = createUIElement(uiElementClass, context);
64  
65          setPath(uiElement, context);
66  
67          setBasePath(uiElement, context);
68  
69          setLocation(uiElement, context);
70  
71          setAttributes(uiElement, attributes);
72  
73          if (uiElement instanceof UIComponent) {
74              setRenderer((UIComponent) uiElement);
75          }
76  
77          setParent(uiElement, context);
78  
79          if (enableAutoId()) {
80              setupAutoId(uiElement);
81          }
82  
83          if (enableAutoTitle()) {
84              setupAutoTitle(uiElement);
85          }
86  
87          context.push(uiElement);
88      }
89  
90      /*
91       * @see org.seasar.framework.xml.TagHandler#end(org.seasar.framework.xml.TagHandlerContext,
92       *      java.lang.String)
93       */
94      @Override
95      public void end(final TagHandlerContext context, final String body) {
96          context.pop();
97      }
98  
99      /**
100      * {@link UIElement} オブジェクトを生成します。<br />
101      * 
102      * @param uiElementClass
103      *            {@link UIElement} クラス
104      * @param context
105      *            {@link TagHandlerContext} オブジェクト。<br />
106      *            コンテクストに応じて生成する {@link UIElement} を変更するために使用します。<br />
107      *            本クラスでは利用しませんが、サブクラスで必要に応じて利用することができます。<br />
108      * @return {@link UIElement} オブジェクト
109      */
110     protected UIElement createUIElement(
111             final Class<? extends UIElement> uiElementClass,
112             final TagHandlerContext context) {
113         return ClassUtil.<UIElement> newInstance(uiElementClass);
114     }
115 
116     /**
117      * {@link UIElement} へXMLのパスを設定します。<br />
118      * 
119      * @param uiElement
120      *            {@link UIElement} オブジェクト
121      * @param context
122      *            コンテクスト情報
123      */
124     protected void setPath(final UIElement uiElement,
125             final TagHandlerContext context) {
126         uiElement.setPath((String) context
127                 .getParameter(UrumaTagHandler.PARAM_PATH));
128     }
129 
130     /**
131      * {@link UIElement} へXMLのベースパスを設定します。<br />
132      * 
133      * @param uiElement
134      *            {@link UIElement} オブジェクト
135      * @param context
136      *            コンテクスト情報
137      */
138     protected void setBasePath(final UIElement uiElement,
139             final TagHandlerContext context) {
140         uiElement.setBasePath((String) context
141                 .getParameter(UrumaTagHandler.PARAM_BASE_PATH));
142     }
143 
144     /**
145      * {@link UIElement} へXML上のロケーション情報を設定します。<br />
146      * 
147      * @param uiElement
148      *            {@link UIElement} オブジェクト
149      * @param context
150      *            コンテクスト情報
151      */
152     protected void setLocation(final UIElement uiElement,
153             final TagHandlerContext context) {
154         uiElement.setLocation(context.getDetailPath());
155     }
156 
157     /**
158      * {@link UIElement} へ属性の値をセットします。<br />
159      * 
160      * @param uiElement
161      *            {@link UIElement} オブジェクト
162      * @param attributes
163      *            {@link Attributes} オブジェクト
164      */
165     protected void setAttributes(final UIElement uiElement,
166             final Attributes attributes) {
167         int length = attributes.getLength();
168 
169         for (int i = 0; i < length; i++) {
170             String name = attributes.getQName(i);
171             String value = attributes.getValue(i);
172             setProperty(uiElement, name, value);
173         }
174     }
175 
176     /**
177      * {@link UIElement} へプロパティを設定します。<br />
178      * <p>
179      * <code>name</code>に対応したsetterメソッドが存在すればそれを利用して値を設定します。<br />
180      * </p>
181      * 
182      * @param uiElement
183      *            {@link UIElement} オブジェクト
184      * @param name
185      *            プロパティ名
186      * @param value
187      *            値
188      */
189     protected void setProperty(final UIElement uiElement, final String name,
190             final String value) {
191         BeanDesc desc = BeanDescFactory.getBeanDesc(uiElement.getClass());
192         if (desc.hasPropertyDesc(name)) {
193             PropertyDesc pd = desc.getPropertyDesc(name);
194             pd.setValue(uiElement, value);
195         } else {
196             throw new ParseException(name, uiElement.getClass().getName());
197         }
198     }
199 
200     /**
201      * 生成した {@link UIElement} を {@link TagHandlerContext} 内に存在する親へ設定します。<br />
202      * 
203      * @param uiElement
204      *            {@link UIElement} オブジェクト
205      * @param context
206      *            {@link TagHandlerContext} オブジェクト
207      */
208     protected void setParent(final UIElement uiElement,
209             final TagHandlerContext context) {
210         if (!context.isEmpty()) {
211             Object parent = context.peek();
212             if (UIElementContainer.class.isAssignableFrom(parent.getClass())) {
213                 UIElementContainer parentComponent = (UIElementContainer) parent;
214                 parentComponent.addChild(uiElement);
215             }
216         }
217     }
218 
219     /**
220      * {@link UIComponent} に対応するレンダラをセットします。<br />
221      * 
222      * @param uiComponent
223      *            {@link UIComponent} オブジェクト
224      */
225     protected void setRenderer(final UIComponent uiComponent) {
226         Renderer renderer = RendererFactory
227                 .getRenderer(uiComponent.getClass());
228         if (renderer != null) {
229             uiComponent.setRenderer(renderer);
230         } else {
231             throw new NotFoundException(UrumaMessageCodes.RENDERER_NOT_FOUND,
232                     uiComponent.getClass().getName());
233         }
234     }
235 
236     /*
237      * @see org.seasar.uruma.component.factory.UrumaTagHandler#getElementPath()
238      */
239     @Override
240     public String getElementPath() {
241         return null;
242     }
243 
244     protected void setupAutoId(final UIElement element) {
245         if (element instanceof UIComponent) {
246             UIComponent uiComponent = (UIComponent) element;
247             if (StringUtil.isEmpty(uiComponent.getId())) {
248                 String fileName = PathUtil.getFileName(uiComponent.getPath());
249                 String id = StringUtil.decapitalize(PathUtil
250                         .getBaseName(fileName));
251                 uiComponent.setId(id);
252             }
253         }
254     }
255 
256     /**
257      * ID の自動設定を有効にするかどうかを返します。<br />
258      * デフォルトでは <code>false</code> を返します。<br />
259      * 本機能を有効にする場合、サブクラスでオーバーライドして <code>true</code> を返してください。<br />
260      * 
261      * @return ID の自動設定を有効にするかどうか
262      */
263     protected boolean enableAutoId() {
264         return false;
265     }
266 
267     protected void setupAutoTitle(final UIElement element) {
268         if (element instanceof UIComponent) {
269             UIComponent uiComponent = (UIComponent) element;
270             BeanDesc desc = BeanDescFactory.getBeanDesc(uiComponent.getClass());
271             if (desc.hasPropertyDesc("title")) {
272                 PropertyDesc pd = desc.getPropertyDesc("title");
273 
274                 if (StringUtil.isEmpty((String) pd.getValue(uiComponent))) {
275                     String fileName = PathUtil.getFileName(uiComponent
276                             .getPath());
277                     String title = PathUtil.getBaseName(fileName);
278                     pd.setValue(uiComponent, title);
279                 }
280             }
281         }
282     }
283 
284     /**
285      * タイトルの自動設定を有効にするかどうかを返します。<br />
286      * デフォルトでは <code>false</code> を返します。<br />
287      * 本機能を有効にする場合、サブクラスでオーバーライドして <code>true</code> を返してください。<br />
288      * 
289      * @return タイトルの自動設定を有効にするかどうか
290      */
291     protected boolean enableAutoTitle() {
292         return false;
293     }
294 }