/**\r
-* Copyright (C) 2008 EDIT\r
-* European Distributed Institute of Taxonomy \r
-* http://www.e-taxonomy.eu\r
- * \r
+ * Copyright (C) 2008 EDIT\r
+ * European Distributed Institute of Taxonomy\r
+ * http://www.e-taxonomy.eu\r
+ *\r
* The contents of this file are subject to the Mozilla Public License Version 1.1\r
* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
+ */\r
\r
package eu.etaxonomy.cdm.io.jaxb;\r
\r
import java.io.Reader;\r
import java.io.UnsupportedEncodingException;\r
import java.io.Writer;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
\r
-import javax.xml.XMLConstants;\r
-import javax.xml.bind.JAXBContext;\r
import javax.xml.bind.JAXBException;\r
import javax.xml.bind.Marshaller;\r
-import javax.xml.bind.Unmarshaller;\r
-import javax.xml.bind.UnmarshallerHandler;\r
+import javax.xml.bind.PropertyException;\r
import javax.xml.parsers.ParserConfigurationException;\r
import javax.xml.parsers.SAXParser;\r
import javax.xml.parsers.SAXParserFactory;\r
import javax.xml.transform.Source;\r
+import javax.xml.transform.sax.SAXResult;\r
import javax.xml.transform.sax.SAXSource;\r
-import javax.xml.transform.stream.StreamSource;\r
+import javax.xml.transform.stream.StreamResult;\r
import javax.xml.validation.Schema;\r
import javax.xml.validation.SchemaFactory;\r
\r
import org.apache.log4j.Logger;\r
import org.apache.xml.resolver.tools.CatalogResolver;\r
+import org.springframework.core.io.ClassPathResource;\r
+import org.springframework.core.io.Resource;\r
+import org.springframework.oxm.UncategorizedMappingException;\r
+import org.springframework.oxm.XmlMappingException;\r
+import org.springframework.oxm.jaxb.Jaxb2Marshaller;\r
import org.xml.sax.InputSource;\r
import org.xml.sax.SAXException;\r
import org.xml.sax.XMLReader;\r
+import org.xml.sax.helpers.XMLReaderFactory;\r
\r
import eu.etaxonomy.cdm.jaxb.CdmNamespacePrefixMapper;\r
import eu.etaxonomy.cdm.jaxb.FormattedText;\r
import eu.etaxonomy.cdm.jaxb.MultilanguageTextElement;\r
-import eu.etaxonomy.cdm.model.agent.Person;\r
\r
/**\r
- * Initializes a JaxbContext with one class (eu.etaxonomy.cdm.model.DataSet). \r
- * \r
+ * Initializes a JaxbContext with one class (eu.etaxonomy.cdm.model.DataSet).\r
+ *\r
* @author a.babadshanjan, ben.clark\r
*/\r
//Binds it to XML schemas found in /src/main/resources/schema/cdm (cdm.xsd, common.xsd, name.xsd).\r
//There is a bit of magic with a resource resolver in eu.etaxonomy.cdm.io.jaxb\r
//which allows to package the schemas into a jar file.\r
-public class CdmDocumentBuilder {\r
- \r
- private static final Logger logger = Logger.getLogger(CdmDocumentBuilder.class);\r
- \r
- private JAXBContext jaxbContext;\r
- private boolean formattedOutput = Boolean.TRUE;\r
- private String encoding = "UTF-8";\r
- private Schema schema;\r
- private Marshaller marshaller;\r
- private Unmarshaller unmarshaller;\r
- private XMLReader xmlReader;\r
- \r
- public static String CDM_NAMESPACE = "eu.etaxonomy.cdm.model";\r
- public static String[] CDM_SCHEMA_FILES = { "/schema/cdm/agent.xsd",\r
- "/schema/cdm/cdm.xsd",\r
- "/schema/cdm/common.xsd",\r
- "/schema/cdm/description.xsd",\r
- "/schema/cdm/location.xsd",\r
- "/schema/cdm/media.xsd",\r
- "/schema/cdm/molecular.xsd",\r
- "/schema/cdm/name.xsd",\r
- "/schema/cdm/occurrence.xsd",\r
- "/schema/cdm/reference.xsd",\r
- "/schema/cdm/taxon.xsd"};\r
- public static Class[] CONTEXT_CLASSES = {DataSet.class,FormattedText.class,MultilanguageTextElement.class};\r
- \r
- protected String[] getSchemaFiles() {\r
- return CDM_SCHEMA_FILES;\r
- }\r
- \r
- protected Class[] getContextClasses() {\r
- return CONTEXT_CLASSES;\r
- }\r
- \r
- protected void constructSchema() throws IOException, SAXException {\r
- SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);\r
- schemaFactory.setResourceResolver(new CdmResourceResolver());\r
- String[] schemaFiles = getSchemaFiles();\r
- \r
- Source[] sources = new Source[schemaFiles.length];\r
- \r
- for(int i = 0; i < schemaFiles.length; i++) {\r
- String schemaName = schemaFiles[i];\r
- sources[i] = new StreamSource(this.getClass().getResourceAsStream(schemaName));\r
- }\r
-\r
- schema = schemaFactory.newSchema(sources);\r
- }\r
- \r
- protected void constructUnmarshaller() throws ParserConfigurationException, SAXException, JAXBException {\r
- unmarshaller = jaxbContext.createUnmarshaller();\r
- unmarshaller.setSchema(schema);\r
- \r
+public class CdmDocumentBuilder extends Jaxb2Marshaller {\r
+\r
+ private static final Logger logger = Logger.getLogger(CdmDocumentBuilder.class);\r
+ private boolean formattedOutput = Boolean.TRUE;\r
+ private String encoding = "UTF-8";\r
+\r
+ public static String CDM_NAMESPACE = "eu.etaxonomy.cdm.model";\r
+ public static String[] CDM_SCHEMA_FILES = { "/schema/cdm/agent.xsd",\r
+ "/schema/cdm/cdm.xsd",\r
+ "/schema/cdm/common.xsd",\r
+ "/schema/cdm/description.xsd",\r
+ "/schema/cdm/location.xsd",\r
+ "/schema/cdm/media.xsd",\r
+ "/schema/cdm/molecular.xsd",\r
+ "/schema/cdm/name.xsd",\r
+ "/schema/cdm/occurrence.xsd",\r
+ "/schema/cdm/reference.xsd",\r
+ "/schema/cdm/taxon.xsd"};\r
+ public static Class[] CONTEXT_CLASSES = {DataSet.class,FormattedText.class,MultilanguageTextElement.class};\r
+\r
+ private Resource schemas[];\r
+\r
+ protected String[] getSchemaFiles() {\r
+ return CDM_SCHEMA_FILES;\r
+ }\r
+\r
+ protected Class[] getContextClasses() {\r
+ return CONTEXT_CLASSES;\r
+ }\r
+\r
+ public CdmDocumentBuilder() {\r
+ schemas = new Resource[CDM_SCHEMA_FILES.length];\r
+\r
+ for(int i = 0; i < CDM_SCHEMA_FILES.length; i++) {\r
+ schemas[i] = new ClassPathResource(CDM_SCHEMA_FILES[i]);\r
+ }\r
+\r
+ super.setSchemas(schemas);\r
+ super.setClassesToBeBound(CONTEXT_CLASSES);\r
+ super.setSchemaLanguage("http://www.w3.org/2001/XMLSchema");\r
+ }\r
+\r
+ public CdmDocumentBuilder(boolean formattedOutput, String encoding) {\r
+ this.formattedOutput = formattedOutput;\r
+ this.encoding = encoding;\r
+ }\r
+\r
+\r
+ @Override\r
+ protected void initJaxbMarshaller(Marshaller marshaller) throws JAXBException {\r
+ try {\r
+ marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new CdmNamespacePrefixMapper() );\r
+\r
+ // For test purposes insert newlines to make the XML output readable\r
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formattedOutput);\r
+ //marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,"http://etaxonomy.eu/cdm/model/1.0 schema/cdm/cdm.xsd");\r
+ //marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,"http://etaxonomy.eu/cdm/model/1.0 cdm.xsd");\r
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);\r
+\r
+ CdmMarshallerListener marshallerListener = new CdmMarshallerListener();\r
+ marshaller.setListener(marshallerListener);\r
+ marshaller.setEventHandler(new WarningTolerantValidationEventHandler());\r
+ } catch(PropertyException pe) {\r
+ throw new JAXBException(pe.getMessage(),pe);\r
+ }\r
+ }\r
+\r
+ protected <T> T unmarshal(Class<T> clazz, InputSource input) {\r
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();\r
- \r
- saxParserFactory.setNamespaceAware(true);\r
- saxParserFactory.setXIncludeAware(true);\r
- saxParserFactory.setValidating(true);\r
- \r
- SAXParser saxParser = saxParserFactory.newSAXParser();\r
- saxParser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage",\r
- "http://www.w3.org/2001/XMLSchema");\r
- xmlReader = saxParser.getXMLReader();\r
- xmlReader.setEntityResolver(new CatalogResolver());\r
- xmlReader.setErrorHandler(new DefaultErrorHandler());\r
- unmarshaller.setEventHandler(new WarningTolerantValidationEventHandler());\r
- }\r
- \r
- public CdmDocumentBuilder() throws SAXException, JAXBException, IOException, ParserConfigurationException {\r
- constructSchema();\r
- \r
- jaxbContext = JAXBContext.newInstance(getContextClasses());\r
- \r
- constructUnmarshaller();\r
- constructMarshaller();\r
- }\r
- \r
- protected void constructMarshaller() throws JAXBException {\r
- marshaller = jaxbContext.createMarshaller();\r
- marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new CdmNamespacePrefixMapper() );\r
- marshaller.setSchema(schema);\r
- \r
- // For test purposes insert newlines to make the XML output readable\r
- marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formattedOutput);\r
-// marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,"http://etaxonomy.eu/cdm/model/1.0 schema/cdm/cdm.xsd");\r
- marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION,"http://etaxonomy.eu/cdm/model/1.0 cdm.xsd");\r
- marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);\r
- \r
- CdmMarshallerListener marshallerListener = new CdmMarshallerListener();\r
- marshaller.setListener(marshallerListener); \r
- marshaller.setEventHandler(new WarningTolerantValidationEventHandler());\r
- }\r
-\r
- public CdmDocumentBuilder(boolean formattedOutput, String encoding) throws SAXException, JAXBException, IOException, ParserConfigurationException {\r
- this.formattedOutput = formattedOutput;\r
- this.encoding = encoding;\r
- constructSchema();\r
- \r
- jaxbContext = JAXBContext.newInstance(getContextClasses());\r
- \r
- constructUnmarshaller();\r
- constructMarshaller();\r
- }\r
- \r
- public void marshal(DataSet dataSet, Writer writer) throws JAXBException {\r
- \r
- logger.info("Start marshalling");\r
- marshaller.marshal(dataSet, writer);\r
- \r
- }\r
- \r
- public <T> T unmarshal(Class<T> clazz,Reader reader) throws JAXBException {\r
- InputSource input = new InputSource(reader);\r
- SAXSource saxSource = new SAXSource( xmlReader, input);\r
- logger.info("Start unmarshalling");\r
- T t = (T) unmarshaller.unmarshal(saxSource);\r
- return t;\r
- } \r
- \r
- public <T> T unmarshal(Class<T> clazz,Reader reader, String systemId) throws JAXBException {\r
- InputSource input = new InputSource(reader);\r
- input.setSystemId(systemId);\r
- SAXSource saxSource = new SAXSource( xmlReader, input);\r
- logger.info("Start unmarshalling");\r
- T t = (T) unmarshaller.unmarshal(saxSource);\r
- return t;\r
- } \r
-\r
- public <T> T unmarshal(Class<T> clazz, File file) throws JAXBException, UnsupportedEncodingException, FileNotFoundException {\r
-\r
- InputSource input = new InputSource(new InputStreamReader(new FileInputStream(file),encoding));\r
- input.setSystemId(file.toURI().toString());\r
- SAXSource saxSource = new SAXSource( xmlReader, input);\r
- logger.info("Start unmarshalling");\r
- T t = (T) unmarshaller.unmarshal(saxSource);\r
- return t;\r
- \r
- }\r
-\r
-// public void marshal(DataSet dataSet, File file) throws JAXBException {\r
-// marshaller.marshal(dataSet, file);\r
-// }\r
+ Schema schema;\r
+ try {\r
+ schema = createSchema();\r
+ saxParserFactory.setNamespaceAware(true);\r
+ saxParserFactory.setXIncludeAware(true);\r
+ saxParserFactory.setValidating(true);\r
+ saxParserFactory.setSchema(schema);\r
+\r
+ SAXParser saxParser = saxParserFactory.newSAXParser();\r
+ XMLReader xmlReader = saxParser.getXMLReader();\r
+ xmlReader.setEntityResolver(new CatalogResolver());\r
+ xmlReader.setErrorHandler(new DefaultErrorHandler());\r
+ SAXSource saxSource = new SAXSource( xmlReader, input);\r
+ saxSource.setSystemId(input.getSystemId());\r
+\r
+ return (T)super.unmarshal(saxSource);\r
+ } catch (IOException e) {\r
+ throw new UncategorizedMappingException(e.getMessage(), e);\r
+ } catch (SAXException e) {\r
+ throw new UncategorizedMappingException(e.getMessage(), e);\r
+ } catch (ParserConfigurationException e) {\r
+ throw new UncategorizedMappingException(e.getMessage(), e);\r
+ }\r
+ }\r
+\r
+ private Schema createSchema() throws SAXException, IOException {\r
+ //method created to avoid dependency of spring-xml like in earlier versions\r
+ //old implementation was schema = SchemaLoaderUtils.loadSchema(schemas, "http://www.w3.org/2001/XMLSchema");\r
+ //maybe we can improve this loading in future\r
+\r
+ String schemaLanguage = "http://www.w3.org/2001/XMLSchema";\r
+ Source[] schemaSources = new Source[schemas.length];\r
+ XMLReader reader = XMLReaderFactory.createXMLReader();\r
+ reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);\r
+ for (int i = 0; i < schemas.length; i++) {\r
+ schemaSources[i] = makeSchemaSource(reader, schemas[i]);// new ResourceSource(reader, schemas[i]);\r
+ }\r
+ SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage);\r
+ return schemaFactory.newSchema(schemaSources);\r
+ }\r
+\r
+ private Source makeSchemaSource(XMLReader reader, Resource resource) throws IOException {\r
+ Source result = new SAXSource(reader, createInputSource(resource));\r
+ return result;\r
+ }\r
+\r
+ private static InputSource createInputSource(Resource resource) throws IOException {\r
+ InputSource inputSource = new InputSource(resource.getInputStream());\r
+ inputSource.setSystemId(getSystemId(resource));\r
+ return inputSource;\r
+ }\r
+\r
+ /** Retrieves the URL from the given resource as System ID. Returns <code>null</code> if it cannot be opened. */\r
+ private static String getSystemId(Resource resource) {\r
+ try {\r
+ return new URI(resource.getURL().toExternalForm()).toString();\r
+ }\r
+ catch (IOException ex) {\r
+ logger.debug("Could not get System ID from [" + resource + "], ex");\r
+ return null;\r
+ }\r
+ catch (URISyntaxException e) {\r
+ logger.debug("Could not get System ID from [" + resource + "], ex");\r
+ return null;\r
+ }\r
+ }\r
+\r
+\r
+ public <T> T unmarshal(Class<T> clazz,Reader reader) throws XmlMappingException {\r
+ InputSource source = new InputSource(reader);\r
+ return unmarshal(clazz,source);\r
+ }\r
+\r
+ public <T> T unmarshal(Class<T> clazz,Reader reader, String systemId) throws XmlMappingException {\r
+ InputSource input = new InputSource(reader);\r
+ input.setSystemId(systemId);\r
+ return unmarshal(clazz,input);\r
+ }\r
+\r
+ public <T> T unmarshal(Class<T> clazz, File file) throws XmlMappingException {\r
+\r
+ InputSource input;\r
+ try {\r
+ input = new InputSource(new InputStreamReader(new FileInputStream(file),encoding));\r
+ return unmarshal(clazz,input);\r
+ } catch (UnsupportedEncodingException e) {\r
+ throw new UncategorizedMappingException(e.getMessage(), e);\r
+ } catch (FileNotFoundException e) {\r
+ throw new UncategorizedMappingException(e.getMessage(), e);\r
+ }\r
+\r
+ }\r
+\r
+ public void marshal(DataSet dataSet, Writer writer) throws XmlMappingException {\r
+ logger.info("Start marshalling");\r
+ super.marshal(dataSet, new StreamResult(writer));\r
+ }\r
+\r
+ public void marshal(DataSet dataSet, StreamResult result) throws XmlMappingException {\r
+ logger.info("Start marshalling");\r
+ super.marshal(dataSet, result);\r
+ }\r
+\r
+ public void marshal(DataSet dataSet, SAXResult result) throws XmlMappingException {\r
+ logger.info("Start marshalling");\r
+ super.marshal(dataSet, result);\r
+ }\r
\r
}\r
\r
- \r
+\r