001: /*
002: Copyright (c) 2003-2005, 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.*;
034: import org.jibx.runtime.JiBXException;
035:
036: /**
037: * Base class for structure and collection binding definitions. This handles one
038: * or more child components, which may be ordered or unordered.
039: *
040: * @author Dennis M. Sosnoski
041: * @version 1.0
042: */
043: public abstract class NestedBase extends BindingBuilder.ContainerBase
044: implements IComponent, IContainer {
045: /** Context object for this definition. */
046: private IContextObj m_contextObject;
047:
048: /** Flag for context defined at level. */
049: private final boolean m_hasContext;
050:
051: /** Flag for ordered child content (used by subclasses). */
052: protected final boolean m_isOrdered;
053:
054: /** Flag for flexible element handling (used by subclasses). */
055: protected final boolean m_isFlexible;
056:
057: /** Definition context for container (may be same as parent). */
058: private final DefinitionContext m_defContext;
059:
060: /** Included attribute definitions (lazy create, only if needed). */
061: protected ArrayList m_attributes;
062:
063: /** Nested content definitions (initially used for all child components). */
064: protected ArrayList m_contents;
065:
066: /**
067: * Constructor.
068: *
069: * @param contain containing binding definition context
070: * @param objc current object context
071: * @param ord ordered content flag
072: * @param flex flexible element handling flag
073: * @param defc define context for structure flag
074: */
075: public NestedBase(IContainer contain, IContextObj objc,
076: boolean ord, boolean flex, boolean defc) {
077:
078: // set base class defaults
079: super (contain);
080: m_styleDefault = m_autoLink = m_accessLevel = m_nameStyle = -1;
081:
082: // initialize members at this level
083: m_contextObject = objc;
084: m_contents = new ArrayList();
085: m_isOrdered = ord;
086: m_isFlexible = flex;
087: m_hasContext = defc;
088: if (defc) {
089: m_defContext = new DefinitionContext(contain);
090: } else {
091: m_defContext = contain.getDefinitionContext();
092: }
093: }
094:
095: /**
096: * Set the object context.
097: *
098: * @param objc object context
099: */
100: public void setObjectContext(IContextObj objc) {
101: m_contextObject = objc;
102: }
103:
104: /**
105: * Get the attribute children of this mapping.
106: *
107: * @return list of attribute children (<code>null</code> if none; should not
108: * be modified)
109: */
110: public ArrayList getAttributes() {
111: return m_attributes;
112: }
113:
114: /**
115: * Get the content children of this mapping.
116: *
117: * @return list of content children (should not be modified)
118: */
119: public ArrayList getContents() {
120: return m_contents;
121: }
122:
123: /**
124: * Add child component to nested structure. All components are initially
125: * assumed to contain content. When {@link #setLinkages} is called the
126: * components are checked to determine whether they actually supply
127: * attribute(s), content, or both.
128: *
129: * @param comp child component to be added to structure
130: */
131: public void addComponent(IComponent comp) {
132: m_contents.add(comp);
133: }
134:
135: /**
136: * Check if flexible unmarshalling.
137: *
138: * @return flexible flag
139: */
140: public boolean isFlexible() {
141: return m_isFlexible;
142: }
143:
144: //
145: // IContainer interface method definitions
146:
147: public boolean isContentOrdered() {
148: return m_isOrdered;
149: }
150:
151: public boolean hasNamespaces() {
152: return m_hasContext && m_defContext.hasNamespace();
153: }
154:
155: public BindingDefinition getBindingRoot() {
156: return m_container.getBindingRoot();
157: }
158:
159: public DefinitionContext getDefinitionContext() {
160: return m_defContext;
161: }
162:
163: //
164: // IComponent interface method definitions
165:
166: public boolean isOptional() {
167:
168: // optional if and only if all child components are optional
169: if (m_attributes != null) {
170: for (int i = 0; i < m_attributes.size(); i++) {
171: if (!((IComponent) m_attributes.get(i)).isOptional()) {
172: return false;
173: }
174: }
175: }
176: for (int i = 0; i < m_contents.size(); i++) {
177: if (!((IComponent) m_contents.get(i)).isOptional()) {
178: return false;
179: }
180: }
181: return true;
182: }
183:
184: public boolean hasContent() {
185: return m_contents.size() > 0;
186: }
187:
188: public void genContentPresentTest(ContextMethodBuilder mb)
189: throws JiBXException {
190: if (m_contents.size() > 0) {
191:
192: // if single possiblity just test it directly
193: int count = m_contents.size();
194: if (count == 1) {
195: ((IComponent) m_contents.get(0))
196: .genContentPresentTest(mb);
197: } else {
198:
199: // generate code for chained test with branches to found exit
200: BranchWrapper[] tofound = new BranchWrapper[count];
201: for (int i = 0; i < count; i++) {
202: IComponent comp = (IComponent) m_contents.get(i);
203: comp.genContentPresentTest(mb);
204: tofound[i] = mb.appendIFNE(this );
205: }
206:
207: // fall off end of loop to push "false" on stack and jump to end
208: mb.appendICONST_0();
209: BranchWrapper toend = mb
210: .appendUnconditionalBranch(this );
211:
212: // generate found target to push "true" on stack and continue
213: for (int i = 0; i < count; i++) {
214: mb.targetNext(tofound[i]);
215: }
216: mb.appendICONST_1();
217: mb.targetNext(toend);
218:
219: }
220: } else {
221: throw new IllegalStateException(
222: "Internal error - no content present");
223: }
224: }
225:
226: public void genNewInstance(ContextMethodBuilder mb) {
227: throw new IllegalStateException(
228: "Internal error - no instance creation");
229: }
230:
231: public String getType() {
232: return m_contextObject.getBoundClass().getClassName();
233: }
234:
235: public NameDefinition getWrapperName() {
236: if (m_contents.size() == 1) {
237: return ((IComponent) m_contents.get(0)).getWrapperName();
238: } else {
239: return null;
240: }
241: }
242: }
|