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.geronimo.system.configuration; 018 019 import java.io.BufferedInputStream; 020 import java.io.BufferedOutputStream; 021 import java.io.File; 022 import java.io.FileInputStream; 023 import java.io.FileNotFoundException; 024 import java.io.FileOutputStream; 025 import java.io.IOException; 026 import java.io.InputStream; 027 import java.io.OutputStream; 028 import java.util.ArrayList; 029 import java.util.Collection; 030 import java.util.HashMap; 031 import java.util.Iterator; 032 import java.util.List; 033 import java.util.Map; 034 import java.util.Properties; 035 import java.util.Timer; 036 import java.util.TimerTask; 037 038 import javax.xml.parsers.DocumentBuilder; 039 import javax.xml.parsers.DocumentBuilderFactory; 040 import javax.xml.parsers.ParserConfigurationException; 041 import javax.xml.transform.OutputKeys; 042 import javax.xml.transform.Transformer; 043 import javax.xml.transform.TransformerException; 044 import javax.xml.transform.TransformerFactory; 045 import javax.xml.transform.dom.DOMSource; 046 import javax.xml.transform.stream.StreamResult; 047 048 import org.apache.commons.logging.Log; 049 import org.apache.commons.logging.LogFactory; 050 import org.apache.geronimo.gbean.AbstractName; 051 import org.apache.geronimo.gbean.GAttributeInfo; 052 import org.apache.geronimo.gbean.GBeanData; 053 import org.apache.geronimo.gbean.GBeanInfo; 054 import org.apache.geronimo.gbean.GBeanInfoBuilder; 055 import org.apache.geronimo.gbean.GBeanLifecycle; 056 import org.apache.geronimo.gbean.GReferenceInfo; 057 import org.apache.geronimo.gbean.ReferencePatterns; 058 import org.apache.geronimo.kernel.InvalidGBeanException; 059 import org.apache.geronimo.kernel.config.Configuration; 060 import org.apache.geronimo.kernel.config.InvalidConfigException; 061 import org.apache.geronimo.kernel.config.ManageableAttributeStore; 062 import org.apache.geronimo.kernel.config.PersistentConfigurationList; 063 import org.apache.geronimo.kernel.repository.Artifact; 064 import org.apache.geronimo.kernel.util.XmlUtil; 065 import org.apache.geronimo.system.configuration.condition.JexlExpressionParser; 066 import org.apache.geronimo.system.serverinfo.ServerInfo; 067 import org.w3c.dom.Document; 068 import org.w3c.dom.Element; 069 import org.xml.sax.ErrorHandler; 070 import org.xml.sax.InputSource; 071 import org.xml.sax.SAXException; 072 import org.xml.sax.SAXParseException; 073 074 /** 075 * Stores managed attributes in an XML file on the local filesystem. 076 * 077 * @version $Rev: 560020 $ $Date: 2007-07-26 18:28:15 -0400 (Thu, 26 Jul 2007) $ 078 */ 079 public class LocalAttributeManager implements PluginAttributeStore, PersistentConfigurationList, GBeanLifecycle { 080 private static final Log log = LogFactory.getLog(LocalAttributeManager.class); 081 082 private static final String CONFIG_FILE_PROPERTY = "org.apache.geronimo.config.file"; 083 private final static String SUBSTITUTIONS_FILE_PROPERTY = "org.apache.geronimo.config.substitutions.file"; 084 private final static String SUBSTITUTION_PREFIX_PREFIX = "org.apache.geronimo.config.substitution.prefix"; 085 086 private static final String BACKUP_EXTENSION = ".bak"; 087 private static final String TEMP_EXTENSION = ".working"; 088 private static final int SAVE_BUFFER_MS = 5000; 089 090 private final ServerInfo serverInfo; 091 private final String configFile; 092 private final boolean readOnly; 093 private final JexlExpressionParser expressionParser; 094 095 private File attributeFile; 096 private File backupFile; 097 private File tempFile; 098 private ServerOverride serverOverride; 099 100 private Timer timer; 101 private TimerTask currentTask; 102 103 private boolean kernelFullyStarted; 104 105 public LocalAttributeManager(String configFile, String configSubstitutionsFile, String configSubstitutionsPrefix, boolean readOnly, ServerInfo serverInfo) { 106 this.configFile = System.getProperty(CONFIG_FILE_PROPERTY, configFile); 107 String resolvedPropertiesFile = System.getProperty(SUBSTITUTIONS_FILE_PROPERTY, configSubstitutionsFile); 108 String prefix = System.getProperty(SUBSTITUTION_PREFIX_PREFIX, configSubstitutionsPrefix); 109 expressionParser = loadProperties(resolvedPropertiesFile, serverInfo, prefix); 110 this.readOnly = readOnly; 111 this.serverInfo = serverInfo; 112 serverOverride = new ServerOverride(); 113 log.debug("setting configSubstitutionsFile to " + configSubstitutionsFile + "."); 114 } 115 116 public boolean isReadOnly() { 117 return readOnly; 118 } 119 120 public synchronized Collection applyOverrides(Artifact configName, Collection untypedGbeanDatas, ClassLoader classLoader) throws InvalidConfigException { 121 // clone the datas since we will be modifying this collection 122 Collection<GBeanData> gbeanDatas = new ArrayList<GBeanData>(untypedGbeanDatas); 123 124 ConfigurationOverride configuration = serverOverride.getConfiguration(configName); 125 if (configuration == null) { 126 return gbeanDatas; 127 } 128 129 // index the incoming datas 130 Map<Object, GBeanData> datasByName = new HashMap<Object, GBeanData>(); 131 for (GBeanData gbeanData : gbeanDatas) { 132 datasByName.put(gbeanData.getAbstractName(), gbeanData); 133 datasByName.put(gbeanData.getAbstractName().getName().get("name"), gbeanData); 134 } 135 136 // add the new GBeans 137 for (Object o : configuration.getGBeans().entrySet()) { 138 Map.Entry entry = (Map.Entry) o; 139 Object name = entry.getKey(); 140 GBeanOverride gbean = (GBeanOverride) entry.getValue(); 141 if (!datasByName.containsKey(name) && gbean.isLoad()) { 142 if (gbean.getGBeanInfo() == null || !(name instanceof AbstractName)) { 143 String sep = ""; 144 StringBuffer message = new StringBuffer("New GBeans must be specified with "); 145 if (gbean.getGBeanInfo() == null) { 146 message.append("a GBeanInfo "); 147 sep = "and "; 148 } 149 if (!(name instanceof AbstractName)) { 150 message.append(sep).append("a full AbstractName "); 151 } 152 message.append("configuration=").append(configName); 153 message.append(" gbeanName=").append(name); 154 throw new InvalidConfigException(message.toString()); 155 } 156 GBeanInfo gbeanInfo = GBeanInfo.getGBeanInfo(gbean.getGBeanInfo(), classLoader); 157 AbstractName abstractName = (AbstractName) name; 158 GBeanData gBeanData = new GBeanData(abstractName, gbeanInfo); 159 gbeanDatas.add(gBeanData); 160 } 161 } 162 163 // set the attributes 164 for (Iterator iterator = gbeanDatas.iterator(); iterator.hasNext();) { 165 GBeanData data = (GBeanData) iterator.next(); 166 boolean load = setAttributes(data, configuration, configName, classLoader); 167 if (!load) { 168 iterator.remove(); 169 } 170 } 171 return gbeanDatas; 172 } 173 174 /** 175 * Set the attributes from the attribute store on a single gbean, and return whether or not to load the gbean. 176 * 177 * @param data GBeanData we are going to override attributes on 178 * @param configuration the module override the gbean relates to 179 * @param configName name of the module (why can't this be determined from the configuration?) 180 * @param classLoader ClassLoader to use for property objects/PropertyEditors 181 * @return true if the gbean should be loaded, false otherwise. 182 * @throws org.apache.geronimo.kernel.config.InvalidConfigException if we cannot update the gbeanData 183 * 184 */ 185 private synchronized boolean setAttributes(GBeanData data, ConfigurationOverride configuration, Artifact configName, ClassLoader classLoader) throws InvalidConfigException { 186 AbstractName gbeanName = data.getAbstractName(); 187 GBeanOverride gbean = configuration.getGBean(gbeanName); 188 if (gbean == null) { 189 gbean = configuration.getGBean((String) gbeanName.getName().get("name")); 190 } 191 192 if (gbean == null) { 193 //no attr info, load by default 194 return true; 195 } 196 197 return gbean.applyOverrides(data, configName, gbeanName, classLoader); 198 } 199 200 public void setModuleGBeans(Artifact moduleName, GBeanOverride[] gbeans) { 201 if (readOnly) { 202 return; 203 } 204 ConfigurationOverride configuration = serverOverride.getConfiguration(moduleName, true); 205 for (GBeanOverride gbean : gbeans) { 206 configuration.addGBean(gbean); 207 } 208 attributeChanged(); 209 } 210 211 public synchronized void setValue(Artifact configurationName, AbstractName gbeanName, GAttributeInfo attribute, Object value, ClassLoader classLoader) { 212 if (readOnly) { 213 return; 214 } 215 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, true); 216 GBeanOverride gbean = configuration.getGBean(gbeanName); 217 if (gbean == null) { 218 gbean = configuration.getGBean((String) gbeanName.getName().get("name")); 219 if (gbean == null) { 220 gbean = new GBeanOverride(gbeanName, true, expressionParser); 221 configuration.addGBean(gbeanName, gbean); 222 } 223 } 224 225 try { 226 gbean.setAttribute(attribute.getName(), value, attribute.getType(), classLoader); 227 attributeChanged(); 228 } catch (InvalidAttributeException e) { 229 // attribute can not be represented as a string 230 log.error(e.getMessage()); 231 } 232 } 233 234 public synchronized void setReferencePatterns(Artifact configurationName, AbstractName gbeanName, GReferenceInfo reference, ReferencePatterns patterns) { 235 if (readOnly) { 236 return; 237 } 238 239 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, true); 240 GBeanOverride gbean = configuration.getGBean(gbeanName); 241 if (gbean == null) { 242 gbean = configuration.getGBean((String) gbeanName.getName().get("name")); 243 if (gbean == null) { 244 gbean = new GBeanOverride(gbeanName, true, expressionParser); 245 configuration.addGBean(gbeanName, gbean); 246 } 247 } 248 gbean.setReferencePatterns(reference.getName(), patterns); 249 attributeChanged(); 250 } 251 252 public synchronized void setShouldLoad(Artifact configurationName, AbstractName gbeanName, boolean load) { 253 if (readOnly) { 254 return; 255 } 256 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, true); 257 258 GBeanOverride gbean = configuration.getGBean(gbeanName); 259 if (gbean == null) { 260 // attempt to lookup by short name 261 gbean = configuration.getGBean((String) gbeanName.getName().get("name")); 262 } 263 264 if (gbean == null) { 265 gbean = new GBeanOverride(gbeanName, load, expressionParser); 266 configuration.addGBean(gbeanName, gbean); 267 } else { 268 gbean.setLoad(load); 269 } 270 attributeChanged(); 271 } 272 273 public void addGBean(Artifact configurationName, GBeanData gbeanData, ClassLoader classLoader) { 274 if (readOnly) { 275 return; 276 } 277 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName); 278 if (configuration == null) { 279 log.debug("Can not add GBean; Configuration not found " + configurationName); 280 return; 281 } 282 try { 283 GBeanOverride gbean = new GBeanOverride(gbeanData, expressionParser, classLoader); 284 configuration.addGBean(gbean); 285 attributeChanged(); 286 } catch (InvalidAttributeException e) { 287 // attribute can not be represented as a string 288 log.error(e.getMessage()); 289 } 290 } 291 292 public synchronized void load() throws IOException { 293 ensureParentDirectory(); 294 if (!attributeFile.exists()) { 295 return; 296 } 297 InputStream input = new BufferedInputStream(new FileInputStream(attributeFile)); 298 InputSource source = new InputSource(input); 299 source.setSystemId(attributeFile.toString()); 300 DocumentBuilderFactory dFactory = XmlUtil.newDocumentBuilderFactory(); 301 302 try { 303 dFactory.setValidating(true); 304 dFactory.setNamespaceAware(true); 305 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", 306 "http://www.w3.org/2001/XMLSchema"); 307 308 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", 309 LocalAttributeManager.class.getResourceAsStream("/META-INF/schema/attributes-1.1.xsd")); 310 311 DocumentBuilder builder = dFactory.newDocumentBuilder(); 312 builder.setErrorHandler(new ErrorHandler() { 313 public void error(SAXParseException e) { 314 log.error("Unable to read saved manageable attributes. " + 315 "SAX parse error: " + e.getMessage() + 316 " at line " + e.getLineNumber() + 317 ", column " + e.getColumnNumber() + 318 " in entity " + e.getSystemId()); 319 320 if (log.isTraceEnabled()) { 321 log.trace("Exception deatils", e); 322 } 323 324 // TODO throw an exception here? 325 } 326 327 public void fatalError(SAXParseException e) { 328 log.error("Unable to read saved manageable attributes. " + 329 "Fatal SAX parse error: " + e.getMessage() + 330 " at line " + e.getLineNumber() + 331 ", column " + e.getColumnNumber() + 332 " in entity " + e.getSystemId()); 333 334 if (log.isTraceEnabled()) { 335 log.trace("Exception deatils", e); 336 } 337 338 // TODO throw an exception here? 339 } 340 341 public void warning(SAXParseException e) { 342 log.error("SAX parse warning whilst reading saved manageable attributes: " + 343 e.getMessage() + 344 " at line " + e.getLineNumber() + 345 ", column " + e.getColumnNumber() + 346 " in entity " + e.getSystemId()); 347 348 if (log.isTraceEnabled()) { 349 log.trace("Exception deatils", e); 350 } 351 } 352 }); 353 354 Document doc = builder.parse(source); 355 Element root = doc.getDocumentElement(); 356 serverOverride = new ServerOverride(root, expressionParser); 357 } catch (SAXException e) { 358 log.error("Unable to read saved manageable attributes", e); 359 } catch (ParserConfigurationException e) { 360 log.error("Unable to read saved manageable attributes", e); 361 } catch (InvalidGBeanException e) { 362 log.error("Unable to read saved manageable attributes", e); 363 } finally { 364 // input is always non-null 365 input.close(); 366 } 367 } 368 369 public synchronized void save() throws IOException { 370 if (readOnly) { 371 return; 372 } 373 ensureParentDirectory(); 374 if (!tempFile.exists() && !tempFile.createNewFile()) { 375 throw new IOException("Unable to create manageable attribute working file for save " + tempFile.getAbsolutePath()); 376 } 377 if (!tempFile.canWrite()) { 378 throw new IOException("Unable to write to manageable attribute working file for save " + tempFile.getAbsolutePath()); 379 } 380 381 // write the new configuration to the temp file 382 saveXmlToFile(tempFile, serverOverride); 383 384 // delete the current backup file 385 if (backupFile.exists()) { 386 if (!backupFile.delete()) { 387 throw new IOException("Unable to delete old backup file in order to back up current manageable attribute working file for save"); 388 } 389 } 390 391 // rename the existing configuration file to the backup file 392 if (attributeFile.exists()) { 393 if (!attributeFile.renameTo(backupFile)) { 394 throw new IOException("Unable to rename " + attributeFile.getAbsolutePath() + " to " + backupFile.getAbsolutePath() + " in order to back up manageable attribute save file"); 395 } 396 } 397 398 // rename the temp file the the configuration file 399 if (!tempFile.renameTo(attributeFile)) { 400 throw new IOException("EXTREMELY CRITICAL! Unable to move manageable attributes working file to proper file name! Configuration will revert to defaults unless this is manually corrected! (could not rename " + tempFile.getAbsolutePath() + " to " + attributeFile.getAbsolutePath() + ")"); 401 } 402 } 403 404 private static void saveXmlToFile(File file, ServerOverride serverOverride) { 405 DocumentBuilderFactory dFactory = XmlUtil.newDocumentBuilderFactory(); 406 dFactory.setValidating(true); 407 dFactory.setNamespaceAware(true); 408 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", 409 "http://www.w3.org/2001/XMLSchema"); 410 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", 411 LocalAttributeManager.class.getResourceAsStream("/META-INF/schema/attributes-1.1.xsd")); 412 413 OutputStream output = null; 414 try { 415 Document doc = dFactory.newDocumentBuilder().newDocument(); 416 serverOverride.writeXml(doc); 417 TransformerFactory xfactory = XmlUtil.newTransformerFactory(); 418 Transformer xform = xfactory.newTransformer(); 419 xform.setOutputProperty(OutputKeys.INDENT, "yes"); 420 xform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 421 output = new BufferedOutputStream(new FileOutputStream(file)); 422 423 // use a FileOutputStream instead of a File on the StreamResult 424 // constructor as problems were encountered with the file not being closed. 425 StreamResult sr = new StreamResult(output); 426 xform.transform(new DOMSource(doc), sr); 427 428 output.flush(); 429 } catch (FileNotFoundException e) { 430 // file is directory or cannot be created/opened 431 log.error("Unable to write config.xml", e); 432 } catch (ParserConfigurationException e) { 433 log.error("Unable to write config.xml", e); 434 } catch (TransformerException e) { 435 log.error("Unable to write config.xml", e); 436 } catch (IOException e) { 437 log.error("Unable to write config.xml", e); 438 } finally { 439 if (output != null) { 440 try { 441 output.close(); 442 } catch (IOException ignored) { 443 // ignored 444 } 445 } 446 } 447 } 448 449 //PersistentConfigurationList 450 public synchronized boolean isKernelFullyStarted() { 451 return kernelFullyStarted; 452 } 453 454 public synchronized void setKernelFullyStarted(boolean kernelFullyStarted) { 455 this.kernelFullyStarted = kernelFullyStarted; 456 } 457 458 public synchronized List restore() throws IOException { 459 List<Artifact> configs = new ArrayList<Artifact>(); 460 for (Map.Entry<Artifact, ConfigurationOverride> entry : serverOverride.getConfigurations().entrySet()) { 461 ConfigurationOverride configuration = entry.getValue(); 462 if (configuration.isLoad()) { 463 Artifact configID = entry.getKey(); 464 configs.add(configID); 465 } 466 } 467 return configs; 468 } 469 470 public void startConfiguration(Artifact configurationName) { 471 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, false); 472 if (configuration == null) { 473 return; 474 } 475 configuration.setLoad(true); 476 attributeChanged(); 477 } 478 479 public synchronized void addConfiguration(Artifact configurationName) { 480 // Check whether we have it already 481 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, false); 482 // If not, initialize it 483 if (configuration == null) { 484 configuration = serverOverride.getConfiguration(configurationName, true); 485 configuration.setLoad(false); 486 attributeChanged(); 487 } 488 } 489 490 public synchronized void removeConfiguration(Artifact configName) { 491 ConfigurationOverride configuration = serverOverride.getConfiguration(configName); 492 if (configuration == null) { 493 return; 494 } 495 serverOverride.removeConfiguration(configName); 496 attributeChanged(); 497 } 498 499 public Artifact[] getListedConfigurations(Artifact query) { 500 return serverOverride.queryConfigurations(query); 501 } 502 503 public void stopConfiguration(Artifact configName) { 504 ConfigurationOverride configuration = serverOverride.getConfiguration(configName); 505 if (configuration == null) { 506 return; 507 } 508 configuration.setLoad(false); 509 attributeChanged(); 510 } 511 512 public void migrateConfiguration(Artifact oldName, Artifact newName, Configuration configuration) { 513 ConfigurationOverride configInfo = serverOverride.getConfiguration(oldName); 514 if (configInfo == null) { 515 throw new IllegalArgumentException("Trying to migrate unknown configuration: " + oldName); 516 } 517 serverOverride.removeConfiguration(oldName); 518 configInfo = new ConfigurationOverride(configInfo, newName); 519 //todo: check whether all the attributes are still valid for the new configuration 520 serverOverride.addConfiguration(configInfo); 521 attributeChanged(); 522 } 523 524 /** 525 * This method checks if there are any custom gbean attributes in the configuration. 526 * 527 * @param configName Name of the configuration 528 * @return true if the configuration contains any custom gbean attributes 529 */ 530 public boolean hasGBeanAttributes(Artifact configName) { 531 ConfigurationOverride configInfo = serverOverride.getConfiguration(configName); 532 return configInfo != null && !configInfo.getGBeans().isEmpty(); 533 } 534 535 //GBeanLifeCycle 536 public synchronized void doStart() throws Exception { 537 load(); 538 if (!readOnly) { 539 timer = new Timer(); 540 } 541 log.debug("Started LocalAttributeManager with data on " + serverOverride.getConfigurations().size() + " configurations"); 542 } 543 544 public synchronized void doStop() throws Exception { 545 boolean doSave = false; 546 synchronized (this) { 547 if (timer != null) { 548 timer.cancel(); 549 if (currentTask != null) { 550 currentTask.cancel(); 551 doSave = true; 552 } 553 } 554 } 555 if (doSave) { 556 save(); 557 } 558 log.debug("Stopped LocalAttributeManager with data on " + serverOverride.getConfigurations().size() + " configurations"); 559 serverOverride = new ServerOverride(); 560 } 561 562 public synchronized void doFail() { 563 synchronized (this) { 564 if (timer != null) { 565 timer.cancel(); 566 if (currentTask != null) { 567 currentTask.cancel(); 568 } 569 } 570 } 571 serverOverride = new ServerOverride(); 572 } 573 574 private synchronized void ensureParentDirectory() throws IOException { 575 if (attributeFile == null) { 576 attributeFile = serverInfo.resolveServer(configFile); 577 tempFile = new File(attributeFile.getAbsolutePath() + TEMP_EXTENSION); 578 backupFile = new File(attributeFile.getAbsolutePath() + BACKUP_EXTENSION); 579 } 580 File parent = attributeFile.getParentFile(); 581 if (!parent.isDirectory()) { 582 if (!parent.mkdirs()) { 583 throw new IOException("Unable to create directory for list:" + parent); 584 } 585 } 586 if (!parent.canRead()) { 587 throw new IOException("Unable to read manageable attribute files in directory " + parent.getAbsolutePath()); 588 } 589 if (!readOnly && !parent.canWrite()) { 590 throw new IOException("Unable to write manageable attribute files to directory " + parent.getAbsolutePath()); 591 } 592 } 593 594 private synchronized void attributeChanged() { 595 if (currentTask != null) { 596 currentTask.cancel(); 597 } 598 if (timer != null) { 599 currentTask = new TimerTask() { 600 601 public void run() { 602 try { 603 LocalAttributeManager.this.save(); 604 } catch (IOException e) { 605 log.error("IOException occurred while saving attributes", e); 606 } catch (Throwable t) { 607 log.error("Error occurred during execution of attributeChanged TimerTask", t); 608 } 609 } 610 }; 611 timer.schedule(currentTask, SAVE_BUFFER_MS); 612 } 613 } 614 615 private static JexlExpressionParser loadProperties(String propertiesFile, ServerInfo serverInfo, String prefix) { 616 Map<String, String> vars = new HashMap<String, String>(); 617 //properties file is least significant 618 if (propertiesFile != null) { 619 Properties properties = new Properties(); 620 File thePropertiesFile = serverInfo.resolveServer(propertiesFile); 621 log.debug("Loading properties file " + thePropertiesFile.getAbsolutePath()); 622 try { 623 properties.load(new FileInputStream(thePropertiesFile)); 624 } catch (Exception e) { 625 log.error("Caught exception " + e 626 + " trying to open properties file " + thePropertiesFile.getAbsolutePath()); 627 } 628 addGeronimoSubstitutions(vars, properties, ""); 629 } 630 //environment variables are next 631 addGeronimoSubstitutions(vars, System.getenv(), prefix); 632 //most significant are the command line system properties 633 addGeronimoSubstitutions(vars, System.getProperties(), prefix); 634 return new JexlExpressionParser(vars); 635 } 636 637 private static void addGeronimoSubstitutions(Map<String, String> vars, Map props, String prefix) { 638 if (prefix != null) { 639 int start = prefix.length(); 640 for (Object o: props.entrySet()) { 641 Map.Entry entry = (Map.Entry) o; 642 if (((String)entry.getKey()).startsWith(prefix)) { 643 vars.put(((String)entry.getKey()).substring(start), (String)entry.getValue()); 644 } 645 } 646 } 647 } 648 649 public static final GBeanInfo GBEAN_INFO; 650 651 static { 652 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(LocalAttributeManager.class, "AttributeStore"); 653 infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean"); 654 infoFactory.addAttribute("configFile", String.class, true); 655 infoFactory.addAttribute("readOnly", boolean.class, true); 656 infoFactory.addAttribute("substitutionsFile", String.class, true); 657 infoFactory.addAttribute("substitutionPrefix", String.class, true); 658 infoFactory.addInterface(ManageableAttributeStore.class); 659 infoFactory.addInterface(PersistentConfigurationList.class); 660 661 infoFactory.setConstructor(new String[]{"configFile", "substitutionsFile", "substitutionPrefix", "readOnly", "ServerInfo"}); 662 663 GBEAN_INFO = infoFactory.getBeanInfo(); 664 } 665 666 public static GBeanInfo getGBeanInfo() { 667 return GBEAN_INFO; 668 } 669 }