View Javadoc

1   /*
2    * Copyright 2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16   
17  package org.apache.commons.betwixt.io.read;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.apache.commons.betwixt.ElementDescriptor;
23  import org.apache.commons.betwixt.expression.Context;
24  import org.apache.commons.betwixt.expression.Updater;
25  import org.xml.sax.Attributes;
26  
27  /***
28   * <p>Acts to bind an array property.
29   * Note that this is intended to be used to map 
30   * properties with a setter taking an array 
31   * but which do not have an adder.</p>
32   * <p>
33   * <strong>Note</strong> this implementation has state 
34   * and therefore cannot be used concurrently (in simultaneous readings).
35   * </p>
36   * @author <a href='http://jakarta.apache.org/'>Jakarta Commons Team</a>
37   * @version $Revision: 155402 $
38   */
39  public class ArrayBindAction extends MappingAction.Base {
40     
41      
42      /***
43       * Factory method creates implementations to map arrays.
44       * @param elementDescriptor <code>ElementDescriptor</code> to be mapped, 
45       * not null
46       * @return <code>MappingAction</code>, not null 
47       */
48      public static final MappingAction createMappingAction(ElementDescriptor elementDescriptor) {
49          MappingAction result = new ArrayBindAction();
50          if (elementDescriptor.getSingularPropertyType() != null && 
51                  !elementDescriptor.getSingularPropertyType().isArray()) {
52              result = BeanBindAction.INSTANCE;
53          }
54          return result;
55      }
56      
57      private BeanMapping beanMapping = new BeanMapping();
58      private Updater originalUpdater;
59      
60      /***
61       * Mapping arrays requires the addition of a temporary object
62       * (an <code>ArrayList</code>) into the stack together with an
63       * updater for that object.   
64       *    
65       */
66      public MappingAction begin(
67          String namespace,
68          String name,
69          Attributes attributes,
70          ReadContext context)
71          throws Exception {
72          // push an array onto the object stack
73          context.pushBean(new ArrayList());
74          return this;
75      }
76  
77      /***
78       * Pops the <code>ArrayList</code> and the updater from
79       * their stacks. The original updater is called with the
80       * result of the convertion.      
81       */
82      public void end(ReadContext context) throws Exception {
83          if (originalUpdater != null) {       
84              // create an array of appropriate type
85              List values = (List) context.popBean();
86              originalUpdater.update(context, values);
87          }
88      }    
89      
90      /*** Construct a delegating implmentation that wraps the real bean creator */
91      public MappingAction next(
92          String namespace,
93          String name,
94          Attributes attributes,
95          ReadContext context)
96          throws Exception {
97          originalUpdater = context.getCurrentUpdater();
98          MappingAction nextBindAction = BeanBindAction.INSTANCE;
99          beanMapping.setDelegate(nextBindAction);
100         return beanMapping;
101     }
102 
103     
104     
105     /*** Updates a list by adding the new value */
106     private static class ListUpdater implements Updater {
107         /*** Singleton */
108         private static final ListUpdater INSTANCE = new ListUpdater();
109         
110         /*** Update by adding the new value to the list */
111         public void update(Context context, Object newValue) {
112             List values = (List) context.getBean();
113             values.add(newValue);
114         }
115         
116     }
117     
118     private static class BeanMapping extends MappingAction.Base {
119         private MappingAction delegate;
120         
121         BeanMapping() {}
122         
123 
124         /***
125          * Gets the action to which the bean binding is delegated.
126          * @return <code>MappingAction</code> delegate, not null
127          */
128         MappingAction getDelegate() {
129             return delegate;
130         }
131 
132         /***
133          * Sets the action to which the bean binding is delegated.
134          * @param action< code>MappingAction</code> delegate, not null
135          */
136         void setDelegate(MappingAction action) {
137             delegate = action;
138         }
139         
140         /*** Push updater and then delegate */
141         public MappingAction begin(
142             String namespace,
143             String name,
144             Attributes attributes,
145             ReadContext context)
146             throws Exception {
147             context.pushUpdater(ListUpdater.INSTANCE);
148             delegate = delegate.begin(namespace, name, attributes, context);
149             return this;
150         }
151 
152         /*** Delegate to delegate (Doh!) */
153         public void body(String text, ReadContext context) throws Exception {
154             delegate.body(text, context);
155         }
156 
157         /*** Call delegate then pop <code>Updater</code> */
158         public void end(ReadContext context) throws Exception {
159             delegate.end(context);
160             Updater updater = context.popUpdater();
161         }
162 
163         /*** Use delegate to create next action */
164         public MappingAction next(
165             String namespace,
166             String name,
167             Attributes attributes,
168             ReadContext context)
169             throws Exception {
170             return delegate.next(namespace, name, attributes, context);
171         }
172 
173 
174     }
175 }