1 17 18 package org.sape.carbon.core.config.format; 19 20 21 import java.beans.BeanInfo ; 22 import java.beans.IntrospectionException ; 23 import java.beans.Introspector ; 24 import java.beans.PropertyDescriptor ; 25 import java.io.InputStream ; 26 import java.io.OutputStream ; 27 import java.lang.reflect.Array ; 28 import java.lang.reflect.InvocationTargetException ; 29 import java.lang.reflect.Method ; 30 import java.lang.reflect.Proxy ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.Map ; 34 import java.util.Set ; 35 36 import org.jdom.Document; 37 38 import org.apache.commons.logging.Log; 39 import org.apache.commons.logging.LogFactory; 40 41 import org.sape.carbon.core.config.Config; 42 import org.sape.carbon.core.config.Configuration; 43 import org.sape.carbon.core.config.ConfigurationRuntimeException; 44 import org.sape.carbon.core.config.InvalidConfigurationException; 45 import org.sape.carbon.core.config.PropertyConfiguration; 46 import org.sape.carbon.core.config.format.jdom.JDOMConfigurationFactory; 47 import org.sape.carbon.core.config.format.jdom.JDOMConfigurationProxy; 48 import org.sape.carbon.core.config.format.jdom.JDOMPropertyConfiguration; 49 import org.sape.carbon.core.config.node.Node; 50 import org.sape.carbon.core.config.type.ConfigurationTypeService; 51 import org.sape.carbon.core.config.type.ConfigurationTypeServiceFactory; 52 import org.sape.carbon.core.exception.ExceptionUtility; 53 import org.sape.carbon.core.exception.InvalidParameterException; 54 import org.sape.carbon.core.util.string.StringUtil; 55 56 57 67 public class DefaultConfigurationFormatService 68 implements ConfigurationFormatService { 69 70 73 private Log log = 74 LogFactory.getLog(this.getClass()); 75 76 83 public Configuration newConfiguration(Class configurationClass) { 84 if (!Configuration.class.isAssignableFrom(configurationClass)) { 85 throw new org.sape.carbon.core.exception.InvalidParameterException( 86 this.getClass(), 87 "The supplied type [" 88 + configurationClass.getName() 89 + "] was not assignable from " 90 + Configuration.class.getName()); 91 } 92 93 if (configurationClass == PropertyConfiguration.class) { 94 return new JDOMPropertyConfiguration(); 95 96 } else { 97 JDOMConfigurationProxy proxy = 98 new JDOMConfigurationProxy(configurationClass); 99 100 Configuration config = 101 (Configuration) Proxy.newProxyInstance( 102 this.getClass().getClassLoader(), 103 new Class [] {configurationClass}, 104 proxy); 105 106 return config; 107 } 108 } 109 110 123 public Configuration readConfigurationStream(String name, InputStream in) 124 throws ConfigurationFormatException { 125 126 ConfigurationDataFormatService dataFormat = 127 new JDOMConfigurationFactory(); 128 129 Document dataNode = dataFormat.readConfigurationStreamToData(name, in); 130 131 String className = null; 132 Class configurationClass = null; 133 try { 134 className = 135 dataNode.getRootElement().getAttributeValue( 136 "ConfigurationInterface"); 137 138 if (className == null) { 139 throw new InvalidConfigurationException( 140 this.getClass(), 141 name, 142 "ConfigurationInterface", 143 "Document did not supply a valid ConfigurationInterface " 144 + "class name. All configuration documents must supply " 145 + "the Java interface which represents them."); 146 } else { 147 configurationClass = Class.forName(className); 148 } 149 } catch (ClassNotFoundException cnfe) { 150 throw new InvalidConfigurationException( 151 this.getClass(), 152 name, 153 "ConfigurationInterface", 154 "Document did not supply a valid ConfigurationInterface " 155 + "class name. The class [" 156 + className 157 + "] could not be found."); 158 } 159 160 Configuration config = null; 161 162 if (configurationClass.equals(PropertyConfiguration.class)) { 163 String extendedConfigurationName = 164 dataNode.getRootElement().getAttributeValue("Extends"); 165 166 if (extendedConfigurationName == null) { 167 config = new JDOMPropertyConfiguration(dataNode); 168 } else { 169 try { 170 PropertyConfiguration extendedConfiguration = 171 (PropertyConfiguration) Config 172 .getInstance() 173 .fetchConfiguration( 174 extendedConfigurationName); 175 176 config = 177 new JDOMPropertyConfiguration( 178 dataNode, 179 extendedConfiguration); 180 181 } catch (ConfigurationRuntimeException cre) { 182 throw new InvalidConfigurationException( 183 this.getClass(), 184 name, 185 "Extends", 186 "Could not reference parent configuration: [" 187 + extendedConfigurationName 188 + "]", 189 cre); 190 191 } catch (ClassCastException cce) { 192 throw new InvalidConfigurationException( 193 this.getClass(), 194 name, 195 "Extends", 196 "Parent was not assignable from " 197 + PropertyConfiguration.class.getClass(), 198 cce); 199 } 200 } 201 } else { 202 JDOMConfigurationProxy proxy = 203 new JDOMConfigurationProxy(dataNode, configurationClass); 204 205 if (log.isTraceEnabled()) { 206 log.trace("Instantiating new Configuration for document [" 207 + name + "] with class of [" 208 + configurationClass.getName() 209 + "]"); 210 } 211 try { 212 config = 213 (Configuration) Proxy.newProxyInstance( 214 this.getClass().getClassLoader(), 215 new Class [] {configurationClass}, 216 proxy); 217 } catch (ClassCastException cce) { 218 throw new InvalidConfigurationException( 219 this.getClass(), 220 name, 221 "ConfigurationInterface", 222 "Configuration class [" + 223 configurationClass.getName() + 224 "] was not assignable from [" + 225 Configuration.class.getName() + "]"); 226 } 227 } 228 config.setConfigurationName(name); 229 230 return config; 231 } 232 233 245 public void writeConfigurationStream( 246 Configuration configuration, 247 OutputStream out) 248 throws ConfigurationFormatException { 249 250 Document dataNode = configuration.getDataStructure(); 251 252 ConfigurationDataFormatService dataFormat = 253 new JDOMConfigurationFactory(); 254 255 dataFormat.writeConfigurationStreamToData(dataNode, out); 256 } 257 258 270 protected String constructIndexedName( 271 String parentName, 272 String name, 273 int index) { 274 275 if (name == null) { 276 throw new InvalidParameterException( 277 this.getClass(), "Name cannot be null"); 278 } 279 280 if (index < 0) { 281 throw new InvalidParameterException( 282 this.getClass(), "Index cannot be negative"); 283 } 284 285 StringBuffer indexedName = new StringBuffer (); 286 if (parentName != null) { 287 indexedName.append(parentName).append(Node.DELIMITER); 288 } 289 indexedName.append(name).append("[").append(index).append("]"); 290 return indexedName.toString(); 291 } 292 293 305 protected String constructMapName( 306 String parentName, 307 String name, 308 String key) { 309 310 if (name == null) { 311 throw new InvalidParameterException( 312 this.getClass(), "Name cannot be null"); 313 } 314 315 if (key == null) { 316 throw new InvalidParameterException( 317 this.getClass(), "Key must not be null."); 318 } 319 320 StringBuffer indexedName = new StringBuffer (); 321 if (parentName != null) { 322 indexedName.append(parentName).append(Node.DELIMITER); 323 } 324 indexedName.append(name).append("[").append(key).append("]"); 325 return indexedName.toString(); 326 } 327 328 329 332 public Configuration getChildConfiguration( 333 Configuration parentConfig, 334 String childName) { 335 336 if (parentConfig == null) { 337 throw new InvalidParameterException( 338 this.getClass(), 339 "parentConfig cannot be null"); 340 } 341 342 if (childName == null) { 343 throw new InvalidParameterException( 344 this.getClass(), 345 "childName cannot be null"); 346 } 347 348 if (!Proxy.isProxyClass(parentConfig.getClass())) { 349 return null; 350 } 351 352 AbstractConfigurationProxy configProxy = 353 (AbstractConfigurationProxy) Proxy.getInvocationHandler( 354 parentConfig); 355 356 357 358 if (childName.endsWith("]")) { 359 362 int rightBracketIndex = childName.lastIndexOf("["); 363 String elementName = childName.substring(0, rightBracketIndex); 364 String key = 365 childName.substring( 366 rightBracketIndex + 1, 367 childName.length() - 1); 368 369 Class childType = configProxy.getChildType(elementName); 370 if (Map .class.isAssignableFrom(childType)) { 371 Map map = 372 configProxy.getMap(elementName, 373 configProxy.getCollectionComponentType(elementName)); 374 return (Configuration) map.get(key); 375 } else if (childType.isArray()) { 376 int index = 377 Integer.parseInt(key); 378 379 Object array = 380 configProxy.getArray( 381 elementName, Configuration.class); 382 383 return (Configuration) Array.get(array, index); 384 } else { 385 throw new InvalidParameterException( 386 this.getClass(), "Unknown child type."); 387 } 388 } else { 389 return (Configuration) configProxy.lookupAttribute( 392 childName, 393 Configuration.class); 394 } 395 } 396 397 408 public Set getChildConfigurationNames(Configuration parentConfig) { 409 if (parentConfig == null) { 410 throw new InvalidParameterException( 411 this.getClass(), 412 "parentConfig cannot be null"); 413 } 414 415 final ConfigurationTypeService typeService = 416 ConfigurationTypeServiceFactory.getInstance(); 417 Class configType = parentConfig.getConfigurationInterface(); 418 Set childConfigurationNames = new HashSet (); 419 420 BeanInfo configBeanInfo = null; 421 try { 422 configBeanInfo = Introspector.getBeanInfo(configType); 423 } catch (IntrospectionException ie) { 424 log.info("Could not introspect confgiuration [" 425 + parentConfig.getConfigurationName() 426 + "], with config interface [" 427 + configType.getName() 428 + "], no children will be listed: cause: " 429 + ExceptionUtility.printStackTracesToString(ie)); 430 431 return childConfigurationNames; 432 } 433 434 PropertyDescriptor [] properties = 435 configBeanInfo.getPropertyDescriptors(); 436 437 for (int i = 0; i < properties.length; i++) { 438 PropertyDescriptor property = properties[i]; 439 Class returnType = property.getPropertyType(); 440 String attributeName = StringUtil.capitalize(property.getName()); 441 442 try { 443 Object attributeValue = 444 property.getReadMethod().invoke(parentConfig, null); 445 446 if (returnType == Map .class) { 447 Class contentType = 448 getContentType(parentConfig.getClass(), attributeName); 449 450 if (contentType != null && 451 (typeService.isComplexType(contentType) || 452 Configuration.class.isAssignableFrom(contentType))) { 453 454 Map attributeMap = (Map ) attributeValue; 455 Set keySet = attributeMap.keySet(); 456 for (Iterator keyIter = keySet.iterator(); 457 keyIter.hasNext(); 458 ) { 459 460 String key = (String ) keyIter.next(); 461 childConfigurationNames.add( 462 constructMapName(null, attributeName, key)); 463 } 464 } 465 466 } else if (returnType.isArray()) { 467 Class contentType = 468 attributeValue.getClass().getComponentType(); 469 470 if (typeService.isComplexType(contentType) 471 || Configuration.class.isAssignableFrom(contentType)) { 472 473 int arrayLength = Array.getLength(attributeValue); 474 for (int count = 0; count < arrayLength; count++) { 475 childConfigurationNames.add( 476 constructIndexedName( 477 null, attributeName, count)); 478 } 479 } 480 481 } else if (attributeValue != null 482 && (typeService.isComplexType(returnType) 483 || Configuration.class.isAssignableFrom(returnType))) { 484 485 childConfigurationNames.add(attributeName); 486 } 487 488 } catch (IllegalAccessException iae) { 489 log.info("Could not read attribute [" 490 + attributeName 491 + "] from confgiuration [" 492 + parentConfig.getConfigurationName() 493 + "], attribute will not be listed as a " 494 + "child configuration: cause: " 495 + ExceptionUtility.printStackTracesToString(iae)); 496 497 } catch (IllegalArgumentException iae) { 498 log.info("Could not read attribute [" 499 + attributeName 500 + "] from confgiuration [" 501 + parentConfig.getConfigurationName() 502 + "], attribute will not be listed as a " 503 + "child configuration: cause: " 504 + ExceptionUtility.printStackTracesToString(iae)); 505 506 } catch (InvocationTargetException ite) { 507 log.info("Could not read attribute [" 508 + attributeName 509 + "] from confgiuration [" 510 + parentConfig.getConfigurationName() 511 + "], attribute will not be listed as a " 512 + "child configuration: cause: " 513 + ExceptionUtility.printStackTracesToString( 514 ite.getTargetException())); 515 } 516 } 517 518 return childConfigurationNames; 519 } 520 521 525 public void alterChildConfiguration( 526 Configuration parentConfig, 527 String childName, 528 Configuration newConfig) { 529 530 if (parentConfig == null) { 531 throw new InvalidParameterException( 532 this.getClass(), 533 "parentConfig cannot be null"); 534 } 535 536 if (childName == null) { 537 throw new InvalidParameterException( 538 this.getClass(), 539 "childName cannot be null"); 540 } 541 542 if (!Proxy.isProxyClass(parentConfig.getClass())) { 543 return; 544 } 545 546 AbstractConfigurationProxy configProxy = 547 (AbstractConfigurationProxy) Proxy.getInvocationHandler( 548 parentConfig); 549 550 Class configurationInterface = Configuration.class; 551 if (newConfig != null) { 552 configurationInterface = newConfig.getConfigurationInterface(); 553 } 554 555 if (childName.endsWith("]")) { 556 int rightBracketIndex = childName.lastIndexOf("["); 558 String elementName = childName.substring(0, rightBracketIndex); 559 String key = 560 childName.substring( 561 rightBracketIndex + 1, 562 childName.length() - 1); 563 564 Class childType = configProxy.getChildType(elementName); 565 if (Map .class.isAssignableFrom(childType)) { 566 Class childComponentType = 567 configProxy.getCollectionComponentType(elementName); 568 configProxy.setMapValue( 569 elementName, 570 childComponentType, 571 key, 572 newConfig); 573 574 } else if (childType.isArray()) { 575 int index = Integer.parseInt(key); 576 577 configProxy.setArrayValue( 579 elementName, 580 configurationInterface, 581 index, 582 newConfig); 583 } else { 584 throw new InvalidParameterException( 585 this.getClass(), 586 "Unknown component type"); 587 } 588 589 } else { 590 configProxy.alterAttribute( 592 childName, 593 configurationInterface, 594 newConfig); 595 } 596 } 597 598 606 private Class getContentType(Class configurationType, String attrName) { 607 Class componentType = null; 608 609 try { 610 Method readMethod = configurationType.getMethod( 611 "get" + attrName, new Class [] { String .class }); 612 613 componentType = readMethod.getReturnType(); 614 } catch (NoSuchMethodException e) { 615 } 617 618 return componentType; 619 } 620 } 621 | Popular Tags |