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.IOException;
21  import java.io.InputStream;
22  import java.lang.annotation.Annotation;
23  import java.lang.reflect.Type;
24  import javax.ws.rs.Consumes;
25  import javax.ws.rs.WebApplicationException;
26  import javax.ws.rs.core.MediaType;
27  import javax.ws.rs.core.MultivaluedMap;
28  import javax.ws.rs.core.Response.Status;
29  import javax.ws.rs.ext.MessageBodyReader;
30  import javax.ws.rs.ext.Provider;
31  import javax.xml.parsers.DocumentBuilder;
32  import javax.xml.parsers.DocumentBuilderFactory;
33  import javax.xml.parsers.ParserConfigurationException;
34  import org.w3c.dom.Element;
35  import org.xml.sax.SAXException;
36  import at.ac.tuwien.infosys.sm4all.copal.api.util.FailedUnmarshallingException;
37  
38  /**
39   * An abstract {@link MessageBodyReader} that reads an instance of a
40   * {@link Class} from an <code>application/xml</code> {@link InputStream}.
41   * 
42   * @param <T> the type of read value.
43   * @author sanjin
44   */
45  @Provider
46  @Consumes("application/xml")
47  public abstract class XMLReader<T> implements MessageBodyReader<T> {
48  
49      private final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
50  
51      /**
52       * Creates instance of {@link MessageBodyReader} that reads an instance of
53       * specified {@link Class} from an <code>application/xml</code>
54       * {@link InputStream}.
55       * 
56       * @param type the {@link Class} of instances that are read.
57       */
58      protected XMLReader(final Class<T> type) {
59          super();
60  
61          this.documentBuilderFactory.setNamespaceAware(true);
62      }
63  
64      @Override
65      public boolean isReadable(final Class<?> type, final Type genericType,
66              final Annotation[] annotations, final MediaType mediaType) {
67          return type.isAssignableFrom(type);
68      }
69  
70      @Override
71      public T readFrom(final Class<T> type, final Type genericType,
72              final Annotation[] annotations, final MediaType mediaType,
73              final MultivaluedMap<String, String> httpHeaders,
74              final InputStream input) throws IOException,
75              WebApplicationException {
76          final T result;
77  
78          try {
79              final DocumentBuilder builder = this.documentBuilderFactory.newDocumentBuilder();
80              final Element element = builder.parse(input).getDocumentElement();
81  
82              result = unmarshal(element);
83          } catch (final FailedUnmarshallingException ex) {
84              throw new WebApplicationException(ex, Status.BAD_REQUEST);
85          } catch (final ParserConfigurationException ex) {
86              throw new WebApplicationException(ex, Status.INTERNAL_SERVER_ERROR);
87          } catch (final SAXException ex) {
88              throw new WebApplicationException(ex, Status.BAD_REQUEST);
89          }
90  
91          return result;
92      }
93  
94      /**
95       * Unmarshal a value from specified {@link Element}.
96       * 
97       * @param element the {@link Element} used for unmarshalling.
98       * @return value the unmarshaled value.
99       * @throws FailedUnmarshallingException if unmarshalling was unsuccessful.
100      */
101     protected abstract T unmarshal(final Element element)
102             throws FailedUnmarshallingException;
103 }