View Javadoc

1   package org.apache.commons.digester3;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import static java.lang.String.format;
23  import java.util.Stack;
24  
25  import org.xml.sax.Attributes;
26  
27  /**
28   * <p>
29   * Rule implementation that saves a parameter for use by a surrounding <code>CallMethodRule<code>.
30   * </p>
31   * <p>
32   * This parameter may be:
33   * <ul>
34   * <li>from an attribute of the current element See {@link #CallParamRule(int paramIndex, String attributeName)}
35   * <li>from current the element body See {@link #CallParamRule(int paramIndex)}
36   * <li>from the top object on the stack. See {@link #CallParamRule(int paramIndex, boolean fromStack)}
37   * <li>the current path being processed (separate <code>Rule</code>). See {@link PathCallParamRule}
38   * </ul>
39   * </p>
40   */
41  public class CallParamRule
42      extends Rule
43  {
44  
45      // ----------------------------------------------------------- Constructors
46  
47      /**
48       * Construct a "call parameter" rule that will save the body text of this element as the parameter value.
49       * <p>
50       * Note that if the element is empty the an <i>empty string</i> is passed to the target method, not null. And if
51       * automatic type conversion is being applied (ie if the target function takes something other than a string as a
52       * parameter) then the conversion will fail if the converter class does not accept an empty string as valid input.
53       * </p>
54       * 
55       * @param paramIndex The zero-relative parameter number
56       */
57      public CallParamRule( int paramIndex )
58      {
59          this( paramIndex, null );
60      }
61  
62      /**
63       * Construct a "call parameter" rule that will save the value of the specified attribute as the parameter value.
64       * 
65       * @param paramIndex The zero-relative parameter number
66       * @param attributeName The name of the attribute to save
67       */
68      public CallParamRule( int paramIndex, String attributeName )
69      {
70          this.paramIndex = paramIndex;
71          this.attributeName = attributeName;
72      }
73  
74      /**
75       * Construct a "call parameter" rule.
76       * 
77       * @param paramIndex The zero-relative parameter number
78       * @param fromStack should this parameter be taken from the top of the stack?
79       */
80      public CallParamRule( int paramIndex, boolean fromStack )
81      {
82          this.paramIndex = paramIndex;
83          this.fromStack = fromStack;
84      }
85  
86      /**
87       * Constructs a "call parameter" rule which sets a parameter from the stack. If the stack contains too few objects,
88       * then the parameter will be set to null.
89       * 
90       * @param paramIndex The zero-relative parameter number
91       * @param stackIndex the index of the object which will be passed as a parameter. The zeroth object is the top of
92       *            the stack, 1 is the next object down and so on.
93       */
94      public CallParamRule( int paramIndex, int stackIndex )
95      {
96          this.paramIndex = paramIndex;
97          this.fromStack = true;
98          this.stackIndex = stackIndex;
99      }
100 
101     // ----------------------------------------------------- Instance Variables
102 
103     /**
104      * The attribute from which to save the parameter value
105      */
106     protected String attributeName = null;
107 
108     /**
109      * The zero-relative index of the parameter we are saving.
110      */
111     protected int paramIndex = 0;
112 
113     /**
114      * Is the parameter to be set from the stack?
115      */
116     protected boolean fromStack = false;
117 
118     /**
119      * The position of the object from the top of the stack
120      */
121     protected int stackIndex = 0;
122 
123     /**
124      * Stack is used to allow nested body text to be processed. Lazy creation.
125      */
126     protected Stack<String> bodyTextStack;
127 
128     // --------------------------------------------------------- Public Methods
129 
130     /**
131      * Set the attribute from which to save the parameter value.
132      *
133      * @param attributeName The attribute from which to save the parameter value
134      * @since 3.0
135      */
136     public void setAttributeName( String attributeName )
137     {
138         this.attributeName = attributeName;
139     }
140 
141     /**
142      * {@inheritDoc}
143      */
144     @Override
145     public void begin( String namespace, String name, Attributes attributes )
146         throws Exception
147     {
148         Object param = null;
149 
150         if ( attributeName != null )
151         {
152 
153             param = attributes.getValue( attributeName );
154 
155         }
156         else if ( fromStack )
157         {
158 
159             param = getDigester().peek( stackIndex );
160 
161             if ( getDigester().getLogger().isDebugEnabled() )
162             {
163                 getDigester()
164                     .getLogger().debug( format( "[CallParamRule]{%s} Save from stack; from stack?%s; object=%s",
165                                                 getDigester().getMatch(), fromStack, param ) );
166             }
167         }
168 
169         // Have to save the param object to the param stack frame here.
170         // Can't wait until end(). Otherwise, the object will be lost.
171         // We can't save the object as instance variables, as
172         // the instance variables will be overwritten
173         // if this CallParamRule is reused in subsequent nesting.
174 
175         if ( param != null )
176         {
177             Object parameters[] = getDigester().peekParams();
178             parameters[paramIndex] = param;
179         }
180     }
181 
182     /**
183      * {@inheritDoc}
184      */
185     @Override
186     public void body( String namespace, String name, String text )
187         throws Exception
188     {
189         if ( attributeName == null && !fromStack )
190         {
191             // We must wait to set the parameter until end
192             // so that we can make sure that the right set of parameters
193             // is at the top of the stack
194             if ( bodyTextStack == null )
195             {
196                 bodyTextStack = new Stack<String>();
197             }
198             bodyTextStack.push( text.trim() );
199         }
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
205     @Override
206     public void end( String namespace, String name )
207     {
208         if ( bodyTextStack != null && !bodyTextStack.empty() )
209         {
210             // what we do now is push one parameter onto the top set of parameters
211             Object parameters[] = getDigester().peekParams();
212             parameters[paramIndex] = bodyTextStack.pop();
213         }
214     }
215 
216     /**
217      * {@inheritDoc}
218      */
219     @Override
220     public String toString()
221     {
222         return format( "CallParamRule[paramIndex=%s, attributeName=%s, from stack=%s]",
223                        paramIndex, attributeName, fromStack );
224     }
225 
226 }