001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.model;
018:
019: import java.lang.reflect.Field;
020: import java.lang.reflect.Method;
021:
022: import org.apache.wicket.Application;
023: import org.apache.wicket.Component;
024: import org.apache.wicket.Session;
025: import org.apache.wicket.util.lang.PropertyResolver;
026: import org.apache.wicket.util.lang.PropertyResolverConverter;
027: import org.apache.wicket.util.string.Strings;
028:
029: /**
030: * Serves as a base class for different kinds of property models. By default,
031: * this class uses {@link PropertyResolver} to resolve expressions on the target
032: * model object. Note that the property resolver by default provides access to
033: * private members and methods. If guaranteeing encapsulation of the target
034: * objects is a big concern, you should consider using an alternative
035: * implementation.
036: *
037: * @see PropertyResolver
038: * @see org.apache.wicket.model.AbstractDetachableModel
039: *
040: * @author Chris Turner
041: * @author Eelco Hillenius
042: * @author Jonathan Locke
043: */
044: public abstract class AbstractPropertyModel implements IChainingModel,
045: IObjectClassAwareModel, IPropertyReflectionAwareModel {
046: /** Any model object (which may or may not implement IModel) */
047: private Object target;
048:
049: /**
050: * Constructor
051: *
052: * @param modelObject
053: * The nested model object
054: */
055: public AbstractPropertyModel(final Object modelObject) {
056: if (modelObject == null) {
057: throw new IllegalArgumentException(
058: "Parameter modelObject cannot be null");
059: }
060:
061: target = modelObject;
062: }
063:
064: /**
065: * Unsets this property model's instance variables and detaches the model.
066: *
067: * @see AbstractDetachableModel#onDetach()
068: */
069: public void detach() {
070: // Detach nested object if it's a detachable
071: if (target instanceof IDetachable) {
072: ((IDetachable) target).detach();
073: }
074: }
075:
076: /**
077: * @see org.apache.wicket.model.IChainingModel#getChainedModel()
078: */
079: public IModel getChainedModel() {
080: if (target instanceof IModel) {
081: return (IModel) target;
082: }
083: return null;
084: }
085:
086: /**
087: * @see org.apache.wicket.model.IModel#getObject()
088: */
089: public Object getObject() {
090: final String expression = propertyExpression();
091: if (Strings.isEmpty(expression)) {
092: // Return a meaningful value for an empty property expression
093: return getTarget();
094: }
095:
096: final Object target = getTarget();
097: if (target != null) {
098: return PropertyResolver.getValue(expression, target);
099: }
100: return null;
101: }
102:
103: /**
104: * Gets the property expression for this model
105: *
106: * @return The property expression
107: */
108: public final String getPropertyExpression() {
109: return propertyExpression();
110: }
111:
112: /**
113: * @see org.apache.wicket.model.IChainingModel#setChainedModel(org.apache.wicket.model.IModel)
114: */
115: public void setChainedModel(IModel model) {
116: target = model;
117: }
118:
119: /**
120: * Applies the property expression on the model object using the given
121: * object argument.
122: *
123: * @param object
124: * The object that will be used when setting a value on the model
125: * object
126: * @see IModel#setObject(Object)
127: */
128: public void setObject(Object object) {
129: final String expression = propertyExpression();
130: if (Strings.isEmpty(expression)) {
131: // TODO check, really do this?
132: // why not just set the target to the object?
133: if (target instanceof IModel) {
134: ((IModel) target).setObject(object);
135: } else {
136: target = object;
137: }
138: } else {
139: PropertyResolverConverter prc = null;
140: prc = new PropertyResolverConverter(Application.get()
141: .getConverterLocator(), Session.get().getLocale());
142: PropertyResolver.setValue(expression, getTarget(), object,
143: prc);
144: }
145: }
146:
147: /**
148: * @see java.lang.Object#toString()
149: */
150: public String toString() {
151: StringBuffer sb = new StringBuffer("Model:classname=[");
152: sb.append(getClass().getName()).append("]");
153: sb.append(":nestedModel=[").append(target).append("]");
154: return sb.toString();
155: }
156:
157: /**
158: * @return The target object
159: */
160: public final Object getTarget() {
161: Object object = target;
162: while (object instanceof IModel) {
163: Object tmp = ((IModel) object).getObject();
164: if (tmp == object)
165: break;
166: object = tmp;
167: }
168: return object;
169: }
170:
171: /**
172: * @return model object class
173: */
174: public Class getObjectClass() {
175: final String expression = propertyExpression();
176: if (Strings.isEmpty(expression)) {
177: // Return a meaningful value for an empty property expression
178: Object target = getTarget();
179: return target != null ? target.getClass() : null;
180: }
181:
182: final Object target = getTarget();
183: if (target != null) {
184: return PropertyResolver
185: .getPropertyClass(expression, target);
186: }
187: return null;
188: }
189:
190: /**
191: * @see org.apache.wicket.model.IPropertyReflectionAwareModel#getPropertyField()
192: */
193: public Field getPropertyField() {
194: String expression = propertyExpression();
195: if (Strings.isEmpty(expression) == false) {
196: Object target = getTarget();
197: if (target != null) {
198: try {
199: return PropertyResolver.getPropertyField(
200: expression, target);
201: } catch (Exception ignore) {
202: }
203: }
204: }
205: return null;
206: }
207:
208: /**
209: * @see org.apache.wicket.model.IPropertyReflectionAwareModel#getPropertyGetter()
210: */
211: public Method getPropertyGetter() {
212: String expression = propertyExpression();
213: if (Strings.isEmpty(expression) == false) {
214: Object target = getTarget();
215: if (target != null) {
216: try {
217: return PropertyResolver.getPropertyGetter(
218: expression, target);
219: } catch (Exception ignore) {
220: }
221: }
222: }
223: return null;
224: }
225:
226: /**
227: * @see org.apache.wicket.model.IPropertyReflectionAwareModel#getPropertySetter()
228: */
229: public Method getPropertySetter() {
230: String expression = propertyExpression();
231: if (Strings.isEmpty(expression) == false) {
232: Object target = getTarget();
233: if (target != null) {
234: try {
235: return PropertyResolver.getPropertySetter(
236: expression, target);
237: } catch (Exception ignore) {
238: }
239: }
240: }
241: return null;
242: }
243:
244: /**
245: * @return The property expression for the component
246: */
247: protected abstract String propertyExpression();
248:
249: /**
250: * @param component
251: * @return nothing
252: * @deprecated use {@link #getObject()} instead
253: */
254: protected final Object onGetObject(Component component) {
255: throw new UnsupportedOperationException();
256: }
257:
258: // TODO remove these methods after a deprecation release
259:
260: /**
261: * @param component
262: * @param object
263: * @deprecated use {@link #setObject(object)} instead
264: */
265: protected final void onSetObject(Component component, Object object) {
266: throw new UnsupportedOperationException();
267: }
268:
269: }
|