001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.betwixt.io.read;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.apache.commons.betwixt.ElementDescriptor;
024: import org.apache.commons.betwixt.expression.Context;
025: import org.apache.commons.betwixt.expression.Updater;
026: import org.xml.sax.Attributes;
027:
028: /**
029: * <p>Acts to bind an array property.
030: * Note that this is intended to be used to map
031: * properties with a setter taking an array
032: * but which do not have an adder.</p>
033: * <p>
034: * <strong>Note</strong> this implementation has state
035: * and therefore cannot be used concurrently (in simultaneous readings).
036: * </p>
037: * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
038: * @version $Revision: 438373 $
039: */
040: public class ArrayBindAction extends MappingAction.Base {
041:
042: /**
043: * Factory method creates implementations to map arrays.
044: * @param elementDescriptor <code>ElementDescriptor</code> to be mapped,
045: * not null
046: * @return <code>MappingAction</code>, not null
047: */
048: public static final MappingAction createMappingAction(
049: ElementDescriptor elementDescriptor) {
050: MappingAction result = new ArrayBindAction();
051: if (elementDescriptor.getSingularPropertyType() != null
052: && !elementDescriptor.getSingularPropertyType()
053: .isArray()) {
054: result = BeanBindAction.INSTANCE;
055: }
056: return result;
057: }
058:
059: private BeanMapping beanMapping = new BeanMapping();
060: private Updater originalUpdater;
061:
062: /**
063: * Mapping arrays requires the addition of a temporary object
064: * (an <code>ArrayList</code>) into the stack together with an
065: * updater for that object.
066: *
067: */
068: public MappingAction begin(String namespace, String name,
069: Attributes attributes, ReadContext context)
070: throws Exception {
071: // push an array onto the object stack
072: context.pushBean(new ArrayList());
073: return this ;
074: }
075:
076: /**
077: * Pops the <code>ArrayList</code> and the updater from
078: * their stacks. The original updater is called with the
079: * result of the convertion.
080: */
081: public void end(ReadContext context) throws Exception {
082: if (originalUpdater != null) {
083: // create an array of appropriate type
084: List values = (List) context.popBean();
085: originalUpdater.update(context, values);
086: }
087: }
088:
089: /** Construct a delegating implmentation that wraps the real bean creator */
090: public MappingAction next(String namespace, String name,
091: Attributes attributes, ReadContext context)
092: throws Exception {
093: originalUpdater = context.getCurrentUpdater();
094: MappingAction nextBindAction = BeanBindAction.INSTANCE;
095: beanMapping.setDelegate(nextBindAction);
096: return beanMapping;
097: }
098:
099: /** Updates a list by adding the new value */
100: private static class ListUpdater implements Updater {
101: /** Singleton */
102: private static final ListUpdater INSTANCE = new ListUpdater();
103:
104: /** Update by adding the new value to the list */
105: public void update(Context context, Object newValue) {
106: List values = (List) context.getBean();
107: values.add(newValue);
108: }
109:
110: }
111:
112: private static class BeanMapping extends MappingAction.Base {
113: private MappingAction delegate;
114:
115: BeanMapping() {
116: }
117:
118: /**
119: * Gets the action to which the bean binding is delegated.
120: * @return <code>MappingAction</code> delegate, not null
121: */
122: MappingAction getDelegate() {
123: return delegate;
124: }
125:
126: /**
127: * Sets the action to which the bean binding is delegated.
128: * @param action< code>MappingAction</code> delegate, not null
129: */
130: void setDelegate(MappingAction action) {
131: delegate = action;
132: }
133:
134: /** Push updater and then delegate */
135: public MappingAction begin(String namespace, String name,
136: Attributes attributes, ReadContext context)
137: throws Exception {
138: context.pushUpdater(ListUpdater.INSTANCE);
139: delegate = delegate.begin(namespace, name, attributes,
140: context);
141: return this ;
142: }
143:
144: /** Delegate to delegate (Doh!) */
145: public void body(String text, ReadContext context)
146: throws Exception {
147: delegate.body(text, context);
148: }
149:
150: /** Call delegate then pop <code>Updater</code> */
151: public void end(ReadContext context) throws Exception {
152: delegate.end(context);
153: Updater updater = context.popUpdater();
154: }
155:
156: /** Use delegate to create next action */
157: public MappingAction next(String namespace, String name,
158: Attributes attributes, ReadContext context)
159: throws Exception {
160: return delegate.next(namespace, name, attributes, context);
161: }
162:
163: }
164: }
|