001package org.apache.fulcrum.yaafi.framework.factory; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.IOException; 024import java.io.InputStream; 025import java.util.Enumeration; 026import java.util.Hashtable; 027 028import org.apache.avalon.framework.configuration.Configuration; 029import org.apache.avalon.framework.configuration.DefaultConfiguration; 030import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder; 031import org.apache.avalon.framework.context.Context; 032import org.apache.avalon.framework.context.DefaultContext; 033import org.apache.avalon.framework.logger.ConsoleLogger; 034import org.apache.avalon.framework.logger.Logger; 035import org.apache.avalon.framework.service.ServiceManager; 036import org.apache.commons.lang3.StringUtils; 037import org.apache.fulcrum.yaafi.framework.constant.AvalonMerlinConstants; 038import org.apache.fulcrum.yaafi.framework.container.ServiceConstants; 039import org.apache.fulcrum.yaafi.framework.crypto.CryptoStreamFactory; 040import org.apache.fulcrum.yaafi.framework.util.InputStreamLocator; 041import org.apache.fulcrum.yaafi.framework.util.Validate; 042 043/** 044 * Helper class to capture configuration related stuff. The are two ways for 045 * setting up the configuration: 046 * <ul> 047 * <li>set all parameters manually</li> 048 * <li>use a containerConfiguration file and provide the remaining settings</li> 049 * </ul> 050 * 051 * The Avalon context and configuration are created by 052 * <ul> 053 * <li>createFinalContext()</li> 054 * <li>createFinalConfiguration()</li> 055 * </ul> 056 * 057 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a> 058 */ 059 060public class ServiceContainerConfiguration { 061 /** our default implementation class of the service container */ 062 private String serviceContainerClazzName; 063 064 /** the location of the component role file */ 065 private String componentRolesLocation; 066 067 /** is the component role file encrypted? */ 068 private String isComponentRolesEncrypted; 069 070 /** the location of the component configuration file */ 071 private String componentConfigurationLocation; 072 073 /** is the component configuration file encrypted? */ 074 private String isComponentConfigurationEncrypted; 075 076 /** the location of the paramaters file */ 077 private String parametersLocation; 078 079 /** is the parameters file encrypted? */ 080 private String isParametersEncrypted; 081 082 /** the user-supplied Avalon context */ 083 private DefaultContext context; 084 085 /** the Avalon logger */ 086 private Logger logger; 087 088 /** the application directory */ 089 private String applicationRootDir; 090 091 /** the temporary directory */ 092 private String tempRootDir; 093 094 /** the class loader passed in the Avalon Context */ 095 private ClassLoader componentClassLoader; 096 097 /** the type of container where YAAFI is embedded */ 098 private String containerFlavour; 099 100 /** the caller-supplied container configuration */ 101 private Configuration containerConfiguration; 102 103 /** to lookup service in the parent container */ 104 private ServiceManager parentServiceManager; 105 106 /** a list of ServiceManager maintaining their own services */ 107 private String[] serviceManagerList; 108 109 /** Constructor */ 110 public ServiceContainerConfiguration() { 111 this(ConsoleLogger.LEVEL_DEBUG); 112 } 113 114 /** 115 * Constructor. 116 * 117 * @param logLevel the log level for the console logger. 118 */ 119 public ServiceContainerConfiguration(int logLevel) { 120 this.logger = new ConsoleLogger(logLevel); 121 this.containerFlavour = ServiceConstants.AVALON_CONTAINER_YAAFI; 122 this.serviceContainerClazzName = ServiceConstants.CLAZZ_NAME; 123 this.componentRolesLocation = ServiceConstants.COMPONENT_ROLE_VALUE; 124 this.isComponentRolesEncrypted = "false"; 125 this.componentConfigurationLocation = ServiceConstants.COMPONENT_CONFIG_VALUE; 126 this.isComponentConfigurationEncrypted = "false"; 127 this.parametersLocation = ServiceConstants.COMPONENT_PARAMETERS_VALUE; 128 this.isParametersEncrypted = "false"; 129 this.context = new DefaultContext(); 130 this.applicationRootDir = new File("").getAbsolutePath(); 131 this.tempRootDir = System.getProperty("java.io.tmpdir", "."); 132 this.componentClassLoader = this.getClass().getClassLoader(); 133 } 134 135 /** 136 * Add a new entry to the context by creating a new one. 137 * 138 * @param name the name of the new entry 139 * @param value the value of the new entry 140 */ 141 public void addToContext(String name, Object value) { 142 Validate.notEmpty(name, "name"); 143 Validate.notNull(value, "value"); 144 this.getContext().put(name, value); 145 } 146 147 /** 148 * Add a hashtable to the context 149 * 150 * @param hashtable the Hashtable to be added 151 */ 152 public void addToContext(Hashtable<?, ?> hashtable) { 153 Validate.notNull(hashtable, "hashtable"); 154 155 String name = null; 156 Object value = null; 157 Enumeration<?> keys = hashtable.keys(); 158 159 while (keys.hasMoreElements()) { 160 name = (String) keys.nextElement(); 161 value = hashtable.get(name); 162 this.addToContext(name, value); 163 } 164 } 165 166 /** 167 * Create the final Avalon context passed to YAAFI containing 168 * <ul> 169 * <li>user-supplied context</li> 170 * <li>urn:avalon:home</li> 171 * <li>urn:avalon:temp</li> 172 * <li>urn:avalon:name</li> 173 * <li>urn:avalon:partition</li> 174 * <li>urn:avalon:classloader</li> 175 * </ul> 176 * 177 * @return the final Context 178 * @throws Exception if filename not defined 179 * @throws IOException if file not found 180 */ 181 182 public Context createFinalContext() throws IOException, Exception { 183 // 1) add the application root dir 184 185 this.addToContext(AvalonMerlinConstants.URN_AVALON_HOME, this.getApplicationRootDir()); 186 187 // 2) add the temp root dir 188 189 this.addToContext(AvalonMerlinConstants.URN_AVALON_TEMP, this.getTempRootDir()); 190 191 // 3) add the Avalon name 192 193 this.addToContext(AvalonMerlinConstants.URN_AVALON_NAME, ServiceConstants.ROLE_NAME); 194 195 // 4) add the Avalon partition name 196 197 this.addToContext(AvalonMerlinConstants.URN_AVALON_PARTITION, "root"); 198 199 // 5) add the class loader 200 201 this.addToContext(AvalonMerlinConstants.URN_AVALON_CLASSLOADER, this.getComponentClassLoader()); 202 203 return this.getContext(); 204 } 205 206 /** 207 * Create a final configuration. 208 * 209 * @return the configuration 210 */ 211 public Configuration createFinalConfiguration() { 212 DefaultConfiguration result = null; 213 214 if (this.getContainerConfiguration() != null) { 215 return this.getContainerConfiguration(); 216 } else { 217 // the root element is "fulcrum-yaafi" 218 219 result = new DefaultConfiguration(ServiceConstants.ROLE_NAME); 220 221 // add the following fragement 222 // 223 // <containerFlavour>merlin</containerFlavour> 224 225 DefaultConfiguration containerFlavourConfig = new DefaultConfiguration( 226 ServiceConstants.CONTAINERFLAVOUR_CONFIG_KEY); 227 228 containerFlavourConfig.setValue(this.getContainerFlavour()); 229 230 result.addChild(containerFlavourConfig); 231 232 // add the following fragement 233 // 234 // <containerClazzName>...</containerClazzName> 235 236 DefaultConfiguration containerClazzNameConfig = new DefaultConfiguration( 237 ServiceConstants.CONTAINERCLAZZNAME_CONFIG_KEY); 238 239 containerClazzNameConfig.setValue(this.getServiceContainerClazzName()); 240 241 result.addChild(containerClazzNameConfig); 242 243 // add the following fragement 244 // 245 // <componentRoles> 246 // <location>../conf/componentRoles.xml</location> 247 // <isEncrypted>true</isEncrypted> 248 // </componentRoles> 249 250 DefaultConfiguration componentRolesConfig = new DefaultConfiguration(ServiceConstants.COMPONENT_ROLE_KEYS); 251 252 DefaultConfiguration componentRolesLocation = new DefaultConfiguration( 253 ServiceConstants.COMPONENT_LOCATION_KEY); 254 255 componentRolesLocation.setValue(this.getComponentRolesLocation()); 256 257 DefaultConfiguration componentRolesIsEncrypted = new DefaultConfiguration( 258 ServiceConstants.COMPONENT_ISENCRYPTED_KEY); 259 260 componentRolesIsEncrypted.setValue(this.isComponentRolesEncrypted()); 261 262 componentRolesConfig.addChild(componentRolesLocation); 263 componentRolesConfig.addChild(componentRolesIsEncrypted); 264 265 result.addChild(componentRolesConfig); 266 267 // add the following fragement 268 // 269 // <componentConfiguration> 270 // <location>../conf/componentRoles.xml</location> 271 // <isEncrypted>true</isEncrypted> 272 // </componentConfiguration> 273 274 DefaultConfiguration componentConfigurationConfig = new DefaultConfiguration( 275 ServiceConstants.COMPONENT_CONFIG_KEY); 276 277 DefaultConfiguration componentConfigurationLocation = new DefaultConfiguration( 278 ServiceConstants.COMPONENT_LOCATION_KEY); 279 280 componentConfigurationLocation.setValue(this.getComponentConfigurationLocation()); 281 282 DefaultConfiguration componentConfigurationIsEncrypted = new DefaultConfiguration( 283 ServiceConstants.COMPONENT_ISENCRYPTED_KEY); 284 285 componentConfigurationIsEncrypted.setValue(this.isComponentConfigurationEncrypted()); 286 287 componentConfigurationConfig.addChild(componentConfigurationLocation); 288 componentConfigurationConfig.addChild(componentConfigurationIsEncrypted); 289 290 result.addChild(componentConfigurationConfig); 291 292 // Add the following fragement 293 // 294 // <parameters> 295 // <location>../conf/parameters.properties</location> 296 // <isEncrypted>true</isEncrypted> 297 // </parameters> 298 299 DefaultConfiguration parameterConfigurationConfig = new DefaultConfiguration( 300 ServiceConstants.COMPONENT_PARAMETERS_KEY); 301 302 DefaultConfiguration parameterConfigurationLocation = new DefaultConfiguration( 303 ServiceConstants.COMPONENT_LOCATION_KEY); 304 305 parameterConfigurationLocation.setValue(this.getParametersLocation()); 306 307 DefaultConfiguration parameterConfigurationIsEncrypted = new DefaultConfiguration( 308 ServiceConstants.COMPONENT_ISENCRYPTED_KEY); 309 310 parameterConfigurationIsEncrypted.setValue(this.isParametersEncrypted()); 311 312 parameterConfigurationConfig.addChild(parameterConfigurationLocation); 313 parameterConfigurationConfig.addChild(parameterConfigurationIsEncrypted); 314 315 result.addChild(parameterConfigurationConfig); 316 317 // Add the following fragement 318 // 319 // <serviceManagers> 320 // <serviceManagers>springFrameworkService</serviceManager> 321 // </serviceManagers> 322 323 if (this.hasServiceManagerList()) { 324 DefaultConfiguration serviceManagerListConfig = new DefaultConfiguration( 325 ServiceConstants.SERVICEMANAGER_LIST_KEY); 326 327 for (int i = 0; i < this.serviceManagerList.length; i++) { 328 DefaultConfiguration serviceManagerConfig = new DefaultConfiguration( 329 ServiceConstants.SERVICEMANAGER_KEY); 330 331 serviceManagerConfig.setValue(this.serviceManagerList[i]); 332 333 serviceManagerListConfig.addChild(serviceManagerConfig); 334 } 335 336 result.addChild(serviceManagerListConfig); 337 } 338 339 return result; 340 } 341 } 342 343 ///////////////////////////////////////////////////////////////////////// 344 // Generated Getters/Setters 345 ///////////////////////////////////////////////////////////////////////// 346 347 /** 348 * @return Returns the serviceContainerClazzName. 349 */ 350 private String getServiceContainerClazzName() { 351 return this.serviceContainerClazzName; 352 } 353 354 /** 355 * @return Returns the componentConfigurationLocation. 356 */ 357 private String getComponentConfigurationLocation() { 358 return componentConfigurationLocation; 359 } 360 361 /** 362 * @param componentConfigurationLocation The componentConfigurationLocation to 363 * set. 364 */ 365 public void setComponentConfigurationLocation(String componentConfigurationLocation) { 366 Validate.notNull(componentConfigurationLocation, "componentConfigurationLocation"); 367 this.componentConfigurationLocation = componentConfigurationLocation; 368 } 369 370 /** 371 * @return Returns the componentRolesLocation. 372 */ 373 private String getComponentRolesLocation() { 374 return componentRolesLocation; 375 } 376 377 /** 378 * @param componentRolesLocation The componentRolesLocation to set. 379 */ 380 public void setComponentRolesLocation(String componentRolesLocation) { 381 this.componentRolesLocation = componentRolesLocation; 382 } 383 384 /** 385 * @return Returns the context. 386 */ 387 private DefaultContext getContext() { 388 return context; 389 } 390 391 /** 392 * @param context The context to set. 393 */ 394 public void setContext(Context context) { 395 if (context instanceof DefaultContext) { 396 this.context = (DefaultContext) context; 397 } else { 398 this.context = new DefaultContext(context); 399 } 400 } 401 402 /** 403 * @return Returns the isComponentConfigurationEncrypted. 404 */ 405 private String isComponentConfigurationEncrypted() { 406 return isComponentConfigurationEncrypted; 407 } 408 409 /** 410 * @param isComponentConfigurationEncrypted The 411 * isComponentConfigurationEncrypted to 412 * set. 413 */ 414 public void setComponentConfigurationEncrypted(String isComponentConfigurationEncrypted) { 415 this.isComponentConfigurationEncrypted = isComponentConfigurationEncrypted; 416 } 417 418 /** 419 * @return Returns the isComponentRolesEncrypted. 420 */ 421 private String isComponentRolesEncrypted() { 422 return isComponentRolesEncrypted; 423 } 424 425 /** 426 * @param isComponentRolesEncrypted The isComponentRolesEncrypted to set. 427 */ 428 public void setComponentRolesEncrypted(String isComponentRolesEncrypted) { 429 this.isComponentRolesEncrypted = isComponentRolesEncrypted; 430 } 431 432 /** 433 * @return Returns the isParametersEncrypted. 434 */ 435 private String isParametersEncrypted() { 436 return isParametersEncrypted; 437 } 438 439 /** 440 * @param isParametersEncrypted The isParametersEncrypted to set. 441 */ 442 public void setParametersEncrypted(String isParametersEncrypted) { 443 Validate.notEmpty(isParametersEncrypted, "isParametersEncrypted"); 444 this.isParametersEncrypted = isParametersEncrypted; 445 } 446 447 /** 448 * @return Returns the logger. 449 */ 450 public Logger getLogger() { 451 return logger; 452 } 453 454 /** 455 * @param logger The logger to set. 456 */ 457 public void setLogger(Logger logger) { 458 this.logger = logger; 459 } 460 461 /** 462 * @return Returns the parametersLocation. 463 */ 464 private String getParametersLocation() { 465 return parametersLocation; 466 } 467 468 /** 469 * @param parametersLocation The parametersLocation to set. 470 */ 471 public void setParametersLocation(String parametersLocation) { 472 this.parametersLocation = parametersLocation; 473 } 474 475 /** 476 * @return Returns the applicationRootDir. 477 */ 478 private File getApplicationRootDir() { 479 return new File(applicationRootDir); 480 } 481 482 /** 483 * @param applicationRootDir The applicationRootDir to set. 484 */ 485 public void setApplicationRootDir(String applicationRootDir) { 486 Validate.notNull(applicationRootDir, "applicationRootDir"); 487 488 if (applicationRootDir.equals(".")) { 489 this.applicationRootDir = new File("").getAbsolutePath(); 490 } else { 491 this.applicationRootDir = new File(applicationRootDir).getAbsolutePath(); 492 } 493 } 494 495 /** 496 * @return Returns the tempRootDir. 497 * @throws Exception 498 * @throws IOException 499 */ 500 private File getTempRootDir() throws IOException, Exception { 501 return makeAbsoluteFile(this.getApplicationRootDir(), this.tempRootDir); 502 } 503 504 /** 505 * @param tempRootDir The tempRootDir to set. 506 */ 507 public void setTempRootDir(String tempRootDir) { 508 Validate.notNull(tempRootDir, "tempRootDir"); 509 this.tempRootDir = tempRootDir; 510 } 511 512 /** 513 * @return Returns the classLoader. 514 */ 515 private ClassLoader getComponentClassLoader() { 516 return componentClassLoader; 517 } 518 519 /** 520 * @param componentClassLoader The classLoader to set. 521 */ 522 public void setComponentClassLoader(ClassLoader componentClassLoader) { 523 Validate.notNull(componentClassLoader, "componentClassLoader"); 524 this.componentClassLoader = componentClassLoader; 525 } 526 527 /** 528 * @return Returns the containerFlavour. 529 */ 530 private String getContainerFlavour() { 531 return containerFlavour; 532 } 533 534 /** 535 * @param containerFlavour The containerFlavour to set. 536 */ 537 public void setContainerFlavour(String containerFlavour) { 538 this.containerFlavour = containerFlavour; 539 } 540 541 /** 542 * @return Returns the containerConfiguration. 543 */ 544 private Configuration getContainerConfiguration() { 545 return containerConfiguration; 546 } 547 548 /** 549 * @param containerConfiguration The containerConfiguration to set. 550 */ 551 public void setContainerConfiguration(Configuration containerConfiguration) { 552 this.containerConfiguration = containerConfiguration; 553 } 554 555 /** 556 * Get the parent service manager to find service managed by the parent 557 * container. 558 * 559 * @return the parent container 560 */ 561 562 public ServiceManager getParentServiceManager() { 563 return parentServiceManager; 564 } 565 566 /** 567 * Set the parent service manager to find service managed by the parent 568 * container. 569 * 570 * @param parentServiceManager the parent container 571 */ 572 public void setParentServiceManager(ServiceManager parentServiceManager) { 573 this.parentServiceManager = parentServiceManager; 574 } 575 576 /** 577 * Get a list of service manager managing their own set of services. 578 * 579 * @return a list of service implementing the ServiceManager interface 580 */ 581 public String[] getServiceManagerList() { 582 return serviceManagerList; 583 } 584 585 /** 586 * Set a list of service manager managing their own set of services. 587 * 588 * @param serviceManagerList a list of service implementing the ServiceManager 589 * interface 590 */ 591 public void setServiceManagerList(String[] serviceManagerList) { 592 this.serviceManagerList = serviceManagerList; 593 } 594 595 /** 596 * @return true if there is a service manager defined 597 */ 598 public boolean hasServiceManagerList() { 599 if (this.serviceManagerList != null && this.serviceManagerList.length > 0) 600 return true; 601 return false; 602 } 603 604 /** 605 * Loads a containerConfiguration file and set is as the Avalon configuration to 606 * be used for Configurable.configure(). Take care that the implementation uses 607 * an InputStreamLocator to find the containerConfiguration which uses the 608 * previously set application root directory. 609 * 610 * @param location the location of the containerConfiguration 611 * @throws IOException loading the configuration failed 612 */ 613 public void loadContainerConfiguration(String location) throws IOException { 614 this.loadContainerConfiguration(location, "false"); 615 } 616 617 /** 618 * Loads a containerConfiguration file and set is as the Avalon configuration to 619 * be used for Configurable.configure(). Take care that the implementation uses 620 * an InputStreamLocator to find the containerConfiguration which uses the 621 * previously set application root directory. 622 * 623 * @param location the location of the containerConfiguration 624 * @param isEncrypted is the file encrypted 625 * @throws IOException loading the configuration failed 626 */ 627 public void loadContainerConfiguration(String location, String isEncrypted) throws IOException { 628 Configuration result = null; 629 630 InputStreamLocator locator = new InputStreamLocator(this.getApplicationRootDir(), this.getLogger()); 631 632 DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); 633 InputStream is = locator.locate(location); 634 635 if (is != null) { 636 try { 637 is = CryptoStreamFactory.getDecryptingInputStream(is, isEncrypted); 638 result = builder.build(is); 639 this.setContainerConfiguration(result); 640 } catch (Exception e) { 641 String msg = "Unable to parse the following file : " + location; 642 this.getLogger().error(msg, e); 643 throw new IOException(msg); 644 } 645 } else { 646 String msg = "Unable to locate the containerConfiguration file : " + location; 647 this.getLogger().error(msg); 648 throw new IOException(msg); 649 } 650 } 651 652 /** 653 * Determines the absolute file. 654 * 655 * @param baseDir the base directory 656 * @param fileName the filename 657 * @return the absolute path 658 */ 659 private static File makeAbsoluteFile(File baseDir, String fileName) throws IOException, Exception { 660 if (baseDir.exists()) { 661 if (!StringUtils.isEmpty(fileName)) { 662 File result = new File(fileName); 663 if (!result.isAbsolute()) { 664 result = new File(baseDir, fileName); 665 } 666 return result; 667 } else { 668 throw new Exception("No filename specified"); 669 } 670 } else { 671 throw new IOException("The directory does not exist"); 672 } 673 } 674}