View Javadoc

1   /* This file is part of COPAL (COntext Provisioning for All).
2    *
3    * COPAL is a part of SM4All (Smart hoMes for All) project.
4    *
5    * COPAL is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU Lesser General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * COPAL 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
13   * GNU Lesser General Public License for more details.
14   *
15   * You should have received a copy of the GNU Lesser General Public License
16   * along with COPAL. If not, see <http://www.gnu.org/licenses/>.
17   */
18  package at.ac.tuwien.infosys.sm4all.copal.rest.provider;
19  
20  import java.io.OutputStream;
21  import java.lang.annotation.Annotation;
22  import java.lang.reflect.Type;
23  import javax.ws.rs.Produces;
24  import javax.ws.rs.WebApplicationException;
25  import javax.ws.rs.core.MediaType;
26  import javax.ws.rs.core.MultivaluedMap;
27  import javax.ws.rs.core.Response.Status;
28  import javax.ws.rs.ext.MessageBodyWriter;
29  import javax.ws.rs.ext.Provider;
30  import javax.xml.parsers.DocumentBuilderFactory;
31  import javax.xml.parsers.ParserConfigurationException;
32  import javax.xml.transform.OutputKeys;
33  import javax.xml.transform.Transformer;
34  import javax.xml.transform.TransformerConfigurationException;
35  import javax.xml.transform.TransformerException;
36  import javax.xml.transform.TransformerFactory;
37  import javax.xml.transform.dom.DOMSource;
38  import javax.xml.transform.stream.StreamResult;
39  import org.w3c.dom.Document;
40  import org.w3c.dom.Element;
41  import at.ac.tuwien.infosys.sm4all.copal.api.xml.Constants;
42  
43  /**
44   * An abstract {@link MessageBodyWriter} that writes an instance of a
45   * {@link Class} into an <code>application/xml</code> {@link OutputStream}.
46   * 
47   * @param <T> the type of written value.
48   * @author sanjin
49   */
50  @Provider
51  @Produces("application/xml")
52  public abstract class XMLWriter<T> implements MessageBodyWriter<T> {
53  
54      private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
55      private final TransformerFactory transformerFactory = TransformerFactory.newInstance();
56      private final Class<T> type;
57  
58      /**
59       * Creates instance of {@link MessageBodyWriter} that writes an instance of
60       * specified {@link Class} into an <code>application/xml</code>
61       * {@link OutputStream}.
62       * 
63       * @param type the {@link Class} of instances that are written.
64       */
65      protected XMLWriter(final Class<T> type) {
66          super();
67  
68          this.documentBuilderFactory.setNamespaceAware(true);
69          this.type = type;
70      }
71  
72      @Override
73      public long getSize(final T value, final Class<?> klass,
74              final Type genericType, final Annotation[] annotations,
75              final MediaType mediaType) {
76          return -1;
77      }
78  
79      @Override
80      public boolean isWriteable(final Class<?> klass, final Type genericType,
81              final Annotation[] annotations, final MediaType mediaType) {
82          return this.type.isAssignableFrom(klass);
83      }
84  
85      @Override
86      public void writeTo(final T value, final Class<?> klass,
87              final Type genericType, final Annotation[] annotations,
88              final MediaType mediaType,
89              final MultivaluedMap<String, Object> httpHeaders,
90              final OutputStream out) throws WebApplicationException {
91          try {
92              final Transformer transformer = this.transformerFactory.newTransformer();
93              transformer.setOutputProperty(OutputKeys.INDENT, "yes");
94  
95              final Document document = this.documentBuilderFactory.newDocumentBuilder().newDocument();
96              final Element context = document.createElementNS(
97                      Constants.COPAL_NAMESPACE, Constants.COPAL_PREFIX
98                              + ":Context");
99              marshal(value, context);
100             document.appendChild(context);
101 
102             final StreamResult result = new StreamResult(out);
103             final DOMSource source = new DOMSource(document);
104             transformer.transform(source, result);
105         } catch (final TransformerConfigurationException ex) {
106             throw new WebApplicationException(ex, Status.INTERNAL_SERVER_ERROR);
107         } catch (final ParserConfigurationException ex) {
108             throw new WebApplicationException(ex, Status.INTERNAL_SERVER_ERROR);
109         } catch (final TransformerException ex) {
110             throw new WebApplicationException(ex, Status.INTERNAL_SERVER_ERROR);
111         }
112     }
113 
114     /**
115      * Marshal specified value into specified {@link Element}.
116      * 
117      * @param value the value to be marshaled.
118      * @param element the {@link Element} used for marshalling.
119      */
120     protected abstract void marshal(T value, final Element element);
121 }