1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.filter.xml.internal.serializer

File DefaultXMLSerializer.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

78
128
15
1
371
265
63
0.49
8.53
15
4.2

Classes

Class Line # Actions
DefaultXMLSerializer 54 128 0% 63 27
0.8778280687.8%
 

Contributing tests

This file is covered by 308 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.filter.xml.internal.serializer;
21   
22    import java.io.Closeable;
23    import java.io.IOException;
24    import java.lang.reflect.InvocationHandler;
25    import java.lang.reflect.Method;
26    import java.lang.reflect.Type;
27    import java.util.Arrays;
28    import java.util.List;
29    import java.util.Objects;
30    import java.util.regex.Pattern;
31   
32    import javax.xml.stream.FactoryConfigurationError;
33    import javax.xml.stream.XMLStreamException;
34    import javax.xml.stream.XMLStreamWriter;
35    import javax.xml.transform.Result;
36   
37    import org.xwiki.component.util.ReflectionUtils;
38    import org.xwiki.filter.FilterDescriptor;
39    import org.xwiki.filter.FilterElementDescriptor;
40    import org.xwiki.filter.FilterElementParameterDescriptor;
41    import org.xwiki.filter.internal.DefaultFilterDescriptorManager;
42    import org.xwiki.filter.xml.XMLConfiguration;
43    import org.xwiki.filter.xml.internal.XMLUtils;
44    import org.xwiki.filter.xml.internal.parameter.ParameterManager;
45    import org.xwiki.properties.ConverterManager;
46    import org.xwiki.xml.stax.StAXUtils;
47   
48    /**
49    * Proxy called as an event filter to produce SAX events.
50    *
51    * @version $Id: 9657502de1102e7626b691e17a8213ba8f120508 $
52    * @since 5.2M1
53    */
 
