001: /*
002: Copyright (c) 2003-2007, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.binding.def;
030:
031: import java.util.ArrayList;
032:
033: import org.jibx.binding.classes.ContextMethodBuilder;
034: import org.jibx.runtime.JiBXException;
035:
036: /**
037: * Reference to a mapping definition. This is used as a placeholder when
038: * building the component structure of a binding definition. It's necessary
039: * because the referenced mapping may not have been parsed yet. During the
040: * linkage phase that follows parsing this looks up the appropriate mapping
041: * definition and sets up the corresponding component structure. Thereafter it
042: * operates as a simple pass-through wrapper for the top child component.
043: *
044: * @author Dennis M. Sosnoski
045: */
046: public class MappingReference extends PassThroughComponent {
047: /** Containing binding definition structure. */
048: private final IContainer m_container;
049:
050: /** Property definition. */
051: private final PropertyDefinition m_property;
052:
053: /** Flag for nillable element. */
054: private final boolean m_isNillable;
055:
056: /** Fully qualified name of mapped type. */
057: private String m_type;
058:
059: /** Ordinary name of type for abstract mapping. */
060: private String m_referenceText;
061:
062: /** Qualified name of type for abstract mapping. */
063: private String m_referenceQName;
064:
065: /** Context object. */
066: private final IContextObj m_contextObject;
067:
068: /** Name from reference (only allowed with abstract mappings) */
069: private final NameDefinition m_name;
070:
071: /** Synthetic reference added to empty collection flag */
072: private final boolean m_isSynthetic;
073:
074: /** Generated wrapped component, used when checking for both attributes
075: and elements present. */
076: private IComponent m_wrappedReference;
077:
078: /**
079: * Constructor from property and type.
080: *
081: * @param contain containing binding definition structure
082: * @param prop property definition
083: * @param type fully qualified name of mapped type
084: * @param reftext ordinary text name for abstract mapping reference
085: * (<code>null</code> if not specified)
086: * @param refqname qualified type name for abstract mapping reference
087: * (<code>null</code> if not specified)
088: * @param objc current object context
089: * @param name reference name definition (only allowed with abstract
090: * mappings)
091: * @param synth sythentic reference added to empty collection flag
092: * @param nillable flag for nillable element
093: */
094: public MappingReference(IContainer contain,
095: PropertyDefinition prop, String type, String reftext,
096: String refqname, IContextObj objc, NameDefinition name,
097: boolean synth, boolean nillable) {
098: super ();
099: m_container = contain;
100: m_property = prop;
101: m_type = type;
102: m_referenceText = reftext;
103: m_referenceQName = refqname;
104: m_contextObject = objc;
105: m_name = name;
106: m_isSynthetic = synth;
107: m_isNillable = nillable;
108: }
109:
110: //
111: // IComponent interface method definitions (overrides of defaults)
112:
113: public boolean isOptional() {
114: return m_property.isOptional();
115: }
116:
117: public String getType() {
118: return m_type;
119: }
120:
121: public void setLinkages() throws JiBXException {
122:
123: // find the mapping being used
124: DefinitionContext defc = m_container.getDefinitionContext();
125: IMapping mdef = null;
126: if (m_referenceText != null) {
127: mdef = defc.getClassMapping(m_referenceText);
128: if (mdef == null) {
129: mdef = defc.getClassMapping(m_referenceQName);
130: }
131: }
132: if (mdef == null) {
133: mdef = defc.getClassMapping(m_type);
134: }
135: IComponent wrap = null;
136: PropertyDefinition prop = m_property;
137: if (mdef == null) {
138:
139: // generate generic mapping to unknown type
140: if (m_name != null) {
141: throw new JiBXException(
142: "Name not allowed for generic mapping of type "
143: + m_type);
144: }
145: wrap = new DirectGeneric(m_container, m_type, prop);
146:
147: } else if (m_isSynthetic && mdef.isAbstract() && !mdef.isBase()) {
148:
149: // collection reference to abstract non-base mapping as generic
150: wrap = new DirectGeneric(m_container, m_type, prop);
151:
152: } else {
153:
154: // check for reference from collection
155: if (prop.isImplicit()) {
156: prop.setOptional(false);
157: }
158:
159: // add mapping namespaces to context (only if no element on mapping)
160: if (mdef.getName() == null) {
161: ArrayList nss = mdef.getNamespaces();
162: if (nss != null) {
163: for (int i = 0; i < nss.size(); i++) {
164: defc
165: .addImpliedNamespace((NamespaceDefinition) nss
166: .get(i));
167: }
168: }
169: }
170:
171: // generate wrapped component for all calls
172: String type = mdef.getBoundType();
173: if (prop.getTypeName() == null) {
174: prop = new PropertyDefinition(type, m_contextObject,
175: prop.isOptional());
176: }
177: wrap = mdef.buildRef(m_container, m_contextObject, prop
178: .getTypeName(), prop);
179: if (m_name != null) {
180: m_wrappedReference = wrap;
181: if (mdef.getName() == null) {
182:
183: // create the replacement components
184: IComponent icomp = wrap;
185: wrap = new ElementWrapper(defc, m_name, icomp,
186: m_isNillable);
187: if (prop.isImplicit()) {
188: ((ElementWrapper) wrap).setDirect(true);
189: }
190: if (prop.isOptional()) {
191: if (icomp instanceof ComponentProperty) {
192: ((ComponentProperty) icomp)
193: .setSkipping(true);
194: }
195: ((ElementWrapper) wrap).setOptionalNormal(true);
196: ((ElementWrapper) wrap)
197: .setStructureObject(true);
198: ((ElementWrapper) wrap).setDirect(true);
199: wrap = new OptionalStructureWrapper(wrap, prop,
200: true);
201: // m_property.setOptional(false);
202: }
203:
204: } else {
205: throw new JiBXException(
206: "Name not allowed for reference to mapping of type "
207: + type
208: + ", which already defines a name");
209: }
210: }
211:
212: // set type based on mapping
213: m_type = mdef.getReferenceType();
214: }
215:
216: // link actual component into structure
217: setWrappedComponent(wrap);
218: super .setLinkages();
219: }
220:
221: /**
222: * Patch the generated code to remove the unmarshalled object when it's a
223: * "this" reference with both elements and attributes.
224: *
225: * @param mb
226: * @throws JiBXException
227: */
228: public void genContentUnmarshal(ContextMethodBuilder mb)
229: throws JiBXException {
230: super .genContentUnmarshal(mb);
231:
232: // check for unmarshalling fix needed
233: if (m_wrappedReference != null && m_property.isThis()
234: && m_wrappedReference.hasAttribute()
235: && m_wrappedReference.hasContent()) {
236: mb.appendPOP();
237: }
238: }
239:
240: // DEBUG
241: public void print(int depth) {
242: BindingDefinition.indent(depth);
243: System.out
244: .print("mapping reference to "
245: + ((m_referenceText == null) ? m_type
246: : m_referenceText));
247: if (m_property != null) {
248: System.out.print(" using " + m_property.toString());
249: }
250: System.out.println();
251: if (m_component != null) {
252: m_component.print(depth + 1);
253: }
254: }
255: }
|