Project

General

Profile

Download (9.5 KB) Statistics
| Branch: | Tag: | Revision:
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

    
(1-1/17)