1/*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.xml.bind.helpers;
27
28import javax.xml.bind.JAXBException;
29import javax.xml.bind.Marshaller;
30import javax.xml.bind.PropertyException;
31import javax.xml.bind.ValidationEventHandler;
32import javax.xml.bind.annotation.adapters.XmlAdapter;
33import javax.xml.bind.attachment.AttachmentMarshaller;
34import javax.xml.stream.XMLEventWriter;
35import javax.xml.stream.XMLStreamWriter;
36import javax.xml.transform.dom.DOMResult;
37import javax.xml.transform.sax.SAXResult;
38import javax.xml.transform.stream.StreamResult;
39import javax.xml.validation.Schema;
40import java.io.UnsupportedEncodingException;
41import java.io.File;
42import java.io.OutputStream;
43import java.io.FileOutputStream;
44import java.io.BufferedOutputStream;
45import java.io.IOException;
46// J2SE1.4 feature
47// import java.nio.charset.Charset;
48// import java.nio.charset.UnsupportedCharsetException;
49
50/**
51 * Partial default {@code Marshaller} implementation.
52 *
53 * <p>
54 * This class provides a partial default implementation for the
55 * {@link javax.xml.bind.Marshaller} interface.
56 *
57 * <p>
58 * The only methods that a JAXB Provider has to implement are
59 * {@link Marshaller#marshal(Object, javax.xml.transform.Result) marshal(Object, javax.xml.transform.Result)},
60 * {@link Marshaller#marshal(Object, javax.xml.transform.Result) marshal(Object, javax.xml.stream.XMLStreamWriter)}, and
61 * {@link Marshaller#marshal(Object, javax.xml.transform.Result) marshal(Object, javax.xml.stream.XMLEventWriter)}.
62 *
63 * @author <ul><li>Kohsuke Kawaguchi, Sun Microsystems, Inc.</li></ul>
64 * @see javax.xml.bind.Marshaller
65 * @since 1.6, JAXB 1.0
66 */
67public abstract class AbstractMarshallerImpl implements Marshaller
68{
69    /** handler that will be used to process errors and warnings during marshal */
70    private ValidationEventHandler eventHandler =
71        new DefaultValidationEventHandler();
72
73    //J2SE1.4 feature
74    //private Charset encoding = null;
75
76    /** store the value of the encoding property. */
77    private String encoding = "UTF-8";
78
79    /** store the value of the schemaLocation property. */
80    private String schemaLocation = null;
81
82    /** store the value of the noNamespaceSchemaLocation property. */
83    private String noNSSchemaLocation = null;
84
85    /** store the value of the formattedOutput property. */
86    private boolean formattedOutput = false;
87
88    /** store the value of the fragment property. */
89    private boolean fragment = false;
90
91    public final void marshal( Object obj, java.io.OutputStream os )
92        throws JAXBException {
93
94        checkNotNull( obj, "obj", os, "os" );
95        marshal( obj, new StreamResult(os) );
96    }
97
98    public void marshal(Object jaxbElement, File output) throws JAXBException {
99        checkNotNull(jaxbElement, "jaxbElement", output, "output" );
100        try {
101            OutputStream os = new BufferedOutputStream(new FileOutputStream(output));
102            try {
103                marshal( jaxbElement, new StreamResult(os) );
104            } finally {
105                os.close();
106            }
107        } catch (IOException e) {
108            throw new JAXBException(e);
109        }
110    }
111
112    public final void marshal( Object obj, java.io.Writer w )
113        throws JAXBException {
114
115        checkNotNull( obj, "obj", w, "writer" );
116        marshal( obj, new StreamResult(w) );
117    }
118
119    public final void marshal( Object obj, org.xml.sax.ContentHandler handler )
120        throws JAXBException {
121
122        checkNotNull( obj, "obj", handler, "handler" );
123        marshal( obj, new SAXResult(handler) );
124    }
125
126    public final void marshal( Object obj, org.w3c.dom.Node node )
127        throws JAXBException {
128
129        checkNotNull( obj, "obj", node, "node" );
130        marshal( obj, new DOMResult(node) );
131    }
132
133    /**
134     * By default, the getNode method is unsupported and throw
135     * an {@link java.lang.UnsupportedOperationException}.
136     *
137     * Implementations that choose to support this method must
138     * override this method.
139     */
140    public org.w3c.dom.Node getNode( Object obj ) throws JAXBException {
141
142        checkNotNull( obj, "obj", Boolean.TRUE, "foo" );
143
144        throw new UnsupportedOperationException();
145    }
146
147    /**
148     * Convenience method for getting the current output encoding.
149     *
150     * @return the current encoding or "UTF-8" if it hasn't been set.
151     */
152    protected String getEncoding() {
153        return encoding;
154    }
155
156    /**
157     * Convenience method for setting the output encoding.
158     *
159     * @param encoding a valid encoding as specified in the Marshaller class
160     * documentation
161     */
162    protected void setEncoding( String encoding ) {
163        this.encoding = encoding;
164    }
165
166    /**
167     * Convenience method for getting the current schemaLocation.
168     *
169     * @return the current schemaLocation or null if it hasn't been set
170     */
171    protected String getSchemaLocation() {
172        return schemaLocation;
173    }
174
175    /**
176     * Convenience method for setting the schemaLocation.
177     *
178     * @param location the schemaLocation value
179     */
180    protected void setSchemaLocation( String location ) {
181        schemaLocation = location;
182    }
183
184    /**
185     * Convenience method for getting the current noNamespaceSchemaLocation.
186     *
187     * @return the current noNamespaceSchemaLocation or null if it hasn't
188     * been set
189     */
190    protected String getNoNSSchemaLocation() {
191        return noNSSchemaLocation;
192    }
193
194    /**
195     * Convenience method for setting the noNamespaceSchemaLocation.
196     *
197     * @param location the noNamespaceSchemaLocation value
198     */
199    protected void setNoNSSchemaLocation( String location ) {
200        noNSSchemaLocation = location;
201    }
202
203    /**
204     * Convenience method for getting the formatted output flag.
205     *
206     * @return the current value of the formatted output flag or false if
207     * it hasn't been set.
208     */
209    protected boolean isFormattedOutput() {
210        return formattedOutput;
211    }
212
213    /**
214     * Convenience method for setting the formatted output flag.
215     *
216     * @param v value of the formatted output flag.
217     */
218    protected void setFormattedOutput( boolean v ) {
219        formattedOutput = v;
220    }
221
222
223    /**
224     * Convenience method for getting the fragment flag.
225     *
226     * @return the current value of the fragment flag or false if
227     * it hasn't been set.
228     */
229    protected boolean isFragment() {
230        return fragment;
231    }
232
233    /**
234     * Convenience method for setting the fragment flag.
235     *
236     * @param v value of the fragment flag.
237     */
238    protected void setFragment( boolean v ) {
239        fragment = v;
240    }
241
242
243    static String[] aliases = {
244        "UTF-8", "UTF8",
245        "UTF-16", "Unicode",
246        "UTF-16BE", "UnicodeBigUnmarked",
247        "UTF-16LE", "UnicodeLittleUnmarked",
248        "US-ASCII", "ASCII",
249        "TIS-620", "TIS620",
250
251        // taken from the project-X parser
252        "ISO-10646-UCS-2", "Unicode",
253
254        "EBCDIC-CP-US", "cp037",
255        "EBCDIC-CP-CA", "cp037",
256        "EBCDIC-CP-NL", "cp037",
257        "EBCDIC-CP-WT", "cp037",
258
259        "EBCDIC-CP-DK", "cp277",
260        "EBCDIC-CP-NO", "cp277",
261        "EBCDIC-CP-FI", "cp278",
262        "EBCDIC-CP-SE", "cp278",
263
264        "EBCDIC-CP-IT", "cp280",
265        "EBCDIC-CP-ES", "cp284",
266        "EBCDIC-CP-GB", "cp285",
267        "EBCDIC-CP-FR", "cp297",
268
269        "EBCDIC-CP-AR1", "cp420",
270        "EBCDIC-CP-HE", "cp424",
271        "EBCDIC-CP-BE", "cp500",
272        "EBCDIC-CP-CH", "cp500",
273
274        "EBCDIC-CP-ROECE", "cp870",
275        "EBCDIC-CP-YU", "cp870",
276        "EBCDIC-CP-IS", "cp871",
277        "EBCDIC-CP-AR2", "cp918",
278
279        // IANA also defines two that JDK 1.2 doesn't handle:
280        //  EBCDIC-CP-GR        --> CP423
281        //  EBCDIC-CP-TR        --> CP905
282    };
283
284    /**
285     * Gets the corresponding Java encoding name from an IANA name.
286     *
287     * This method is a helper method for the derived class to convert
288     * encoding names.
289     *
290     * @exception UnsupportedEncodingException
291     *      If this implementation couldn't find the Java encoding name.
292     */
293    protected String getJavaEncoding( String encoding ) throws UnsupportedEncodingException {
294        try {
295            "1".getBytes(encoding);
296            return encoding;
297        } catch( UnsupportedEncodingException e ) {
298            // try known alias
299            for( int i=0; i<aliases.length; i+=2 ) {
300                if(encoding.equals(aliases[i])) {
301                    "1".getBytes(aliases[i+1]);
302                    return aliases[i+1];
303                }
304            }
305
306            throw new UnsupportedEncodingException(encoding);
307        }
308        /* J2SE1.4 feature
309        try {
310            this.encoding = Charset.forName( _encoding );
311        } catch( UnsupportedCharsetException uce ) {
312            throw new JAXBException( uce );
313        }
314         */
315    }
316
317    /**
318     * Default implementation of the setProperty method handles
319     * the four defined properties in Marshaller. If a provider
320     * needs to handle additional properties, it should override
321     * this method in a derived class.
322     */
323    public void setProperty( String name, Object value )
324        throws PropertyException {
325
326        if( name == null ) {
327            throw new IllegalArgumentException(
328                Messages.format( Messages.MUST_NOT_BE_NULL, "name" ) );
329        }
330
331        // recognize and handle four pre-defined properties.
332        if( JAXB_ENCODING.equals(name) ) {
333            checkString( name, value );
334            setEncoding( (String)value );
335            return;
336        }
337        if( JAXB_FORMATTED_OUTPUT.equals(name) ) {
338            checkBoolean( name, value );
339            setFormattedOutput((Boolean) value );
340            return;
341        }
342        if( JAXB_NO_NAMESPACE_SCHEMA_LOCATION.equals(name) ) {
343            checkString( name, value );
344            setNoNSSchemaLocation( (String)value );
345            return;
346        }
347        if( JAXB_SCHEMA_LOCATION.equals(name) ) {
348            checkString( name, value );
349            setSchemaLocation( (String)value );
350            return;
351        }
352        if( JAXB_FRAGMENT.equals(name) )  {
353            checkBoolean(name, value);
354            setFragment((Boolean) value );
355            return;
356        }
357
358        throw new PropertyException(name, value);
359    }
360
361    /**
362     * Default implementation of the getProperty method handles
363     * the four defined properties in Marshaller.  If a provider
364     * needs to support additional provider specific properties,
365     * it should override this method in a derived class.
366     */
367    public Object getProperty( String name )
368        throws PropertyException {
369
370        if( name == null ) {
371            throw new IllegalArgumentException(
372                Messages.format( Messages.MUST_NOT_BE_NULL, "name" ) );
373        }
374
375        // recognize and handle four pre-defined properties.
376        if( JAXB_ENCODING.equals(name) )
377            return getEncoding();
378        if( JAXB_FORMATTED_OUTPUT.equals(name) )
379            return isFormattedOutput()?Boolean.TRUE:Boolean.FALSE;
380        if( JAXB_NO_NAMESPACE_SCHEMA_LOCATION.equals(name) )
381            return getNoNSSchemaLocation();
382        if( JAXB_SCHEMA_LOCATION.equals(name) )
383            return getSchemaLocation();
384        if( JAXB_FRAGMENT.equals(name) )
385            return isFragment()?Boolean.TRUE:Boolean.FALSE;
386
387        throw new PropertyException(name);
388    }
389    /**
390     * @see javax.xml.bind.Marshaller#getEventHandler()
391     */
392    public ValidationEventHandler getEventHandler() throws JAXBException {
393        return eventHandler;
394    }
395
396    /**
397     * @see javax.xml.bind.Marshaller#setEventHandler(ValidationEventHandler)
398     */
399    public void setEventHandler(ValidationEventHandler handler)
400        throws JAXBException {
401
402        if( handler == null ) {
403            eventHandler = new DefaultValidationEventHandler();
404        } else {
405            eventHandler = handler;
406        }
407    }
408
409
410
411
412    /*
413     * assert that the given object is a Boolean
414     */
415    private void checkBoolean( String name, Object value ) throws PropertyException {
416        if(!(value instanceof Boolean))
417            throw new PropertyException(
418                Messages.format( Messages.MUST_BE_BOOLEAN, name ) );
419    }
420
421    /*
422     * assert that the given object is a String
423     */
424    private void checkString( String name, Object value ) throws PropertyException {
425        if(!(value instanceof String))
426            throw new PropertyException(
427                Messages.format( Messages.MUST_BE_STRING, name ) );
428    }
429
430    /*
431     * assert that the parameters are not null
432     */
433    private void checkNotNull( Object o1, String o1Name,
434                               Object o2, String o2Name ) {
435
436        if( o1 == null ) {
437            throw new IllegalArgumentException(
438                Messages.format( Messages.MUST_NOT_BE_NULL, o1Name ) );
439        }
440        if( o2 == null ) {
441            throw new IllegalArgumentException(
442                Messages.format( Messages.MUST_NOT_BE_NULL, o2Name ) );
443        }
444    }
445
446    public void marshal(Object obj, XMLEventWriter writer)
447        throws JAXBException {
448
449        throw new UnsupportedOperationException();
450    }
451
452    public void marshal(Object obj, XMLStreamWriter writer)
453        throws JAXBException {
454
455        throw new UnsupportedOperationException();
456    }
457
458    public void setSchema(Schema schema) {
459        throw new UnsupportedOperationException();
460    }
461
462    public Schema getSchema() {
463        throw new UnsupportedOperationException();
464    }
465
466    public void setAdapter(XmlAdapter adapter) {
467        if(adapter==null)
468            throw new IllegalArgumentException();
469        setAdapter((Class)adapter.getClass(),adapter);
470    }
471
472    public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) {
473        throw new UnsupportedOperationException();
474    }
475
476    public <A extends XmlAdapter> A getAdapter(Class<A> type) {
477        throw new UnsupportedOperationException();
478    }
479
480    public void setAttachmentMarshaller(AttachmentMarshaller am) {
481        throw new UnsupportedOperationException();
482    }
483
484    public AttachmentMarshaller getAttachmentMarshaller() {
485        throw new UnsupportedOperationException();
486    }
487
488    public void setListener(Listener listener) {
489        throw new UnsupportedOperationException();
490    }
491
492    public Listener getListener() {
493        throw new UnsupportedOperationException();
494    }
495}
496