KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > naming > IndexedNameInterceptor


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  * $Header:$
17  */

18 package org.apache.beehive.netui.tags.naming;
19
20 // java imports
21

22 import org.apache.beehive.netui.script.Expression;
23 import org.apache.beehive.netui.script.ExpressionEvaluationException;
24 import org.apache.beehive.netui.script.ExpressionEvaluator;
25 import org.apache.beehive.netui.script.ExpressionEvaluatorFactory;
26 import org.apache.beehive.netui.script.common.IDataAccessProvider;
27 import org.apache.beehive.netui.util.logging.Logger;
28
29 import javax.servlet.jsp.tagext.SimpleTagSupport JavaDoc;
30 import javax.servlet.jsp.tagext.Tag JavaDoc;
31 import java.util.List JavaDoc;
32
33 // external imports
34

35 /**
36  * A {@link INameInterceptor} that is used to rewrite names which
37  * reference the <code>container</code> databinding context. This
38  * INameInterceptor is for use by tags that render form-updatable HTML
39  * elements. If the dataSource attribute of the tag references a
40  * <code>container</code> binding context, the name must be qualified
41  * into a real path down a bean / property hierarchy in order to
42  * correctly update that value on a POST. This INameInterceptor
43  * rewrites that name using the given name and the hierarchy of
44  * {@link org.apache.beehive.netui.script.common.IDataAccessProvider} tags in a JSP page.
45  */

