ref #9359 upgrade cdmlib to log4j 2
[cdmlib.git] / cdmlib-io / src / main / java / eu / etaxonomy / cdm / io / jaxb / CdmDocumentBuilder.java
1 /**
2 * Copyright (C) 2008 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.cdm.io.jaxb;
11
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.IOException;
16 import java.io.InputStreamReader;
17 import java.io.Reader;
18 import java.io.UnsupportedEncodingException;
19 import java.io.Writer;
20 import eu.etaxonomy.cdm.common.URI;
21 import java.net.URISyntaxException;
22
23 import javax.xml.bind.JAXBException;
24 import javax.xml.bind.Marshaller;
25 import javax.xml.bind.PropertyException;
26 import javax.xml.parsers.ParserConfigurationException;
27 import javax.xml.parsers.SAXParser;
28 import javax.xml.parsers.SAXParserFactory;
29 import javax.xml.transform.Source;
30 import javax.xml.transform.sax.SAXResult;
31 import javax.xml.transform.sax.SAXSource;
32 import javax.xml.transform.stream.StreamResult;
33 import javax.xml.validation.Schema;
34 import javax.xml.validation.SchemaFactory;
35
36 import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;
37 import org.apache.xml.resolver.tools.CatalogResolver;
38 import org.springframework.core.io.ClassPathResource;
39 import org.springframework.core.io.Resource;
40 import org.springframework.oxm.UncategorizedMappingException;
41 import org.springframework.oxm.XmlMappingException;
42 import org.springframework.oxm.jaxb.Jaxb2Marshaller;
43 import org.xml.sax.InputSource;
44 import org.xml.sax.SAXException;
45 import org.xml.sax.XMLReader;
46 import org.xml.sax.helpers.XMLReaderFactory;
47
48 import eu.etaxonomy.cdm.jaxb.CdmNamespacePrefixMapper;
49 import eu.etaxonomy.cdm.jaxb.FormattedText;
50 import eu.etaxonomy.cdm.jaxb.MultilanguageTextElement;
51
52 /**
53 * Initializes a JaxbContext with one class (eu.etaxonomy.cdm.model.DataSet).
54 *
55 * @author a.babadshanjan, ben.clark
56 */
57 //Binds it to XML schemas found in /src/main/resources/schema/cdm (cdm.xsd, common.xsd, name.xsd).
58 //There is a bit of magic with a resource resolver in eu.etaxonomy.cdm.io.jaxb
59 //which allows to package the schemas into a jar file.
60 public class CdmDocumentBuilder extends Jaxb2Marshaller {
61
62 private static final Logger logger = LogManager.getLogger(CdmDocumentBuilder.class);
63 private boolean formattedOutput = Boolean.TRUE;
64 private String encoding = "UTF-8";
65
66 public static String CDM_NAMESPACE = "eu.etaxonomy.cdm.model";
67 public static String[] CDM_SCHEMA_FILES = { "/schema/cdm/agent.xsd",
68 "/schema/cdm/cdm.xsd",
69 "/schema/cdm/common.xsd",
70 "/schema/cdm/description.xsd",
71 "/schema/cdm/location.xsd",
72 "/schema/cdm/media.xsd",
73 "/schema/cdm/molecular.xsd",
74 "/schema/cdm/name.xsd",
75 "/schema/cdm/occurrence.xsd",
76 "/schema/cdm/reference.xsd",
77 "/schema/cdm/taxon.xsd"};
78 public static Class[] CONTEXT_CLASSES = {DataSet.class,FormattedText.class,MultilanguageTextElement.class};
79
80 private Resource schemas[];
81
82 protected String[] getSchemaFiles() {
83 return CDM_SCHEMA_FILES;
84 }
85
86 protected Class[] getContextClasses() {
87 return CONTEXT_CLASSES;
88 }
89
90 public CdmDocumentBuilder() {
91 schemas = new Resource[CDM_SCHEMA_FILES.length];
92
93 for(int i = 0; i < CDM_SCHEMA_FILES.length; i++) {
94 schemas[i] = new ClassPathResource(CDM_SCHEMA_FILES[i]);
95 }
96
97 super.setSchemas(schemas);
98 super.setClassesToBeBound(CONTEXT_CLASSES);
99 super.setSchemaLanguage("http://www.w3.org/2001/XMLSchema");
100 }
101
102 public CdmDocumentBuilder(boolean formattedOutput, String encoding) {
103 this.formattedOutput = formattedOutput;
104 this.encoding = encoding;
105 }
106
107
108 @Override
109 protected void initJaxbMarshaller(Marshaller marshaller) throws JAXBException {
110 try {
111 marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new CdmNamespacePrefixMapper() );
112
113 // For test purposes insert newlines to make the XML output readable
114 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formattedOutput);
115 //marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,"http://etaxonomy.eu/cdm/model/1.0 schema/cdm/cdm.xsd");
116 //marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,"http://etaxonomy.eu/cdm/model/1.0 cdm.xsd");
117 marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
118
119 CdmMarshallerListener marshallerListener = new CdmMarshallerListener();
120 marshaller.setListener(marshallerListener);
121 marshaller.setEventHandler(new WarningTolerantValidationEventHandler());
122 } catch(PropertyException pe) {
123 throw new JAXBException(pe.getMessage(),pe);
124 }
125 }
126
127 protected <T> T unmarshal(Class<T> clazz, InputSource input) {
128 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
129 Schema schema;
130 try {
131 schema = createSchema();
132 saxParserFactory.setNamespaceAware(true);
133 saxParserFactory.setXIncludeAware(true);
134 saxParserFactory.setValidating(true);
135 saxParserFactory.setSchema(schema);
136
137 SAXParser saxParser = saxParserFactory.newSAXParser();
138 XMLReader xmlReader = saxParser.getXMLReader();
139 xmlReader.setEntityResolver(new CatalogResolver());
140 xmlReader.setErrorHandler(new DefaultErrorHandler());
141 SAXSource saxSource = new SAXSource( xmlReader, input);
142 saxSource.setSystemId(input.getSystemId());
143
144 return (T)super.unmarshal(saxSource);
145 } catch (IOException e) {
146 throw new UncategorizedMappingException(e.getMessage(), e);
147 } catch (SAXException e) {
148 throw new UncategorizedMappingException(e.getMessage(), e);
149 } catch (ParserConfigurationException e) {
150 throw new UncategorizedMappingException(e.getMessage(), e);
151 }
152 }
153
154 private Schema createSchema() throws SAXException, IOException {
155 //method created to avoid dependency of spring-xml like in earlier versions
156 //old implementation was schema = SchemaLoaderUtils.loadSchema(schemas, "http://www.w3.org/2001/XMLSchema");
157 //maybe we can improve this loading in future
158
159 String schemaLanguage = "http://www.w3.org/2001/XMLSchema";
160 Source[] schemaSources = new Source[schemas.length];
161 XMLReader reader = XMLReaderFactory.createXMLReader();
162 reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
163 for (int i = 0; i < schemas.length; i++) {
164 schemaSources[i] = makeSchemaSource(reader, schemas[i]);// new ResourceSource(reader, schemas[i]);
165 }
166 SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage);
167 return schemaFactory.newSchema(schemaSources);
168 }
169
170 private Source makeSchemaSource(XMLReader reader, Resource resource) throws IOException {
171 Source result = new SAXSource(reader, createInputSource(resource));
172 return result;
173 }
174
175 private static InputSource createInputSource(Resource resource) throws IOException {
176 InputSource inputSource = new InputSource(resource.getInputStream());
177 inputSource.setSystemId(getSystemId(resource));
178 return inputSource;
179 }
180
181 /** Retrieves the URL from the given resource as System ID. Returns <code>null</code> if it cannot be opened. */
182 private static String getSystemId(Resource resource) {
183 try {
184 return new URI(resource.getURL().toExternalForm()).toString();
185 }
186 catch (IOException ex) {
187 logger.debug("Could not get System ID from [" + resource + "], ex");
188 return null;
189 }
190 catch (URISyntaxException e) {
191 logger.debug("Could not get System ID from [" + resource + "], ex");
192 return null;
193 }
194 }
195
196
197 public <T> T unmarshal(Class<T> clazz,Reader reader) throws XmlMappingException {
198 InputSource source = new InputSource(reader);
199 return unmarshal(clazz,source);
200 }
201
202 public <T> T unmarshal(Class<T> clazz,Reader reader, String systemId) throws XmlMappingException {
203 InputSource input = new InputSource(reader);
204 input.setSystemId(systemId);
205 return unmarshal(clazz,input);
206 }
207
208 public <T> T unmarshal(Class<T> clazz, File file) throws XmlMappingException {
209
210 InputSource input;
211 try {
212 input = new InputSource(new InputStreamReader(new FileInputStream(file),encoding));
213 return unmarshal(clazz,input);
214 } catch (UnsupportedEncodingException e) {
215 throw new UncategorizedMappingException(e.getMessage(), e);
216 } catch (FileNotFoundException e) {
217 throw new UncategorizedMappingException(e.getMessage(), e);
218 }
219
220 }
221
222 public void marshal(DataSet dataSet, Writer writer) throws XmlMappingException {
223 logger.info("Start marshalling");
224 super.marshal(dataSet, new StreamResult(writer));
225 }
226
227 public void marshal(DataSet dataSet, StreamResult result) throws XmlMappingException {
228 logger.info("Start marshalling");
229 super.marshal(dataSet, result);
230 }
231
232 public void marshal(DataSet dataSet, SAXResult result) throws XmlMappingException {
233 logger.info("Start marshalling");
234 super.marshal(dataSet, result);
235 }
236
237 }
238
239