1 16 package org.apache.commons.jxpath.ri.model.dynamic; 17 18 import java.util.Arrays ; 19 import java.util.Map ; 20 21 import org.apache.commons.jxpath.AbstractFactory; 22 import org.apache.commons.jxpath.DynamicPropertyHandler; 23 import org.apache.commons.jxpath.JXPathContext; 24 import org.apache.commons.jxpath.JXPathException; 25 import org.apache.commons.jxpath.ri.model.NodePointer; 26 import org.apache.commons.jxpath.ri.model.beans.PropertyPointer; 27 import org.apache.commons.jxpath.util.ValueUtils; 28 29 35 public class DynamicPropertyPointer extends PropertyPointer { 36 private DynamicPropertyHandler handler; 37 private String name; 38 private String [] names; 39 private String requiredPropertyName; 40 41 public DynamicPropertyPointer( 42 NodePointer parent, 43 DynamicPropertyHandler handler) 44 { 45 super(parent); 46 this.handler = handler; 47 } 48 51 public boolean isContainer() { 52 return true; 53 } 54 55 58 public int getPropertyCount() { 59 return getPropertyNames().length; 60 } 61 62 65 public String [] getPropertyNames() { 66 if (names == null) { 67 String allNames[] = handler.getPropertyNames(getBean()); 68 names = new String [allNames.length]; 69 for (int i = 0; i < names.length; i++) { 70 names[i] = allNames[i]; 71 } 72 Arrays.sort(names); 73 if (requiredPropertyName != null) { 74 int inx = Arrays.binarySearch(names, requiredPropertyName); 75 if (inx < 0) { 76 allNames = names; 77 names = new String [allNames.length + 1]; 78 names[0] = requiredPropertyName; 79 System.arraycopy(allNames, 0, names, 1, allNames.length); 80 Arrays.sort(names); 81 } 82 } 83 } 84 return names; 85 } 86 87 91 public String getPropertyName() { 92 if (name == null) { 93 String names[] = getPropertyNames(); 94 if (propertyIndex >= 0 && propertyIndex < names.length) { 95 name = names[propertyIndex]; 96 } 97 else { 98 name = "*"; 99 } 100 } 101 return name; 102 } 103 104 111 public void setPropertyName(String propertyName) { 112 setPropertyIndex(UNSPECIFIED_PROPERTY); 113 this.name = propertyName; 114 requiredPropertyName = propertyName; 115 if (names != null && Arrays.binarySearch(names, propertyName) < 0) { 116 names = null; 117 } 118 } 119 120 124 public int getPropertyIndex() { 125 if (propertyIndex == UNSPECIFIED_PROPERTY) { 126 String names[] = getPropertyNames(); 127 for (int i = 0; i < names.length; i++) { 128 if (names[i].equals(name)) { 129 setPropertyIndex(i); 130 break; 131 } 132 } 133 } 134 return super.getPropertyIndex(); 135 } 136 137 141 public void setPropertyIndex(int index) { 142 if (propertyIndex != index) { 143 super.setPropertyIndex(index); 144 name = null; 145 } 146 } 147 148 152 public Object getBaseValue() { 153 return handler.getProperty(getBean(), getPropertyName()); 154 } 155 156 162 public Object getImmediateNode() { 163 Object value; 164 if (index == WHOLE_COLLECTION) { 165 value = ValueUtils.getValue(handler.getProperty( 166 getBean(), 167 getPropertyName())); 168 } 169 else { 170 value = ValueUtils.getValue(handler.getProperty( 171 getBean(), 172 getPropertyName()), index); 173 } 174 return value; 175 } 176 177 181 protected boolean isActualProperty() { 182 return true; 183 } 184 185 190 public void setValue(Object value) { 191 if (index == WHOLE_COLLECTION) { 192 handler.setProperty(getBean(), getPropertyName(), value); 193 } 194 else { 195 ValueUtils.setValue( 196 handler.getProperty(getBean(), getPropertyName()), 197 index, 198 value); 199 } 200 } 201 202 public NodePointer createPath(JXPathContext context) { 203 Object collection = getBaseValue(); 205 if (collection == null) { 206 AbstractFactory factory = getAbstractFactory(context); 207 boolean success = 208 factory.createObject( 209 context, 210 this, 211 getBean(), 212 getPropertyName(), 213 0); 214 if (!success) { 215 throw new JXPathException( 216 "Factory could not create an object for path: " + asPath()); 217 } 218 collection = getBaseValue(); 219 } 220 221 if (index != WHOLE_COLLECTION) { 222 if (index < 0) { 223 throw new JXPathException("Index is less than 1: " + asPath()); 224 } 225 226 if (index >= getLength()) { 227 collection = ValueUtils.expandCollection(collection, index + 1); 228 handler.setProperty(getBean(), getPropertyName(), collection); 229 } 230 } 231 232 return this; 233 } 234 235 public NodePointer createPath(JXPathContext context, Object value) { 236 if (index == WHOLE_COLLECTION) { 237 handler.setProperty(getBean(), getPropertyName(), value); 238 } 239 else { 240 createPath(context); 241 ValueUtils.setValue(getBaseValue(), index, value); 242 } 243 return this; 244 } 245 246 public void remove() { 247 if (index == WHOLE_COLLECTION) { 248 removeKey(); 249 } 250 else if (isCollection()) { 251 Object collection = ValueUtils.remove(getBaseValue(), index); 252 handler.setProperty(getBean(), getPropertyName(), collection); 253 } 254 else if (index == 0) { 255 removeKey(); 256 } 257 } 258 259 private void removeKey() { 260 Object bean = getBean(); 261 if (bean instanceof Map ) { 262 ((Map ) bean).remove(getPropertyName()); 263 } 264 else { 265 handler.setProperty(bean, getPropertyName(), null); 266 } 267 } 268 269 public String asPath() { 270 StringBuffer buffer = new StringBuffer (); 271 buffer.append(getImmediateParentPointer().asPath()); 272 if (buffer.length() == 0) { 273 buffer.append("/."); 274 } 275 else if (buffer.charAt(buffer.length() - 1) == '/') { 276 buffer.append('.'); 277 } 278 buffer.append("[@name='"); 279 buffer.append(escape(getPropertyName())); 280 buffer.append("']"); 281 if (index != WHOLE_COLLECTION && isCollection()) { 282 buffer.append('[').append(index + 1).append(']'); 283 } 284 return buffer.toString(); 285 } 286 287 private String escape(String string) { 288 int index = string.indexOf('\''); 289 while (index != -1) { 290 string = 291 string.substring(0, index) 292 + "'" 293 + string.substring(index + 1); 294 index = string.indexOf('\''); 295 } 296 index = string.indexOf('\"'); 297 while (index != -1) { 298 string = 299 string.substring(0, index) 300 + """ 301 + string.substring(index + 1); 302 index = string.indexOf('\"'); 303 } 304 return string; 305 } 306 307 private AbstractFactory getAbstractFactory(JXPathContext context) { 308 AbstractFactory factory = context.getFactory(); 309 if (factory == null) { 310 throw new JXPathException( 311 "Factory is not set on the JXPathContext - cannot create path: " 312 + asPath()); 313 } 314 return factory; 315 } 316 } | Popular Tags |