View Javadoc

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  	/* (non-Javadoc)
67  	 * @see echobinding.Binding#setValue(java.lang.Object, java.lang.Object)
68  	 */
69  	public void setValue(Object bean, Object value) {
70  		setValue(null, bean, value);
71  	}
72  
73  	/* (non-Javadoc)
74  	 * @see echobinding.Binding#getValue(java.lang.Object)
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          	// e.printStackTrace();
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 		// _logger.debug( "Looking up property '" + getExpression() + "' bean class = " + bean.getClass() + " OgnlContext =  "+context);
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        //  _logger.debug( "Property '" + getExpression() + "' was found. Value = " + value );
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 	/* (non-Javadoc)
185 	 * @see echobinding.binding.AbstractPropertyAdapter#validate(java.lang.Object, java.lang.Object)
186 	 */
187 	@Override
188 	public ValidationReport validate(Object bean, Object value) {
189 		ValidationReport report = super.validate( bean, value );
190 		
191 		// validate bean
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 			// e.printStackTrace();
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 }