View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *  http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.any23.validator;
19  
20  import org.w3c.dom.Element;
21  
22  import java.io.OutputStream;
23  import java.io.PrintStream;
24  import java.lang.annotation.Documented;
25  import java.lang.annotation.ElementType;
26  import java.lang.annotation.Retention;
27  import java.lang.annotation.RetentionPolicy;
28  import java.lang.annotation.Target;
29  import java.lang.reflect.Array;
30  import java.lang.reflect.Method;
31  import java.lang.reflect.Modifier;
32  import java.util.ArrayList;
33  import java.util.Collection;
34  import java.util.List;
35  
36  /**
37   * Default implementation of {@link ValidationReportSerializer}
38   * for <i>XML</i>.
39   *
40   * @author Michele Mostarda (mostarda@fbk.eu)
41   */
42  public class XMLValidationReportSerializer implements ValidationReportSerializer {
43  
44      @Override
45      public void serialize(ValidationReport vr, OutputStream os) throws SerializationException {
46          final PrintStream ps = new PrintStream(os);
47          try {
48              serializeObject(vr, ps);
49          } finally {
50              ps.flush();
51          }
52      }
53  
54      private void serializeObject(Object o, PrintStream ps) throws SerializationException {
55          if(o == null) {
56              return;
57          }
58          final Class<? extends Object> oClass = o.getClass();
59          final String oClassName = getClassName(oClass);
60          ps.printf("<%s>%n", oClassName);
61          List<Method> getters = filterGetters(o.getClass());
62          if(getters.isEmpty()) {
63              ps.print( o.toString() );
64              return;
65          }
66          for (Method getter : getters) {
67              serializeGetterValue(o, getter, ps);
68          }
69          ps.printf("</%s>%n", oClassName);
70      }
71  
72      private String getClassName(Class<? extends Object> oClass) {
73          final NodeName nodeName = oClass.getAnnotation(NodeName.class);
74          if(nodeName != null) {
75              return nodeName.value();
76          }
77          final String simpleName = oClass.getSimpleName();
78          return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
79      }
80  
81      private List<Method> filterGetters(Class<? extends Object> c) {
82          Method[] methods = c.getDeclaredMethods();
83          List<Method> filtered = new ArrayList<>();
84          for(Method method : methods) {
85              if(Modifier.isStatic(method.getModifiers())) {
86                  continue;
87              }
88              final String methodName = method.getName();
89              if(
90                      method.getParameterTypes().length == 0
91                          &&
92                      (
93                              (methodName.length() > 3 && methodName.indexOf("get") == 0)
94                                      ||
95                              (methodName.length() > 2 && methodName.indexOf("is")  == 0)
96                      )
97              ) {
98                  filtered.add(method);
99              }
100         }
101         return filtered;
102     }
103 
104     public void serializeGetterValue(Object o, Method m, PrintStream ps) throws SerializationException {
105         final Object value;
106         final String methodName = m.getName();
107         try {
108             value = m.invoke(o);
109         } catch (Exception e) {
110             throw new SerializationException( String.format("Error while reading method '%s'", methodName), e );
111         }
112         final String property = getPropertyFromMethodName(methodName);
113         if( isManaged(value) ) {
114             ps.printf("<%s>%n", property);
115             printObject(value, ps);
116             ps.printf("</%s>%n", property);
117         } else {
118             List<Method> getters = filterGetters(value.getClass());
119             for (Method getter : getters) {
120                 serializeGetterValue(value, getter, ps);
121             }
122         }
123     }
124 
125     private String getPropertyFromMethodName(String methodName) {
126         int i = methodName.indexOf("is");
127         if(i == 0) {
128             return Character.toLowerCase( methodName.charAt(2) ) + methodName.substring(3);
129         }
130         return Character.toLowerCase( methodName.charAt(3) ) + methodName.substring(4);
131     }
132 
133     private void printObject(Object o, PrintStream ps) throws SerializationException {
134         if(o == null) {
135             return;
136         }
137         if(o instanceof Element) {
138             ps.print( o.toString() );
139             return;
140         }
141         if(o instanceof Array) {
142             Object[] array = (Object[]) o;
143             if(array.length == 0) {
144                 return;
145             }
146             for(Object a : array) {
147                 serializeObject(a, ps);
148             }
149             return;
150         }
151         if(o instanceof Collection) {
152             Collection<?> collection = (Collection<?>) o;
153             if(collection.isEmpty()) {
154                 return;
155             }
156             for(Object e : collection) {
157                 serializeObject(e, ps);
158             }
159             return;
160         }
161         ps.print( o.toString() );
162     }
163 
164     private boolean isManaged(Object o) {
165         return
166                 o == null
167                         ||
168                 o instanceof String
169                         ||
170                 o.getClass().isPrimitive()
171                         ||
172                 (o instanceof Collection)
173                         ||
174                 o instanceof Element;
175     }
176 
177     /**
178      * Allows to specify a custom node name.
179      */
180     @Documented
181     @Retention(RetentionPolicy.RUNTIME)
182     @Target(ElementType.TYPE)
183     public @interface NodeName {
184         String value();
185     }
186     
187 }