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.writer;
17  
18  import java.io.IOException;
19  import java.io.Writer;
20  import java.lang.reflect.Field;
21  import java.util.List;
22  
23  import org.seasar.framework.util.FieldUtil;
24  import org.seasar.framework.util.StringUtil;
25  import org.seasar.uruma.annotation.ComponentAttribute;
26  import org.seasar.uruma.annotation.ComponentElement;
27  import org.seasar.uruma.component.Template;
28  import org.seasar.uruma.component.UIComponentContainer;
29  import org.seasar.uruma.component.UIElement;
30  import org.seasar.uruma.component.UIElementContainer;
31  import org.seasar.uruma.component.UIElementVisitor;
32  import org.seasar.uruma.core.UrumaConstants;
33  import org.seasar.uruma.util.AnnotationUtil;
34  import org.seasar.uruma.util.AssertionUtil;
35  
36  /**
37   * {@link UIElement} を XML ファイルへ出力するためのクラスです。<br />
38   * 
39   * @author y-komori
40   */
41  public class UIElementWriter implements UIElementVisitor, UrumaConstants {
42      protected Writer writer;
43  
44      private int indentLevel;
45  
46      private static final String INDENT = "  ";
47  
48      /**
49       * {@link UIElementWriter} を構築します。<br />
50       * 
51       * @param writer
52       *            XML ファイルの出力先 {@link Writer} オブジェクト。
53       */
54      public UIElementWriter(final Writer writer) {
55          AssertionUtil.assertNotNull("writer", writer);
56          this.writer = writer;
57      }
58  
59      /*
60       * @see org.seasar.uruma.component.UIElementVisitor#visit(org.seasar.uruma.component.UIElement)
61       */
62      public void visit(final UIElement element) {
63          AssertionUtil.assertNotNull("element", element);
64  
65          try {
66              writeStartTag(element, true);
67          } catch (IOException ex) {
68              // TODO 自動生成された catch ブロック
69              ex.printStackTrace();
70          }
71      }
72  
73      /*
74       * @see org.seasar.uruma.component.UIElementVisitor#visit(org.seasar.uruma.component.UIElementContainer)
75       */
76      public void visit(final UIElementContainer container) {
77          AssertionUtil.assertNotNull("container", container);
78  
79          try {
80              writeStartTag(container, false);
81  
82              indent();
83              for (UIElement element : container.getChildren()) {
84                  element.accept(this);
85              }
86              deindent();
87  
88              writeEndTag(container);
89          } catch (IOException ex) {
90              // TODO 自動生成された catch ブロック
91              ex.printStackTrace();
92          }
93      }
94  
95      /*
96       * @see org.seasar.uruma.component.UIElementVisitor#visit(org.seasar.uruma.component.Template)
97       */
98      public void visit(final Template template) {
99          AssertionUtil.assertNotNull("template", template);
100         try {
101             writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
102             writer
103                     .write("<template xmlns=\"http://uruma.sandbox.seasar.org\">\n");
104             indent();
105 
106             UIComponentContainer root = template.getRootComponent();
107             if (root != null) {
108                 root.accept(this);
109             }
110 
111             deindent();
112             writer.write("</template>\n");
113             writer.flush();
114         } catch (IOException ex) {
115             // TODO: handle exception
116         }
117     }
118 
119     protected void writeStartTag(final UIElement element,
120             final boolean startTagOnly) throws IOException {
121         String elementName = getElementName(element.getClass());
122         if (elementName == null) {
123             // TODO Warning 出力
124             return;
125         }
126 
127         writeIndent();
128         writer.write('<');
129         writer.write(elementName);
130 
131         List<Field> fields = AnnotationUtil.getAnnotatedFields(element
132                 .getClass(), ComponentAttribute.class);
133 
134         for (Field field : fields) {
135             String attrName = getAttributeName(field);
136             String value = FieldUtil.getString(field, element);
137             if (value == null) {
138                 ComponentAttribute attr = field
139                         .getAnnotation(ComponentAttribute.class);
140                 if (attr.required()) {
141                     value = NULL_STRING;
142                 }
143             }
144 
145             if (value != null) {
146                 writer.write(' ');
147                 writer.write(attrName);
148                 writer.write("=\"");
149                 writer.write(value);
150                 writer.write('"');
151             }
152         }
153 
154         if (startTagOnly) {
155             writer.write(" />\n");
156         } else {
157             writer.write(" >\n");
158         }
159         writer.flush();
160     }
161 
162     protected void writeEndTag(final UIElement element) throws IOException {
163         String elementName = getElementName(element.getClass());
164         if (elementName == null) {
165             // TODO Warning 出力
166             return;
167         }
168 
169         writeIndent();
170         writer.write("</");
171         writer.write(elementName);
172         writer.write(">\n");
173         writer.flush();
174     }
175 
176     /**
177      * クラスオブジェクトから要素名を取得します。<br />
178      * {@link ComponentElement} アノテーションを読み取り、その値を要素名として返します。<br />
179      * {@link ComponentElement} アノテーションの値がない場合、クラス名のサフィックス
180      * <code>Component</code> を除いた名称をデキャピタライズしたものを要素名とします。<br />
181      * 【例】クラス名が ButtonComponent の場合、button が要素名になります。<br />
182      * 
183      * @param clazz
184      *            要素名を取得する {@link Class} オブジェクト
185      * @return 要素名。取得に失敗した場合は <code>null</code>。
186      */
187     protected String getElementName(final Class<?> clazz) {
188         ComponentElement anno = clazz.getAnnotation(ComponentElement.class);
189         if (anno == null) {
190             return null;
191         }
192 
193         String elementName = anno.value();
194         if (NULL_STRING.equals(elementName)) {
195             String className = clazz.getSimpleName();
196             if (className.endsWith("Component")) {
197                 elementName = className.substring(0, className.length()
198                         - "Component".length());
199                 elementName = StringUtil.decapitalize(elementName);
200             } else {
201                 return null;
202             }
203         }
204 
205         return elementName;
206     }
207 
208     protected String getAttributeName(final Field field) {
209         ComponentAttribute attr = field.getAnnotation(ComponentAttribute.class);
210         if (attr == null) {
211             return null;
212         }
213 
214         String attrName = attr.name();
215         if (NULL_STRING.equals(attrName)) {
216             attrName = field.getName();
217         }
218         return attrName;
219     }
220 
221     protected void writeIndent() throws IOException {
222         StringBuffer buf = new StringBuffer(INDENT.length() * indentLevel);
223         for (int i = 0; i < indentLevel; i++) {
224             buf.append(INDENT);
225         }
226         writer.write(buf.toString());
227     }
228 
229     /**
230      * インデントをリセットします。<br />
231      */
232     public void resetIndent() {
233         indentLevel = 0;
234     }
235 
236     /**
237      * インデントレベルを下げます。<br />
238      */
239     public void indent() {
240         indentLevel++;
241     }
242 
243     /**
244      * インデントレベルを上げます。<br />
245      */
246     public void deindent() {
247         indentLevel--;
248     }
249 }