001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.ri.model.dynabeans;
017:
018: import java.util.Arrays;
019:
020: import org.apache.commons.beanutils.DynaBean;
021: import org.apache.commons.beanutils.DynaClass;
022: import org.apache.commons.beanutils.DynaProperty;
023: import org.apache.commons.jxpath.JXPathException;
024: import org.apache.commons.jxpath.ri.model.NodePointer;
025: import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
026: import org.apache.commons.jxpath.util.TypeUtils;
027: import org.apache.commons.jxpath.util.ValueUtils;
028:
029: /**
030: * Pointer pointing to a property of a DynaBean.
031: *
032: * @author Dmitri Plotnikov
033: * @version $Revision: 1.12 $ $Date: 2004/04/04 22:06:35 $
034: */
035: public class DynaBeanPropertyPointer extends PropertyPointer {
036: private DynaBean dynaBean;
037: private String name;
038: private String[] names;
039:
040: public DynaBeanPropertyPointer(NodePointer parent, DynaBean dynaBean) {
041: super (parent);
042: this .dynaBean = dynaBean;
043: }
044:
045: public Object getBaseValue() {
046: return dynaBean.get(getPropertyName());
047: }
048:
049: /**
050: * This type of node is auxiliary.
051: */
052: public boolean isContainer() {
053: return true;
054: }
055:
056: /**
057: * Number of the DP object's properties.
058: */
059: public int getPropertyCount() {
060: return getPropertyNames().length;
061: }
062:
063: /**
064: * Names of all properties, sorted alphabetically
065: *
066: * @todo do something about the sorting
067: */
068: public String[] getPropertyNames() {
069: if (names == null) {
070: DynaClass dynaClass = dynaBean.getDynaClass();
071: DynaProperty properties[] = dynaClass.getDynaProperties();
072: int count = properties.length;
073: boolean hasClass = dynaClass.getDynaProperty("class") != null;
074: if (hasClass) {
075: count--; // Exclude "class" from properties
076: }
077: names = new String[count];
078: for (int i = 0, j = 0; i < properties.length; i++) {
079: String name = properties[i].getName();
080: if (!hasClass || !name.equals("class")) {
081: names[j++] = name;
082: }
083: }
084: Arrays.sort(names);
085: }
086: return names;
087: }
088:
089: /**
090: * Returns the name of the currently selected property or "*"
091: * if none has been selected.
092: */
093: public String getPropertyName() {
094: if (name == null) {
095: String names[] = getPropertyNames();
096: if (propertyIndex >= 0 && propertyIndex < names.length) {
097: name = names[propertyIndex];
098: } else {
099: name = "*";
100: }
101: }
102: return name;
103: }
104:
105: /**
106: * Select a property by name.
107: */
108: public void setPropertyName(String propertyName) {
109: setPropertyIndex(UNSPECIFIED_PROPERTY);
110: this .name = propertyName;
111: }
112:
113: /**
114: * Index of the currently selected property in the list of all
115: * properties sorted alphabetically.
116: */
117: public int getPropertyIndex() {
118: if (propertyIndex == UNSPECIFIED_PROPERTY) {
119: String names[] = getPropertyNames();
120: for (int i = 0; i < names.length; i++) {
121: if (names[i].equals(name)) {
122: propertyIndex = i;
123: name = null;
124: break;
125: }
126: }
127: }
128: return super .getPropertyIndex();
129: }
130:
131: /**
132: * Index a property by its index in the list of all
133: * properties sorted alphabetically.
134: */
135: public void setPropertyIndex(int index) {
136: if (propertyIndex != index) {
137: super .setPropertyIndex(index);
138: name = null;
139: }
140: }
141:
142: /**
143: * If index == WHOLE_COLLECTION, the value of the property, otherwise
144: * the value of the index'th element of the collection represented by the
145: * property. If the property is not a collection, index should be zero
146: * and the value will be the property itself.
147: */
148: public Object getImmediateNode() {
149: String name = getPropertyName();
150: if (name.equals("*")) {
151: return null;
152: }
153:
154: Object value;
155: if (index == WHOLE_COLLECTION) {
156: value = ValueUtils.getValue(dynaBean.get(name));
157: } else if (isIndexedProperty()) {
158: // DynaClass at this point is not based on whether
159: // the property is indeed indexed, but rather on
160: // whether it is an array or List. Therefore
161: // the indexed set may fail.
162: try {
163: value = ValueUtils.getValue(dynaBean.get(name, index));
164: } catch (ArrayIndexOutOfBoundsException ex) {
165: value = null;
166: } catch (IllegalArgumentException ex) {
167: value = dynaBean.get(name);
168: value = ValueUtils.getValue(value, index);
169: }
170: } else {
171: value = dynaBean.get(name);
172: if (ValueUtils.isCollection(value)) {
173: value = ValueUtils.getValue(value, index);
174: } else if (index != 0) {
175: value = null;
176: }
177: }
178: return value;
179: }
180:
181: /**
182: * Returns true if the bean has the currently selected property
183: */
184: protected boolean isActualProperty() {
185: DynaClass dynaClass = dynaBean.getDynaClass();
186: return dynaClass.getDynaProperty(getPropertyName()) != null;
187: }
188:
189: protected boolean isIndexedProperty() {
190: DynaClass dynaClass = dynaBean.getDynaClass();
191: DynaProperty property = dynaClass.getDynaProperty(name);
192: return property.isIndexed();
193: }
194:
195: /**
196: * If index == WHOLE_COLLECTION, change the value of the property, otherwise
197: * change the value of the index'th element of the collection
198: * represented by the property.
199: */
200: public void setValue(Object value) {
201: setValue(index, value);
202: }
203:
204: public void remove() {
205: if (index == WHOLE_COLLECTION) {
206: dynaBean.set(getPropertyName(), null);
207: } else if (isIndexedProperty()) {
208: dynaBean.set(getPropertyName(), index, null);
209: } else if (isCollection()) {
210: Object collection = ValueUtils
211: .remove(getBaseValue(), index);
212: dynaBean.set(getPropertyName(), collection);
213: } else if (index == 0) {
214: dynaBean.set(getPropertyName(), null);
215: }
216: }
217:
218: private void setValue(int index, Object value) {
219: if (index == WHOLE_COLLECTION) {
220: dynaBean.set(getPropertyName(), convert(value, false));
221: } else if (isIndexedProperty()) {
222: dynaBean
223: .set(getPropertyName(), index, convert(value, true));
224: } else {
225: Object baseValue = dynaBean.get(getPropertyName());
226: ValueUtils.setValue(baseValue, index, value);
227: }
228: }
229:
230: private Object convert(Object value, boolean element) {
231: DynaClass dynaClass = (DynaClass) dynaBean.getDynaClass();
232: DynaProperty property = dynaClass
233: .getDynaProperty(getPropertyName());
234: Class type = property.getType();
235: if (element) {
236: if (type.isArray()) {
237: type = type.getComponentType();
238: } else {
239: return value; // No need to convert
240: }
241: }
242:
243: try {
244: return TypeUtils.convert(value, type);
245: } catch (Exception ex) {
246: throw new JXPathException("Cannot convert value of class "
247: + (value == null ? "null" : value.getClass()
248: .getName()) + " to type " + type, ex);
249: }
250: }
251: }
|