View Javadoc

1   /*
2    * Copyright 2007-2013 smartics, Kronseder & Reiner GmbH
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, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.exceptions.report.utils;
17  
18  import java.io.StringReader;
19  import java.util.Iterator;
20  
21  import javax.xml.stream.XMLEventReader;
22  import javax.xml.stream.XMLInputFactory;
23  import javax.xml.stream.XMLStreamException;
24  import javax.xml.stream.XMLStreamWriter;
25  import javax.xml.stream.events.Attribute;
26  import javax.xml.stream.events.Characters;
27  import javax.xml.stream.events.StartElement;
28  import javax.xml.stream.events.XMLEvent;
29  
30  /**
31   * Copies XML information read from one source to another.
32   */
33  public class CopyReader
34  {
35    // ********************************* Fields *********************************
36  
37    // --- constants ------------------------------------------------------------
38  
39    /**
40     * The generic identifier (GI) of the artificial element that is added if the
41     * fragment is not enclosed in an element.
42     * <p>
43     * The value of this constant is {@value}.
44     */
45    private static final String ARTIFICIAL_GI = "root";
46  
47    /**
48     * The artificial start tag with the {@link #ARTIFICIAL_GI}.
49     * <p>
50     * The value of this constant is {@value}.
51     */
52    private static final String ARTIFICIAL_START_TAG = '<' + ARTIFICIAL_GI + '>';
53  
54    /**
55     * The artificial end tag with the {@link #ARTIFICIAL_GI}.
56     * <p>
57     * The value of this constant is {@value}.
58     */
59    private static final String ARTIFICIAL_END_TAG = "</" + ARTIFICIAL_GI + '>';
60  
61    // --- members --------------------------------------------------------------
62  
63    /**
64     * The writer to write to. The caller is responsible to release the resource.
65     */
66    private final XMLStreamWriter xmlWriter;
67  
68    // ****************************** Initializer *******************************
69  
70    // ****************************** Constructors ******************************
71  
72    /**
73     * Default constructor.
74     *
75     * @param xmlWriter the writer to write to.
76     */
77    public CopyReader(final XMLStreamWriter xmlWriter)
78    {
79      this.xmlWriter = xmlWriter;
80    }
81  
82    // ****************************** Inner Classes *****************************
83  
84    // ********************************* Methods ********************************
85  
86    // --- init -----------------------------------------------------------------
87  
88    // --- get&set --------------------------------------------------------------
89  
90    // --- business -------------------------------------------------------------
91  
92    /**
93     * Copies the XML fragment to the writer.
94     *
95     * @param xmlFragment the XML fragment to read and write to the writer.
96     * @throws XMLStreamException on any problem reading from the fragment.
97     */
98    public void copy(final String xmlFragment) throws XMLStreamException
99    {
100     final XMLInputFactory factory = XMLInputFactory.newInstance();
101     final boolean isFragment = isFragment(xmlFragment);
102     final XMLEventReader eventReader;
103     if (isFragment)
104     {
105       eventReader = factory.createXMLEventReader(new StringReader(
106           ARTIFICIAL_START_TAG + xmlFragment + ARTIFICIAL_END_TAG));
107       boolean run = true;
108       while (run && eventReader.hasNext())
109       {
110         final XMLEvent event = eventReader.nextEvent();
111         if (event.getEventType() == XMLEvent.START_ELEMENT)
112         {
113           run = false;
114         }
115       }
116     }
117     else
118     {
119       eventReader = factory.createXMLEventReader(new StringReader(xmlFragment));
120     }
121     parse(eventReader);
122   }
123 
124   /**
125    * Checks if the given XML fragment is not enclosed within an element.
126    *
127    * @param xmlFragment the XML fragment to check.
128    * @return <code>true</code> if the fragment is not enclosed in an element,
129    *         <code>false</code> otherwise.
130    */
131   private static boolean isFragment(final String xmlFragment)
132   {
133     return xmlFragment.charAt(0) != '<';
134   }
135 
136   /**
137    * Parses the events from the given event reader.
138    *
139    * @param eventReader the event reader to read the events from.
140    * @throws XMLStreamException on any problem reading the events.
141    */
142   private void parse(final XMLEventReader eventReader)
143       throws XMLStreamException
144   {
145     int level = 0; // NOPMD
146     while (eventReader.hasNext())
147     {
148       final XMLEvent event = eventReader.nextEvent();
149       switch (event.getEventType())
150       {
151         case XMLEvent.START_ELEMENT:
152           level++; // NOPMD
153           handleStartElement(event);
154           break;
155         case XMLEvent.END_ELEMENT:
156           level--;
157           if (level >= 0)
158           {
159             xmlWriter.writeEndElement();
160           }
161           break;
162         case XMLEvent.CHARACTERS:
163           final Characters chars = event.asCharacters();
164           xmlWriter.writeCharacters(chars.getData());
165         default:
166           // Just skip...
167           break;
168       }
169     }
170   }
171 
172   /**
173    * Handles the start element with all of its attributes.
174    *
175    * @param event the event required to be a {@link StartElement}.
176    * @throws XMLStreamException on any parsing problem.
177    */
178   @SuppressWarnings("unchecked")
179   private void handleStartElement(final XMLEvent event)
180       throws XMLStreamException
181   {
182     final StartElement element = event.asStartElement();
183     final String gi = element.getName().toString();
184     xmlWriter.writeStartElement(gi);
185     for (final Iterator<Attribute> i = element.getAttributes(); i.hasNext();)
186     {
187       final Attribute attribute = i.next();
188       xmlWriter.writeAttribute(attribute.getName().toString(), attribute
189           .getValue());
190     }
191   }
192 
193   // --- object basics --------------------------------------------------------
194 
195 }