1 /***
2 * Copyright (C) 2006 Philipp Mpalampanis
3 *
4 * License: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Alternatively, the contents of this file may be used under the terms of
17 * either the GNU General Public License Version 2 or later (the "GPL"), or
18 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19 * in which case the provisions of the GPL or the LGPL are applicable instead
20 * of those above. If you wish to allow use of your version of this file only
21 * under the terms of either the GPL or the LGPL, and not to allow others to
22 * use your version of this file under the terms of the MPL, indicate your
23 * decision by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL or the LGPL. If you do not delete
25 * the provisions above, a recipient may use your version of this file under
26 * the terms of any one of the MPL, the GPL or the LGPL.
27 */
28
29 package net.sf.echobinding.binding;
30
31 import java.util.StringTokenizer;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34
35 import net.sf.echobinding.validation.BeanValidator;
36 import net.sf.echobinding.validation.ValidationReport;
37 import ognl.*;
38
39 import org.apache.log4j.Logger;
40 import org.hibernate.Hibernate;
41
42 /***
43 * This is an implemenation of the <code>PropertyAdaper</code> interface using OGNL
44 * expressions for accessing domain model properties.
45 *
46 */
47 public class OgnlPropertyAdapter extends AbstractPropertyAdapter {
48
49 @SuppressWarnings("unused")
50 private final Logger _logger = Logger.getLogger(OgnlPropertyAdapter.class);
51
52 private String _expression;
53
54 private Object _parsedExpression;
55
56 /***
57 * Creates a new PropertyAdapter using OGNL expressions for accessing model properties.
58 *
59 * @param expression The OGNL expression
60 */
61 public OgnlPropertyAdapter(String expression) {
62 setExpression(expression);
63 }
64
65
66
67
68
69 public void setValue(Object bean, Object value) {
70 setValue(null, bean, value);
71 }
72
73
74
75
76 public Object getValue(Object bean) throws BindingException {
77 return getValue(null, bean);
78 }
79
80
81 /***
82 * Sets the value.
83 *
84 * @param context
85 * @param bean
86 * @param value
87 * @throws BindingException
88 */
89 public void setValue(OgnlContext context, Object bean, Object value) throws BindingException {
90
91 Object newValue = parse(value);
92 try {
93 if(context != null)
94 Ognl.setValue(_parsedExpression, context, bean, newValue);
95 else
96 Ognl.setValue(_parsedExpression, bean, newValue);
97 }
98 catch (OgnlException e) {
99
100 throw new BindingException(e.getMessage(), e);
101 }
102 }
103
104
105 /***
106 *
107 * @param context
108 * @param bean
109 * @return
110 */
111 public Object getValue(OgnlContext context, Object bean) {
112 if (context == null && bean == null)
113 throw new BindingException("Bean and context must not be null!");
114
115
116
117 Object value = null;
118 try {
119 if(context != null)
120 value = Ognl.getValue( _parsedExpression, context, bean );
121 else
122 value = Ognl.getValue( _parsedExpression, bean );
123 }
124 catch (OgnlException e) {
125 _logger.debug( "Property '" + getExpression() + "' not found. Exception = " + e.getMessage() );
126 String hint ="An error has occured.";
127 if(e instanceof ognl.NoSuchPropertyException) {
128 if(bean != null) {
129 hint="Property not found in class "+bean.getClass().getName()+". ";
130 }
131 }
132 throw new BindingException("Could not get value for property adapter '"+getId()+"' (expression='"+getExpression()+"')! "+hint+"", e);
133 }
134
135 return value == null ? null : format(value);
136 }
137
138
139 /***
140 * Validates a bean property by examing its annotated contraints.
141 *
142 * @param bean
143 * @param value
144 * @return
145 *
146 * @see Hibernate Validation Framework
147 *
148 * @throws OgnlException
149 */
150 public ValidationReport validateBean(Object bean, Object value) {
151
152 Node node = (Node) _parsedExpression;
153
154 String ognlContextName = getOgnlContextName();
155 if(ognlContextName!=null) {
156 String expression = getExpression().replaceFirst( "#"+ognlContextName+"//.", "" );
157 node = (Node) parseExpression( expression );
158 }
159
160 String propertyName;
161 Node child;
162
163 ValidationReport validationReport = null;
164 for( int i = 0; i < node.jjtGetNumChildren(); i++ ) {
165
166 child = node.jjtGetChild(i);
167 propertyName = child.toString().replaceAll("\"", "");
168
169 validationReport = BeanValidator.validate(bean, propertyName, value);
170
171 OgnlContext context = (OgnlContext) Ognl.createDefaultContext(bean);
172 try {
173 bean = child.getValue( context, bean);
174 } catch (OgnlException e) {
175 e.printStackTrace();
176 }
177 }
178
179 return validationReport;
180 }
181
182
183
184
185
186
187 @Override
188 public ValidationReport validate(Object bean, Object value) {
189 ValidationReport report = super.validate( bean, value );
190
191
192 if(report.isValid())
193 report = validateBean(bean, parse( value ));
194
195 return report;
196 }
197
198
199 public PropertyAdapter newInstance() {
200
201 OgnlPropertyAdapter binding = new OgnlPropertyAdapter(getExpression());
202 binding.setDecorator(getDecorator());
203 binding.setFormat(getFormat());
204 binding.setLabel(getLabel());
205 binding.setSubContext(getSubContext());
206 binding.setValidators(getValidators());
207 binding.setValidationHandler(getValidationHandler());
208
209 return binding;
210 }
211
212
213 @Override
214 public String toString() {
215 return "OgnlPropertyAdapter#"+getExpression()+"#"+hashCode();
216 }
217
218
219 /***
220 * @return Returns the parsedExpression.
221 */
222 protected Object getParsedExpression() {
223 return _parsedExpression;
224 }
225
226 /***
227 * Returns the OGNL expression.
228 *
229 * @return The OGNL expression
230 */
231 public String getExpression() {
232 return _expression;
233 }
234
235 /***
236 * Sets the OGNL expression.
237 *
238 * @param the OGNL expression
239 * @return the property adapter
240 */
241 public void setExpression(String expression) {
242 _expression = expression;
243 _parsedExpression = parseExpression( expression );
244 }
245
246
247 /***
248 * @param expression
249 * @return
250 */
251 private Object parseExpression(String expression) {
252 Object parsedExpression = null;
253 try {
254 parsedExpression = Ognl.parseExpression(expression);
255 } catch (OgnlException e) {
256
257 throw new BindingException(e.getMessage(), e);
258 }
259 return parsedExpression;
260 }
261
262
263 @Override
264 public String getLabel() {
265 if(super.getLabel() == null)
266 return createLabel();
267 return super.getLabel();
268 }
269 /***
270 *
271 * @return
272 */
273 private String createLabel() {
274
275 String label ="";
276 StringTokenizer tokenizer = new StringTokenizer(_expression, ".");
277 while(tokenizer.hasMoreTokens()) {
278 String token = tokenizer.nextToken();
279 label += token.substring(0,1).toUpperCase() + token.substring(1, token.length()).toLowerCase();
280 }
281
282 return label;
283 }
284
285
286 /***
287 * @return
288 */
289 public String getOgnlContextName() {
290
291 Pattern pattern = Pattern.compile( "#(.*?)//..*" );
292 Matcher matcher = pattern.matcher( getExpression() );
293 if(matcher.matches())
294 return matcher.group( 1 );
295 return null;
296 }
297
298 }