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