View Javadoc

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