001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.oxm.support;
018
019import java.io.IOException;
020import javax.xml.transform.Source;
021import javax.xml.transform.sax.SAXResult;
022import javax.xml.transform.sax.SAXSource;
023
024import org.xml.sax.ContentHandler;
025import org.xml.sax.DTDHandler;
026import org.xml.sax.EntityResolver;
027import org.xml.sax.ErrorHandler;
028import org.xml.sax.InputSource;
029import org.xml.sax.SAXException;
030import org.xml.sax.SAXNotRecognizedException;
031import org.xml.sax.SAXParseException;
032import org.xml.sax.XMLReader;
033import org.xml.sax.ext.LexicalHandler;
034
035import org.springframework.oxm.Marshaller;
036import org.springframework.util.Assert;
037
038/**
039 * {@link Source} implementation that uses a {@link Marshaller}.Can be constructed with a
040 * {@code Marshaller} and an object to be marshalled.
041 *
042 * <p>Even though {@code MarshallingSource} extends from {@code SAXSource}, calling the methods of
043 * {@code SAXSource} is <strong>not supported</strong>. In general, the only supported operation on this class is
044 * to use the {@code XMLReader} obtained via {@link #getXMLReader()} to parse the input source obtained via {@link
045 * #getInputSource()}. Calling {@link #setXMLReader(XMLReader)} or {@link #setInputSource(InputSource)} will result in
046 * {@code UnsupportedOperationException}s.
047 *
048 * @author Arjen Poutsma
049 * @since 3.0
050 * @see javax.xml.transform.Transformer
051 */
052public class MarshallingSource extends SAXSource {
053
054        private final Marshaller marshaller;
055
056        private final Object content;
057
058
059        /**
060         * Create a new {@code MarshallingSource} with the given marshaller and content.
061         * @param marshaller the marshaller to use
062         * @param content the object to be marshalled
063         */
064        public MarshallingSource(Marshaller marshaller, Object content) {
065                super(new MarshallingXMLReader(marshaller, content), new InputSource());
066                Assert.notNull(marshaller, "'marshaller' must not be null");
067                Assert.notNull(content, "'content' must not be null");
068                this.marshaller = marshaller;
069                this.content = content;
070        }
071
072
073        /**
074         * Return the {@code Marshaller} used by this {@code MarshallingSource}.
075         */
076        public Marshaller getMarshaller() {
077                return this.marshaller;
078        }
079
080        /**
081         * Return the object to be marshalled.
082         */
083        public Object getContent() {
084                return this.content;
085        }
086
087        /**
088         * Throws a {@code UnsupportedOperationException}.
089         */
090        @Override
091        public void setInputSource(InputSource inputSource) {
092                throw new UnsupportedOperationException("setInputSource is not supported");
093        }
094
095        /**
096         * Throws a {@code UnsupportedOperationException}.
097         */
098        @Override
099        public void setXMLReader(XMLReader reader) {
100                throw new UnsupportedOperationException("setXMLReader is not supported");
101        }
102
103
104        private static class MarshallingXMLReader implements XMLReader {
105
106                private final Marshaller marshaller;
107
108                private final Object content;
109
110                private DTDHandler dtdHandler;
111
112                private ContentHandler contentHandler;
113
114                private EntityResolver entityResolver;
115
116                private ErrorHandler errorHandler;
117
118                private LexicalHandler lexicalHandler;
119
120                private MarshallingXMLReader(Marshaller marshaller, Object content) {
121                        Assert.notNull(marshaller, "'marshaller' must not be null");
122                        Assert.notNull(content, "'content' must not be null");
123                        this.marshaller = marshaller;
124                        this.content = content;
125                }
126
127                @Override
128                public void setContentHandler(ContentHandler contentHandler) {
129                        this.contentHandler = contentHandler;
130                }
131
132                @Override
133                public ContentHandler getContentHandler() {
134                        return this.contentHandler;
135                }
136
137                @Override
138                public void setDTDHandler(DTDHandler dtdHandler) {
139                        this.dtdHandler = dtdHandler;
140                }
141
142                @Override
143                public DTDHandler getDTDHandler() {
144                        return this.dtdHandler;
145                }
146
147                @Override
148                public void setEntityResolver(EntityResolver entityResolver) {
149                        this.entityResolver = entityResolver;
150                }
151
152                @Override
153                public EntityResolver getEntityResolver() {
154                        return this.entityResolver;
155                }
156
157                @Override
158                public void setErrorHandler(ErrorHandler errorHandler) {
159                        this.errorHandler = errorHandler;
160                }
161
162                @Override
163                public ErrorHandler getErrorHandler() {
164                        return this.errorHandler;
165                }
166
167                protected LexicalHandler getLexicalHandler() {
168                        return this.lexicalHandler;
169                }
170
171                @Override
172                public boolean getFeature(String name) throws SAXNotRecognizedException {
173                        throw new SAXNotRecognizedException(name);
174                }
175
176                @Override
177                public void setFeature(String name, boolean value) throws SAXNotRecognizedException {
178                        throw new SAXNotRecognizedException(name);
179                }
180
181                @Override
182                public Object getProperty(String name) throws SAXNotRecognizedException {
183                        if ("http://xml.org/sax/properties/lexical-handler".equals(name)) {
184                                return lexicalHandler;
185                        }
186                        else {
187                                throw new SAXNotRecognizedException(name);
188                        }
189                }
190
191                @Override
192                public void setProperty(String name, Object value) throws SAXNotRecognizedException {
193                        if ("http://xml.org/sax/properties/lexical-handler".equals(name)) {
194                                this.lexicalHandler = (LexicalHandler) value;
195                        }
196                        else {
197                                throw new SAXNotRecognizedException(name);
198                        }
199                }
200
201                @Override
202                public void parse(InputSource input) throws SAXException {
203                        parse();
204                }
205
206                @Override
207                public void parse(String systemId) throws SAXException {
208                        parse();
209                }
210
211                private void parse() throws SAXException {
212                        SAXResult result = new SAXResult(getContentHandler());
213                        result.setLexicalHandler(getLexicalHandler());
214                        try {
215                                this.marshaller.marshal(this.content, result);
216                        }
217                        catch (IOException ex) {
218                                SAXParseException saxException = new SAXParseException(ex.getMessage(), null, null, -1, -1, ex);
219                                ErrorHandler errorHandler = getErrorHandler();
220                                if (errorHandler != null) {
221                                        errorHandler.fatalError(saxException);
222                                }
223                                else {
224                                        throw saxException;
225                                }
226                        }
227                }
228        }
229
230}