1/*
2 * Copyright (c) 1997, 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 com.sun.xml.internal.bind.v2.runtime;
27
28import java.io.IOException;
29
30import javax.xml.bind.ValidationEvent;
31import javax.xml.bind.helpers.ValidationEventImpl;
32import javax.xml.namespace.QName;
33import javax.xml.stream.XMLStreamException;
34
35import com.sun.xml.internal.bind.api.AccessorException;
36import com.sun.xml.internal.bind.v2.model.runtime.RuntimeLeafInfo;
37import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader;
38import com.sun.xml.internal.bind.v2.runtime.unmarshaller.TextLoader;
39import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext;
40import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiTypeLoader;
41
42import org.xml.sax.SAXException;
43
44/**
45 * {@link JaxBeanInfo} implementation for immutable leaf classes.
46 *
47 * <p>
48 * Leaf classes are always bound to a text and they are often immutable.
49 * The JAXB spec allows this binding for a few special Java classes plus
50 * type-safe enums.
51 *
52 * <p>
53 * This implementation obtains necessary information from {@link RuntimeLeafInfo}.
54 *
55 * @author Kohsuke Kawaguchi
56 */
57final class LeafBeanInfoImpl<BeanT> extends JaxBeanInfo<BeanT> {
58
59    private final Loader loader;
60    private final Loader loaderWithSubst;
61
62    private final Transducer<BeanT> xducer;
63
64    /**
65     * Non-null only if the leaf is also an element.
66     */
67    private final Name tagName;
68
69    public LeafBeanInfoImpl(JAXBContextImpl grammar, RuntimeLeafInfo li) {
70        super(grammar,li,li.getClazz(),li.getTypeNames(),li.isElement(),true,false);
71
72        xducer = li.getTransducer();
73        loader = new TextLoader(xducer);
74        loaderWithSubst = new XsiTypeLoader(this);
75
76        if(isElement())
77            tagName = grammar.nameBuilder.createElementName(li.getElementName());
78        else
79            tagName = null;
80    }
81
82    @Override
83    public QName getTypeName(BeanT instance) {
84        QName tn = xducer.getTypeName(instance);
85        if(tn!=null)    return tn;
86        // rely on default
87        return super.getTypeName(instance);
88    }
89
90    public final String getElementNamespaceURI(BeanT t) {
91        return tagName.nsUri;
92    }
93
94    public final String getElementLocalName(BeanT t) {
95        return tagName.localName;
96    }
97
98    public BeanT createInstance(UnmarshallingContext context) {
99        throw new UnsupportedOperationException();
100    }
101
102    public final boolean reset(BeanT bean, UnmarshallingContext context) {
103        return false;
104    }
105
106    public final String getId(BeanT bean, XMLSerializer target) {
107        return null;
108    }
109
110    public final void serializeBody(BeanT bean, XMLSerializer w) throws SAXException, IOException, XMLStreamException {
111        // most of the times leaves are printed as leaf element/attribute property,
112        // so this code is only used for example when you have multiple XmlElement on a property
113        // and some of them are leaves. Hence this doesn't need to be super-fast.
114        try {
115            xducer.writeText(w,bean,null);
116        } catch (AccessorException e) {
117            w.reportError(null,e);
118        }
119    }
120
121    public final void serializeAttributes(BeanT bean, XMLSerializer target) {
122        // noop
123    }
124
125    public final void serializeRoot(BeanT bean, XMLSerializer target) throws SAXException, IOException, XMLStreamException {
126        if(tagName==null) {
127            target.reportError(
128                new ValidationEventImpl(
129                    ValidationEvent.ERROR,
130                    Messages.UNABLE_TO_MARSHAL_NON_ELEMENT.format(bean.getClass().getName()),
131                    null,
132                    null));
133        }
134        else {
135            target.startElement(tagName,bean);
136            target.childAsSoleContent(bean,null);
137            target.endElement();
138        }
139    }
140
141    public final void serializeURIs(BeanT bean, XMLSerializer target) throws SAXException {
142        // TODO: maybe we should create another LeafBeanInfoImpl class for
143        // context-dependent xducers?
144        if(xducer.useNamespace()) {
145            try {
146                xducer.declareNamespace(bean,target);
147            } catch (AccessorException e) {
148                target.reportError(null,e);
149            }
150        }
151    }
152
153    public final Loader getLoader(JAXBContextImpl context, boolean typeSubstitutionCapable) {
154        if(typeSubstitutionCapable)
155            return loaderWithSubst;
156        else
157            return loader;
158    }
159
160    public Transducer<BeanT> getTransducer() {
161        return xducer;
162    }
163}
164