54    public class DefaultXMLSerializer implements InvocationHandler, Closeable
55    {
56    private static final Pattern VALID_ELEMENTNAME = Pattern.compile("[A-Za-z][A-Za-z0-9:_.-]*");
57   
58    private final XMLStreamWriter xmlStreamWriter;
59   
60    private final ParameterManager parameterManager;
61   
62    private final FilterDescriptor descriptor;
63   
64    private final ConverterManager converter;
65   
66    private final XMLConfiguration configuration;
67   
 
68  564 toggle public DefaultXMLSerializer(Result result, ParameterManager parameterManager, FilterDescriptor descriptor,
69    ConverterManager converter, XMLConfiguration configuration) throws XMLStreamException, FactoryConfigurationError
70    {
71  564 this.parameterManager = parameterManager;
72  564 this.descriptor = descriptor;
73  564 this.converter = converter;
74  564 this.configuration = configuration != null ? configuration : new XMLConfiguration();
75   
76  564 this.xmlStreamWriter = StAXUtils.getXMLStreamWriter(result);
77    }
78   
 
79  19491 toggle private boolean isValidBlockElementName(String blockName)
80    {
81  19491 return VALID_ELEMENTNAME.matcher(blockName).matches()
82    && !this.configuration.getElementParameters().equals(blockName);
83    }
84   
 
85  5099 toggle private boolean isValidParameterElementName(String parameterName)
86    {
87  5099 return VALID_ELEMENTNAME.matcher(parameterName).matches()
88    && !XMLUtils.INDEX_PATTERN.matcher(parameterName).matches();
89    }
90   
 
91  3681 toggle private boolean isValidParameterAttributeName(String parameterName)
92    {
93  3681 return isValidParameterElementName(parameterName)
94    && !this.configuration.getAttributeParameterName().equals(parameterName);
95    }
96   
 
97  0 toggle private String getBlockName(String eventName)
98    {
99  0 String blockName = Character.toLowerCase(eventName.charAt(0)) + eventName.substring(1);
100   
101  0 return blockName;
102    }
103   
 
104  4148 toggle private void writeInlineParameters(List<Object> parameters, FilterElementDescriptor element)
105    throws XMLStreamException
106    {
107  11834 for (int i = 0; i < parameters.size(); ++i) {
108  7686 Object parameterValue = parameters.get(i);
109   
110  7686 if (parameterValue != null) {
111  3681 FilterElementParameterDescriptor<?> filterParameter = element.getParameters()[i];
112   
113  3681 if (!Objects.equals(filterParameter.getDefaultValue(), parameterValue)) {
114  3681 Class<?> typeClass = ReflectionUtils.getTypeClass(filterParameter.getType());
115   
116  3681 String attributeName;
117   
118  3681 if (filterParameter.getName() != null) {
119  3681 if (isValidParameterAttributeName(filterParameter.getName())) {
120  3681 attributeName = filterParameter.getName();
121    } else {
122  0 attributeName = null;
123    }
124    } else {
125  0 attributeName = "_" + filterParameter.getIndex();
126    }
127   
128  3681 if (attributeName != null) {
129  3681 if (parameterValue instanceof String) {
130  1693 this.xmlStreamWriter.writeAttribute(attributeName, (String) parameterValue);
131   
132  1693 parameters.set(filterParameter.getIndex(), null);
133  1988 } else if (XMLUtils.isSimpleType(typeClass)) {
134  513 this.xmlStreamWriter.writeAttribute(attributeName,
135    this.converter.<String>convert(String.class, parameterValue));
136   
137  513 parameters.set(filterParameter.getIndex(), null);
138  1475 } else if (Objects.equals(XMLUtils.emptyValue(typeClass), parameterValue)) {
139  57 this.xmlStreamWriter.writeAttribute(attributeName, "");
140   
141  57 parameters.set(filterParameter.getIndex(), null);
142    }
143    }
144    }
145    }
146    }
147    }
148   
 
149  4772 toggle private void writeStartAttributes(String blockName, List<Object> parameters) throws XMLStreamException
150    {
151  4772 if (!isValidBlockElementName(blockName)) {
152  0 this.xmlStreamWriter.writeAttribute(this.configuration.getAttributeBlockName(), blockName);
153    }
154   
155  4772 if (parameters != null) {
156  4148 FilterElementDescriptor element = this.descriptor.getElement(blockName);
157   
158  4148 writeInlineParameters(parameters, element);
159    }
160    }
161   
 
162  14719 toggle private void removeDefaultParameters(List<Object> parameters, FilterElementDescriptor descriptor)
163    {
164  14719 if (parameters != null) {
165  23724 for (int i = 0; i < parameters.size(); ++i) {
166  13631 Object value = parameters.get(i);
167   
168  13631 if (!shouldWriteParameter(value, descriptor.getParameters()[i])) {
169  4056 parameters.set(i, null);
170    }
171    }
172    }
173    }
174   
 
175  3918 toggle private void beginEvent(Method method, Object[] parameters) throws XMLStreamException
176    {
177  3918 String blockName = DefaultFilterDescriptorManager.getElementName(method, true);
178   
179  3918 FilterElementDescriptor element = this.descriptor.getElement(blockName);
180   
181  3918 List<Object> elementParameters = parameters != null ? Arrays.asList(parameters) : null;
182   
183    // Remove useless parameters
184  3918 removeDefaultParameters(elementParameters, element);
185   
186    // Get proper element name
187  3918 String elementName;
188  3918 if (isValidBlockElementName(blockName)) {
189  3918 elementName = blockName;
190    } else {
191  0 elementName = this.configuration.getElementBlock();
192    }
193   
194    // Print start element
195  3918 this.xmlStreamWriter.writeStartElement(elementName);
196   
197    // Put as attributes parameters which are simple enough to not require full XML serialization
198  3918 writeStartAttributes(blockName, elementParameters);
199   
200    // Write complex parameters
201  3918 writeParameters(elementParameters, element);
202    }
203   
 
204  3918 toggle private void endEvent() throws XMLStreamException
205    {
206  3918 this.xmlStreamWriter.writeEndElement();
207    }
208   
 
209  10801 toggle private void onEvent(Method method, Object[] parameters) throws XMLStreamException
210    {
211  10801 String blockName = DefaultFilterDescriptorManager.getElementName(method, true);
212   
213  10801 FilterElementDescriptor element = this.descriptor.getElement(blockName);
214   
215  10801 List<Object> elementParameters = parameters != null ? Arrays.asList(parameters) : null;
216   
217    // Remove useless parameters
218  10801 removeDefaultParameters(elementParameters, element);
219   
220    // Get proper element name
221  10801 String elementName;
222  10801 if (isValidBlockElementName(blockName)) {
223  10801 elementName = blockName;
224    } else {
225  0 elementName = this.configuration.getElementBlock();
226    }
227   
228    // Write start element
229  10801 this.xmlStreamWriter.writeStartElement(elementName);
230   
231    // Put as attributes parameters which are simple enough to not require full XML serialization
232  10801 if (elementParameters != null && elementParameters.size() > 1) {
233  854 writeStartAttributes(blockName, Arrays.asList(parameters));
234    }
235   
236    // Write complex parameters
237  10801 if (parameters != null && parameters.length == 1
238    && XMLUtils.isSimpleType(element.getParameters()[0].getType())) {
239  5902 Object parameter = parameters[0];
240  5902 if (parameter != null && !Objects.equals(element.getParameters()[0].getDefaultValue(), parameter)) {
241  5894 String value = parameter.toString();
242  5894 this.xmlStreamWriter.writeCharacters(value);
243    }
244    } else {
245  4899 writeParameters(elementParameters, element);
246    }
247   
248    // Write end element
249  10801 this.xmlStreamWriter.writeEndElement();
250    }
251   
 
252  21360 toggle private boolean shouldWriteParameter(Object value, FilterElementParameterDescriptor<?> filterParameter)
253    {
254  21360 boolean write;
255   
256  21360 if (value != null && !Objects.equals(filterParameter.getDefaultValue(), value)) {
257  11511 write = true;
258   
259  11511 Type type = filterParameter.getType();
260   
261  11511 if (type instanceof Class) {
262  10865 Class<?> typeClass = (Class<?>) type;
263  10865 try {
264  10865 if (typeClass.isPrimitive()) {
265  1363 write = !XMLUtils.emptyValue(typeClass).equals(value);
266    }
267    } catch (Exception e) {
268    // Should never happen
269    }
270    }
271    } else {
272  9849 write = false;
273    }
274   
275  21360 return write;
276    }
277   
 
278  8817 toggle private void writeParameters(List<Object> parameters, FilterElementDescriptor descriptor) throws XMLStreamException
279    {
280  8817 if (parameters != null && !parameters.isEmpty()) {
281  4191 boolean writeContainer = false;
282   
283  4191 for (Object parameter : parameters) {
284  6996 if (parameter != null) {
285  1366 writeContainer = true;
286  1366 break;
287    }
288    }
289   
290  4191 if (writeContainer) {
291  1366 this.xmlStreamWriter.writeStartElement(this.configuration.getElementParameters());
292    }
293   
294  11920 for (int i = 0; i < parameters.size(); ++i) {
295  7729 Object parameterValue = parameters.get(i);
296   
297  7729 FilterElementParameterDescriptor<?> filterParameter = descriptor.getParameters()[i];
298   
299  7729 if (shouldWriteParameter(parameterValue, filterParameter)) {
300  1418 String elementName;
301  1418 String attributeName = null;
302  1418 String attributeValue = null;
303   
304  1418 if (filterParameter.getName() != null) {
305  1418 if (isValidParameterElementName(filterParameter.getName())) {
306  1418 elementName = filterParameter.getName();
307    } else {
308  0 elementName = "_" + filterParameter.getIndex();
309  0 attributeName = this.configuration.getAttributeParameterName();
310  0 attributeValue = filterParameter.getName();
311    }
312    } else {
313  0 elementName = "_" + filterParameter.getIndex();
314    }
315   
316  1418 this.xmlStreamWriter.writeStartElement(elementName);
317   
318  1418 if (attributeName != null) {
319  0 this.xmlStreamWriter.writeAttribute(attributeName, attributeValue);
320    }
321  1418 if (descriptor.getParameters()[i].getType() == Object.class
322    && parameterValue.getClass() != String.class) {
323  10 this.xmlStreamWriter.writeAttribute(this.configuration.getAttributeParameterType(),
324    parameterValue.getClass().getCanonicalName());
325    }
326   
327  1418 this.parameterManager.serialize(descriptor.getParameters()[i].getType(), parameterValue,
328    this.xmlStreamWriter);
329   
330  1418 this.xmlStreamWriter.writeEndElement();
331    }
332    }
333   
334  4191 if (writeContainer) {
335  1366 this.xmlStreamWriter.writeEndElement();
336    }
337    }
338    }
339   
 
340  18662 toggle @Override
341    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
342    {
343  18662 Object result = null;
344   
345  18662 if (method.getDeclaringClass() == Closeable.class) {
346  25 close();
347    } else {
348  18637 if (method.getName().startsWith("begin")) {
349  3918 beginEvent(method, args);
350  14719 } else if (method.getName().startsWith("end")) {
351  3918 endEvent();
352  10801 } else if (method.getName().startsWith("on")) {
353  10801 onEvent(method, args);
354    } else {
355  0 throw new NoSuchMethodException(method.toGenericString());
356    }
357    }
358   
359  18662 return result;
360    }
361   
 
362  25 toggle @Override
363    public void close() throws IOException
364    {
365  25 try {
366  25 this.xmlStreamWriter.close();
367    } catch (XMLStreamException e) {
368  0 throw new IOException(e);
369    }
370    }
371    }