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.io.UnsupportedEncodingException;
25  import java.lang.annotation.Documented;
26  import java.lang.annotation.ElementType;
27  import java.lang.annotation.Retention;
28  import java.lang.annotation.RetentionPolicy;
29  import java.lang.annotation.Target;
30  import java.lang.reflect.Array;
31  import java.lang.reflect.Method;
32  import java.lang.reflect.Modifier;
33  import java.util.ArrayList;
34  import java.util.Collection;
35  import java.util.List;
36  import java.util.Locale;
37  
38  /**
39   * Default implementation of {@link ValidationReportSerializer} for <i>XML</i>.
40   *
41   * @author Michele Mostarda (mostarda@fbk.eu)
42   */
43  public class XMLValidationReportSerializer implements ValidationReportSerializer {
44  
45      @Override
46      public void serialize(ValidationReport vr, OutputStream os) throws SerializationException {
47          PrintStream ps;
48          try {
49              ps = new PrintStream(os, true, "UTF-8");
50          } catch (UnsupportedEncodingException e) {
51              throw new RuntimeException("Error serializing the OuputStream as UTF-8 encoding.", e);
52          }
53          try {
54              serializeObject(vr, ps);
55          } finally {
56              ps.flush();
57          }
58      }
59  
60      private void serializeObject(Object o, PrintStream ps) throws SerializationException {
61          if (o == null) {
62              return;
63          }
64          final Class<? extends Object> oClass = o.getClass();
65          final String oClassName = getClassName(oClass);
66          ps.printf(Locale.ROOT, "<%s>%n", oClassName);
67          List<Method> getters = filterGetters(o.getClass());
68          if (getters.isEmpty()) {
69              ps.print(o.toString());
70              return;
71          }
72          for (Method getter : getters) {
73              serializeGetterValue(o, getter, ps);
74          }
75          ps.printf(Locale.ROOT, "</%s>%n", oClassName);
76      }
77  
78      private String getClassName(Class<? extends Object> oClass) {
79          final NodeName nodeName = oClass.getAnnotation(NodeName.class);
80          if (nodeName != null) {
81              return nodeName.value();
82          }
83          final String simpleName = oClass.getSimpleName();
84          return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
85      }
86  
87      private List<Method> filterGetters(Class<? extends Object> c) {
88          Method[] methods = c.getDeclaredMethods();
89          List<Method> filtered = new ArrayList<>();
90          for (Method method : methods) {
91              if (Modifier.isStatic(method.getModifiers())) {
92                  continue;
93              }
94              final String methodName = method.getName();
95              if (method.getParameterTypes().length == 0 && ((methodName.length() > 3 && methodName.indexOf("get") == 0)
96                      || (methodName.length() > 2 && methodName.indexOf("is") == 0))) {
97                  filtered.add(method);
98              }
99          }
100         return filtered;
101     }
102 
103     public void serializeGetterValue(Object o, Method m, PrintStream ps) throws SerializationException {
104         final Object value;
105         final String methodName = m.getName();
106         try {
107             value = m.invoke(o);
108         } catch (Exception e) {
109             throw new SerializationException(String.format(Locale.ROOT, "Error while reading method '%s'", methodName),
110                     e);
111         }
112         final String property = getPropertyFromMethodName(methodName);
113         if (isManaged(value)) {
114             ps.printf(Locale.ROOT, "<%s>%n", property);
115             printObject(value, ps);
116             ps.printf(Locale.ROOT, "</%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 o == null || o instanceof String || o.getClass().isPrimitive() || (o instanceof Collection)
166                 || o instanceof Element;
167     }
168 
169     /**
170      * Allows to specify a custom node name.
171      */
172     @Documented
173     @Retention(RetentionPolicy.RUNTIME)
174     @Target(ElementType.TYPE)
175     public @interface NodeName {
176         String value();
177     }
178 
179 }