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 }