46 public class IndexedNameInterceptor
47         implements INameInterceptor
48 {
49     private static final Logger _logger = Logger.getInstance(IndexedNameInterceptor.class);
50
51     /**
52      * Rewrite an expression into a fully-qualified reference to a specific JavaBean property
53      * on an object.
54      * @param name the expression to rewrite
55      * @param currentTag the current JSP tag that can be used as the leaf for walking up
56      * to find parent tags that provide information used to
57      * rewrite the expression.
58      */

59     public final String JavaDoc rewriteName(String JavaDoc name, Tag JavaDoc currentTag)
60             throws ExpressionEvaluationException
61     {
62         if (_logger.isDebugEnabled()) _logger.debug("rewrite expression \"" + name + "\"");
63
64         IDataAccessProvider dap = getCurrentProvider(currentTag);
65         // if the DAP is null, there is no rewriting to do
66
if (dap == null)
67             return name;
68
69         // given a hierarchy of "container.container.container.item.someProp", the correct parent needs
70
// to be found so that expression rewriting can happen correctly.
71
//
72
// ensure that this expression contains container.item
73
Expression parsed = getExpressionEvaluator().parseExpression(name);
74         assert parsed != null;
75
76         int containerCount = 0;
77         List JavaDoc tokens = parsed.getTokens();
78         for (int i = 0; i < tokens.size(); i++) {
79             String JavaDoc tok = tokens.get(i).toString();
80             if (i == 0) {
81                 if (!tok.equals("container"))
82                     break;
83                 else
84                     continue;
85             }
86             // this skips the "current" IDataAccessProvider
87
else if (tok.equals("container"))
88                 containerCount++;
89             else if (tok.equals("item"))
90                 break;
91         }
92
93         if (_logger.isDebugEnabled()) _logger.debug("container parent count: " + containerCount);
94
95         // now walk up the DataAccessProvier hierarchy until the top-most parent is found
96
// the top-most parent is the first one that does not reference "container.item" but
97
// is bound directly to a specific object such as "actionForm" or "pageFlow". This
98
// handles the case where a set of nested IDataAccessProvider tags are "skipped" by
99
// an expression like "container.container.container.item.foo". In order to find
100
// the correct root to start rewriting the names, one needs to walk up three
101
// DAPs in order to find the correct root from which to start.
102
//
103
// In general, containerCount is zero here for the "container.item.foo" case.
104
for (int i = 0; i < containerCount; i++) {
105             dap = dap.getProviderParent();
106         }
107
108         // now, the top-most DAP parent is known
109
assert dap != null;
110         
111         // strip off the "container.item" from the expression that is being rewritten
112
// this should be two tokens into the expression.
113
if (containerCount > 0) {
114             name = parsed.getExpression(containerCount);
115         }
116
117         // now, change the binding context of the parent DAP hierarchy to create a
118
// String that looks like "actionForm.customers[42].order[12].lineItem[2].name"
119
// note, this is done without using the expression that was passed-in and
120
// is derived entirely from the IDataAccessProvider parent hierarchy.
121
String JavaDoc parentNames = rewriteNameInternal(dap);
122
123         if (_logger.isDebugEnabled()) _logger.debug("name hierarchy: " + parentNames + " name: " + name);
124
125         // with a newly re-written expression prefix, substitute this fully-qualified binding
126
// string into the given expression for "container.item".
127
String JavaDoc newName = changeContext(name, "container.item", parentNames, dap.getCurrentIndex());
128
129         if (_logger.isDebugEnabled()) _logger.debug("rewrittenName: " + newName);
130
131         return newName;
132     }
133
134     /**
135      * A default method to find the "current" IDataAccessProvider. This method is
136      * left as non-final so that the implementation here can be tested
137      * outside of a servlet container.
138      */

139     protected IDataAccessProvider getCurrentProvider(Tag JavaDoc tag)
140     {
141         return (IDataAccessProvider) SimpleTagSupport.findAncestorWithClass(tag, IDataAccessProvider.class);
142     }
143
144     /**
145      * Rewrite a parent IDataAccessProvider's dataSource to be fully qualified.
146      *
147      * "container.container.container.container.item.foo" -> "DS1.DS2.DS3.DS4.foo"
148      */

149     private final String JavaDoc rewriteNameInternal(IDataAccessProvider dap)
150             throws ExpressionEvaluationException
151     {
152         if (_logger.isDebugEnabled())
153             _logger.debug("assign index to name: " + dap.getDataSource());
154
155         Expression parsedDataSource = getExpressionEvaluator().parseExpression(dap.getDataSource());
156         assert parsedDataSource != null;
157
158         // @todo: perf
159
boolean isContainerBound = (parsedDataSource.getTokens().get(0)).toString().equals("container");
160
161         // rewrite the name of the current IDataAccessProvider.
162
String JavaDoc parentName = null;
163         // if the current DAP has a parent IDataAccessProvider, rewrite the name of the parent
164
if (dap.getProviderParent() != null)
165             parentName = rewriteNameInternal(dap.getProviderParent());
166         // if the current DAP has no parent, or it does not reference the "container." binding context,
167
// we've found the "root" IDataAccessProvider
168
else if (dap.getProviderParent() == null || (dap.getProviderParent() != null && !isContainerBound)) {
169             return dap.getDataSource();
170         }
171
172         // now, we've found the root and can start rewriting the expressions throughout
173
// the rest of the DAP hierarchy
174
if (_logger.isDebugEnabled()) {
175             _logger.debug("changeContext: DAP.dataSource=" + dap.getDataSource() + " oldContext=container newContext=" +
176                     parentName + " currentIndex=" + dap.getProviderParent().getCurrentIndex() +
177                     " parentName is container: " + isContainerBound);
178         }
179
180         String JavaDoc retVal = null;
181         String JavaDoc ds = dap.getDataSource();
182
183         // If the current DAP's dataSource is "container.item", the binding context needs to change to that
184
// of the parent. This case should only occur for the last token -- the "name" passed into
185
// the method. Oterwise, just replace the "container" to that of the parent. Both are
186
// qualified with the DAP's current index so that "actionForm.customers" becomes
187
// "actionForm.customers[12]".
188

189         boolean isContainerItemBound = false;
190         if (isContainerBound && (parsedDataSource.getTokens().get(1)).toString().equals("item"))
191             isContainerItemBound = true;
192
193         if (isContainerItemBound)
194             retVal = changeContext(ds, "container.item", parentName, dap.getProviderParent().getCurrentIndex());
195         else
196             retVal = changeContext(ds, "container", parentName, dap.getProviderParent().getCurrentIndex());
197
198         if (_logger.isDebugEnabled()) _logger.debug("fully-qualified binding expression: \"" + retVal + "\"");
199
200         return retVal;
201     }
202
203     protected ExpressionEvaluator getExpressionEvaluator()
204     {
205         return ExpressionEvaluatorFactory.getInstance();
206     }
207
208     private final String JavaDoc changeContext(String JavaDoc dataSource, String JavaDoc oldContext, String JavaDoc newContext, int index)
209             throws ExpressionEvaluationException
210     {
211         try {
212             return getExpressionEvaluator().changeContext(dataSource, oldContext, newContext, index);
213         }
214         catch (ExpressionEvaluationException ee) {
215             if (_logger.isErrorEnabled())
216                 _logger.error("An error occurred changing the binding context of the expression \"" +
217                         dataSource + "\". Cause: " + ee, ee);
218
219             throw ee;
220         }
221     }
222 }
223
Popular Tags