1 17 package org.apache.geronimo.system.configuration; 18 19 import org.apache.commons.logging.Log; 20 import org.apache.commons.logging.LogFactory; 21 import org.apache.geronimo.common.propertyeditor.PropertyEditors; 22 import org.apache.geronimo.gbean.AbstractName; 23 import org.apache.geronimo.gbean.GAttributeInfo; 24 import org.apache.geronimo.gbean.GBeanData; 25 import org.apache.geronimo.gbean.GBeanInfo; 26 import org.apache.geronimo.gbean.GBeanInfoBuilder; 27 import org.apache.geronimo.gbean.GBeanLifecycle; 28 import org.apache.geronimo.gbean.GReferenceInfo; 29 import org.apache.geronimo.gbean.ReferencePatterns; 30 import org.apache.geronimo.kernel.config.InvalidConfigException; 31 import org.apache.geronimo.kernel.config.ManageableAttributeStore; 32 import org.apache.geronimo.kernel.config.PersistentConfigurationList; 33 import org.apache.geronimo.kernel.config.Configuration; 34 import org.apache.geronimo.kernel.repository.Artifact; 35 import org.apache.geronimo.kernel.InvalidGBeanException; 36 import org.apache.geronimo.kernel.util.XmlUtil; 37 import org.apache.geronimo.system.serverinfo.ServerInfo; 38 import org.w3c.dom.Document ; 39 import org.w3c.dom.Element ; 40 import org.xml.sax.ErrorHandler ; 41 import org.xml.sax.InputSource ; 42 import org.xml.sax.SAXException ; 43 import org.xml.sax.SAXParseException ; 44 45 import javax.xml.parsers.DocumentBuilder ; 46 import javax.xml.parsers.DocumentBuilderFactory ; 47 import javax.xml.parsers.ParserConfigurationException ; 48 import javax.xml.transform.TransformerFactory ; 49 import javax.xml.transform.Transformer ; 50 import javax.xml.transform.OutputKeys ; 51 import javax.xml.transform.TransformerException ; 52 import javax.xml.transform.stream.StreamResult ; 53 import javax.xml.transform.dom.DOMSource ; 54 55 import java.beans.PropertyEditor ; 56 57 import java.io.File ; 58 import java.io.FileInputStream ; 59 import java.io.InputStream ; 60 import java.io.BufferedInputStream ; 61 import java.io.FileNotFoundException ; 62 import java.io.FileOutputStream ; 63 import java.io.IOException ; 64 import java.io.OutputStream ; 65 import java.io.BufferedOutputStream ; 66 67 import java.util.ArrayList ; 68 import java.util.Collection ; 69 import java.util.HashMap ; 70 import java.util.Iterator ; 71 import java.util.List ; 72 import java.util.Map ; 73 import java.util.Timer ; 74 import java.util.TimerTask ; 75 76 81 public class LocalAttributeManager implements PluginAttributeStore, PersistentConfigurationList, GBeanLifecycle { 82 private static final Log log = LogFactory.getLog(LocalAttributeManager.class); 83 84 private static final String CONFIG_FILE_PROPERTY = "org.apache.geronimo.config.file"; 85 86 private static final String BACKUP_EXTENSION = ".bak"; 87 private static final String TEMP_EXTENSION = ".working"; 88 private static final int SAVE_BUFFER_MS = 5000; 89 90 private final ServerInfo serverInfo; 91 private final String configFile; 92 private final boolean readOnly; 93 94 private File attributeFile; 95 private File backupFile; 96 private File tempFile; 97 private ServerOverride serverOverride; 98 99 private Timer timer; 100 private TimerTask currentTask; 101 102 private boolean kernelFullyStarted; 103 104 public LocalAttributeManager(String configFile, boolean readOnly, ServerInfo serverInfo) { 105 this.configFile = System.getProperty(CONFIG_FILE_PROPERTY, configFile); 106 this.readOnly = readOnly; 107 this.serverInfo = serverInfo; 108 serverOverride = new ServerOverride(); 109 } 110 111 public boolean isReadOnly() { 112 return readOnly; 113 } 114 115 public synchronized Collection applyOverrides(Artifact configName, Collection gbeanDatas, ClassLoader classLoader) throws InvalidConfigException { 116 gbeanDatas = new ArrayList (gbeanDatas); 118 119 ConfigurationOverride configuration = serverOverride.getConfiguration(configName); 120 if (configuration == null) { 121 return gbeanDatas; 122 } 123 124 Map datasByName = new HashMap (); 126 for (Iterator iterator = gbeanDatas.iterator(); iterator.hasNext();) { 127 GBeanData gbeanData = (GBeanData) iterator.next(); 128 datasByName.put(gbeanData.getAbstractName(), gbeanData); 129 datasByName.put(gbeanData.getAbstractName().getName().get("name"), gbeanData); 130 } 131 132 for (Iterator iterator = configuration.getGBeans().entrySet().iterator(); iterator.hasNext();) { 134 Map.Entry entry = (Map.Entry ) iterator.next(); 135 Object name = entry.getKey(); 136 GBeanOverride gbean = (GBeanOverride) entry.getValue(); 137 if (!datasByName.containsKey(name) && gbean.isLoad()) { 138 if (gbean.getGBeanInfo() == null || !(name instanceof AbstractName)) { 139 String sep = ""; 140 StringBuffer message = new StringBuffer ("New GBeans must be specified with "); 141 if (gbean.getGBeanInfo() == null) { 142 message.append("a GBeanInfo "); 143 sep = "and "; 144 } 145 if (!(name instanceof AbstractName)) { 146 message.append(sep).append("a full AbstractName "); 147 } 148 message.append("configuration=").append(configName); 149 message.append(" gbeanName=").append(name); 150 throw new InvalidConfigException(message.toString()); 151 } 152 GBeanInfo gbeanInfo = GBeanInfo.getGBeanInfo(gbean.getGBeanInfo(), classLoader); 153 AbstractName abstractName = (AbstractName)name; 154 GBeanData gBeanData = new GBeanData(abstractName, gbeanInfo); 155 gbeanDatas.add(gBeanData); 156 } 157 } 158 159 for (Iterator iterator = gbeanDatas.iterator(); iterator.hasNext();) { 161 GBeanData data = (GBeanData) iterator.next(); 162 boolean load = setAttributes(data, configuration, configName, classLoader); 163 if (!load) { 164 iterator.remove(); 165 } 166 } 167 return gbeanDatas; 168 } 169 170 181 private synchronized boolean setAttributes(GBeanData data, ConfigurationOverride configuration, Artifact configName, ClassLoader classLoader) throws InvalidConfigException { 182 AbstractName gbeanName = data.getAbstractName(); 183 GBeanOverride gbean = configuration.getGBean(gbeanName); 184 if (gbean == null) { 185 gbean = configuration.getGBean((String ) gbeanName.getName().get("name")); 186 } 187 188 if (gbean == null) { 189 return true; 191 } 192 193 if (!gbean.isLoad()) { 194 return false; 195 } 196 197 GBeanInfo gbeanInfo = data.getGBeanInfo(); 198 199 for (Iterator iterator = gbean.getAttributes().entrySet().iterator(); iterator.hasNext();) { 201 Map.Entry entry = (Map.Entry ) iterator.next(); 202 String attributeName = (String ) entry.getKey(); 203 GAttributeInfo attributeInfo = gbeanInfo.getAttribute(attributeName); 204 if (attributeInfo == null) { 205 throw new InvalidConfigException("No attribute: " + attributeName + " for gbean: " + data.getAbstractName()); 206 } 207 String valueString = (String ) entry.getValue(); 208 Object value = getValue(attributeInfo, valueString, configName, gbeanName, classLoader); 209 data.setAttribute(attributeName, value); 210 } 211 212 for (Iterator iterator = gbean.getClearAttributes().iterator(); iterator.hasNext();){ 214 String attribute = (String ) iterator.next(); 215 if (gbean.getClearAttribute(attribute)){ 216 data.clearAttribute(attribute); 217 } 218 } 219 220 for (Iterator iterator = gbean.getNullAttributes().iterator(); iterator.hasNext();){ 222 String attribute = (String ) iterator.next(); 223 if (gbean.getNullAttribute(attribute)){ 224 data.setAttribute(attribute, null); 225 } 226 } 227 228 for (Iterator iterator = gbean.getReferences().entrySet().iterator(); iterator.hasNext();) { 230 Map.Entry entry = (Map.Entry ) iterator.next(); 231 232 String referenceName = (String ) entry.getKey(); 233 GReferenceInfo referenceInfo = gbeanInfo.getReference(referenceName); 234 if (referenceInfo == null) { 235 throw new InvalidConfigException("No reference: " + referenceName + " for gbean: " + data.getAbstractName()); 236 } 237 238 ReferencePatterns referencePatterns = (ReferencePatterns) entry.getValue(); 239 240 data.setReferencePatterns(referenceName, referencePatterns); 241 } 242 243 for (Iterator iterator = gbean.getClearReferences().iterator(); iterator.hasNext();){ 245 String reference = (String ) iterator.next(); 246 if (gbean.getClearReference(reference)){ 247 data.clearReference(reference); 248 } 249 } 250 251 return true; 252 } 253 254 255 private synchronized Object getValue(GAttributeInfo attribute, String value, Artifact configurationName, AbstractName gbeanName, ClassLoader classLoader) { 256 if (value == null) { 257 return null; 258 } 259 260 try { 261 PropertyEditor editor = PropertyEditors.findEditor(attribute.getType(), classLoader); 262 if (editor == null) { 263 log.debug("Unable to parse attribute of type " + attribute.getType() + "; no editor found"); 264 return null; 265 } 266 editor.setAsText(value); 267 log.debug("Setting value for " + configurationName + "/" + gbeanName + "/" + attribute.getName() + " to value " + value); 268 return editor.getValue(); 269 } catch (ClassNotFoundException e) { 270 log.error("Unable to load attribute type " + attribute.getType()); 271 return null; 272 } 273 } 274 275 public void setModuleGBeans(Artifact moduleName, GBeanOverride[] gbeans) { 276 if (readOnly) { 277 return; 278 } 279 ConfigurationOverride configuration = serverOverride.getConfiguration(moduleName, true); 280 for (int i = 0; i < gbeans.length; i++) { 281 GBeanOverride gbean = gbeans[i]; 282 configuration.addGBean(gbean); 283 } 284 attributeChanged(); 285 } 286 287 public synchronized void setValue(Artifact configurationName, AbstractName gbeanName, GAttributeInfo attribute, Object value) { 288 if (readOnly) { 289 return; 290 } 291 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, true); 292 GBeanOverride gbean = configuration.getGBean(gbeanName); 293 if (gbean == null) { 294 gbean = configuration.getGBean((String ) gbeanName.getName().get("name")); 295 if (gbean == null) { 296 gbean = new GBeanOverride(gbeanName, true); 297 configuration.addGBean(gbeanName, gbean); 298 } 299 } 300 301 try { 302 gbean.setAttribute(attribute.getName(), value, attribute.getType()); 303 attributeChanged(); 304 } catch (InvalidAttributeException e) { 305 log.error(e.getMessage()); 307 } 308 } 309 310 public synchronized void setReferencePatterns(Artifact configurationName, AbstractName gbeanName, GReferenceInfo reference, ReferencePatterns patterns) { 311 if (readOnly) { 312 return; 313 } 314 315 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, true); 316 GBeanOverride gbean = configuration.getGBean(gbeanName); 317 if (gbean == null) { 318 gbean = configuration.getGBean((String )gbeanName.getName().get("name")); 319 if (gbean == null) { 320 gbean = new GBeanOverride(gbeanName, true); 321 configuration.addGBean(gbeanName, gbean); 322 } 323 } 324 gbean.setReferencePatterns(reference.getName(), patterns); 325 attributeChanged(); 326 } 327 328 public synchronized void setShouldLoad(Artifact configurationName, AbstractName gbeanName, boolean load) { 329 if (readOnly) { 330 return; 331 } 332 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, true); 333 334 GBeanOverride gbean = configuration.getGBean(gbeanName); 335 if (gbean == null) { 336 gbean = configuration.getGBean((String )gbeanName.getName().get("name")); 338 } 339 340 if (gbean == null) { 341 gbean = new GBeanOverride(gbeanName, load); 342 configuration.addGBean(gbeanName, gbean); 343 } else { 344 gbean.setLoad(load); 345 } 346 attributeChanged(); 347 } 348 349 public void addGBean(Artifact configurationName, GBeanData gbeanData) { 350 if (readOnly) { 351 return; 352 } 353 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName); 354 if (configuration == null) { 355 log.debug("Can not add GBean; Configuration not found " + configurationName); 356 return; 357 } 358 try { 359 GBeanOverride gbean = new GBeanOverride(gbeanData); 360 configuration.addGBean(gbean); 361 attributeChanged(); 362 } catch (InvalidAttributeException e) { 363 log.error(e.getMessage()); 365 } 366 } 367 368 public synchronized void load() throws IOException { 369 ensureParentDirectory(); 370 if (!attributeFile.exists()) { 371 return; 372 } 373 374 InputStream input = new BufferedInputStream (new FileInputStream (attributeFile)); 375 InputSource source = new InputSource (input); 376 source.setSystemId(attributeFile.toString()); 377 DocumentBuilderFactory dFactory = XmlUtil.newDocumentBuilderFactory(); 378 379 try { 380 dFactory.setValidating(true); 381 dFactory.setNamespaceAware(true); 382 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", 383 "http://www.w3.org/2001/XMLSchema"); 384 385 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", 386 LocalAttributeManager.class.getResourceAsStream("/META-INF/schema/attributes-1.1.xsd")); 387 388 DocumentBuilder builder = dFactory.newDocumentBuilder(); 389 builder.setErrorHandler(new ErrorHandler () { 390 public void error(SAXParseException e) { 391 log.error("Unable to read saved manageable attributes. " + 392 "SAX parse error: " + e.getMessage() + 393 " at line " + e.getLineNumber() + 394 ", column " + e.getColumnNumber() + 395 " in entity " + e.getSystemId()); 396 397 if (log.isTraceEnabled()) { 398 log.trace("Exception deatils", e); 399 } 400 401 } 403 404 public void fatalError(SAXParseException e) { 405 log.error("Unable to read saved manageable attributes. " + 406 "Fatal SAX parse error: " + e.getMessage() + 407 " at line " + e.getLineNumber() + 408 ", column " + e.getColumnNumber() + 409 " in entity " + e.getSystemId()); 410 411 if (log.isTraceEnabled()) { 412 log.trace("Exception deatils", e); 413 } 414 415 } 417 418 public void warning(SAXParseException e) { 419 log.error("SAX parse warning whilst reading saved manageable attributes: " + 420 e.getMessage() + 421 " at line " + e.getLineNumber() + 422 ", column " + e.getColumnNumber() + 423 " in entity " + e.getSystemId()); 424 425 if (log.isTraceEnabled()) { 426 log.trace("Exception deatils", e); 427 } 428 } 429 }); 430 431 Document doc = builder.parse(source); 432 Element root = doc.getDocumentElement(); 433 serverOverride = new ServerOverride(root); 434 } catch (SAXException e) { 435 log.error("Unable to read saved manageable attributes", e); 436 } catch (ParserConfigurationException e) { 437 log.error("Unable to read saved manageable attributes", e); 438 } catch (InvalidGBeanException e) { 439 log.error("Unable to read saved manageable attributes", e); 440 } finally { 441 input.close(); 443 } 444 } 445 446 public synchronized void save() throws IOException { 447 if (readOnly) { 448 return; 449 } 450 ensureParentDirectory(); 451 if (!tempFile.exists() && !tempFile.createNewFile()) { 452 throw new IOException ("Unable to create manageable attribute working file for save " + tempFile.getAbsolutePath()); 453 } 454 if (!tempFile.canWrite()) { 455 throw new IOException ("Unable to write to manageable attribute working file for save " + tempFile.getAbsolutePath()); 456 } 457 458 saveXmlToFile(tempFile, serverOverride); 460 461 if (backupFile.exists()) { 463 if (!backupFile.delete()) { 464 throw new IOException ("Unable to delete old backup file in order to back up current manageable attribute working file for save"); 465 } 466 } 467 468 if (attributeFile.exists()) { 470 if (!attributeFile.renameTo(backupFile)) { 471 throw new IOException ("Unable to rename " + attributeFile.getAbsolutePath() + " to " + backupFile.getAbsolutePath() + " in order to back up manageable attribute save file"); 472 } 473 } 474 475 if (!tempFile.renameTo(attributeFile)) { 477 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() + ")"); 478 } 479 } 480 481 private static void saveXmlToFile(File file, ServerOverride serverOverride) { 482 DocumentBuilderFactory dFactory = XmlUtil.newDocumentBuilderFactory(); 483 dFactory.setValidating(true); 484 dFactory.setNamespaceAware(true); 485 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage", 486 "http://www.w3.org/2001/XMLSchema"); 487 dFactory.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaSource", 488 LocalAttributeManager.class.getResourceAsStream("/META-INF/schema/attributes-1.1.xsd")); 489 490 OutputStream output = null; 491 try { 492 Document doc = dFactory.newDocumentBuilder().newDocument(); 493 serverOverride.writeXml(doc); 494 TransformerFactory xfactory = XmlUtil.newTransformerFactory(); 495 Transformer xform = xfactory.newTransformer(); 496 xform.setOutputProperty(OutputKeys.INDENT, "yes"); 497 xform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 498 output = new BufferedOutputStream (new FileOutputStream (file)); 499 500 StreamResult sr = new StreamResult (output); 503 xform.transform(new DOMSource (doc), sr); 504 505 output.flush(); 506 } catch (FileNotFoundException e) { 507 log.error("Unable to write config.xml", e); 509 } catch (ParserConfigurationException e) { 510 log.error("Unable to write config.xml", e); 511 } catch (TransformerException e) { 512 log.error("Unable to write config.xml", e); 513 } catch (IOException e) { 514 log.error("Unable to write config.xml", e); 515 } finally { 516 if (output != null) { 517 try { 518 output.close(); 519 } catch (IOException ignored) { 520 } 522 } 523 } 524 } 525 526 public synchronized boolean isKernelFullyStarted() { 528 return kernelFullyStarted; 529 } 530 531 public synchronized void setKernelFullyStarted(boolean kernelFullyStarted) { 532 this.kernelFullyStarted = kernelFullyStarted; 533 } 534 535 public synchronized List restore() throws IOException { 536 List configs = new ArrayList (); 537 for (Iterator iterator = serverOverride.getConfigurations().entrySet().iterator(); iterator.hasNext();) { 538 Map.Entry entry = (Map.Entry ) iterator.next(); 539 ConfigurationOverride configuration = (ConfigurationOverride) entry.getValue(); 540 if (configuration.isLoad()) { 541 Artifact configID = (Artifact) entry.getKey(); 542 configs.add(configID); 543 } 544 } 545 return configs; 546 } 547 548 public void startConfiguration(Artifact configurationName) { 549 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, false); 550 if(configuration == null) { 551 return; 552 } 553 configuration.setLoad(true); 554 attributeChanged(); 555 } 556 557 public synchronized void addConfiguration(Artifact configurationName) { 558 ConfigurationOverride configuration = serverOverride.getConfiguration(configurationName, false); 560 if(configuration == null) { 562 configuration = serverOverride.getConfiguration(configurationName, true); 563 configuration.setLoad(false); 564 attributeChanged(); 565 } 566 } 567 568 public synchronized void removeConfiguration(Artifact configName) { 569 ConfigurationOverride configuration = serverOverride.getConfiguration(configName); 570 if (configuration == null) { 571 return; 572 } 573 serverOverride.removeConfiguration(configName); 574 attributeChanged(); 575 } 576 577 public Artifact[] getListedConfigurations(Artifact query) { 578 return serverOverride.queryConfigurations(query); 579 } 580 581 public void stopConfiguration(Artifact configName) { 582 ConfigurationOverride configuration = serverOverride.getConfiguration(configName); 583 if (configuration == null) { 584 return; 585 } 586 configuration.setLoad(false); 587 attributeChanged(); 588 } 589 590 public void migrateConfiguration(Artifact oldName, Artifact newName, Configuration configuration) { 591 ConfigurationOverride configInfo = serverOverride.getConfiguration(oldName); 592 if(configInfo == null) { 593 throw new IllegalArgumentException ("Trying to migrate unknown configuration: " + oldName); 594 } 595 serverOverride.removeConfiguration(oldName); 596 configInfo = new ConfigurationOverride(configInfo, newName); 597 serverOverride.addConfiguration(configInfo); 599 attributeChanged(); 600 } 601 602 608 public boolean hasGBeanAttributes(Artifact configName) { 609 ConfigurationOverride configInfo = serverOverride.getConfiguration(configName); 610 return configInfo != null && !configInfo.getGBeans().isEmpty(); 611 } 612 613 public synchronized void doStart() throws Exception { 615 load(); 616 if (!readOnly) { 617 timer = new Timer (); 618 } 619 log.debug("Started LocalAttributeManager with data on " + serverOverride.getConfigurations().size() + " configurations"); 620 } 621 622 public synchronized void doStop() throws Exception { 623 boolean doSave = false; 624 synchronized (this) { 625 if (timer != null) { 626 timer.cancel(); 627 if (currentTask != null) { 628 currentTask.cancel(); 629 doSave = true; 630 } 631 } 632 } 633 if (doSave) { 634 save(); 635 } 636 log.debug("Stopped LocalAttributeManager with data on " + serverOverride.getConfigurations().size() + " configurations"); 637 serverOverride = new ServerOverride(); 638 } 639 640 public synchronized void doFail() { 641 synchronized (this) { 642 if (timer != null) { 643 timer.cancel(); 644 if (currentTask != null) { 645 currentTask.cancel(); 646 } 647 } 648 } 649 serverOverride = new ServerOverride(); 650 } 651 652 private synchronized void ensureParentDirectory() throws IOException { 653 if (attributeFile == null) { 654 attributeFile = serverInfo.resolveServer(configFile); 655 tempFile = new File (attributeFile.getAbsolutePath() + TEMP_EXTENSION); 656 backupFile = new File (attributeFile.getAbsolutePath() + BACKUP_EXTENSION); 657 } 658 File parent = attributeFile.getParentFile(); 659 if (!parent.isDirectory()) { 660 if (!parent.mkdirs()) { 661 throw new IOException ("Unable to create directory for list:" + parent); 662 } 663 } 664 if (!parent.canRead() || !parent.canWrite()) { 665 throw new IOException ("Unable to write manageable attribute files to directory " + parent.getAbsolutePath()); 666 } 667 } 668 669 private synchronized void attributeChanged() { 670 if (currentTask != null) { 671 currentTask.cancel(); 672 } 673 if (timer != null) { 674 currentTask = new TimerTask () { 675 676 public void run() { 677 try { 678 LocalAttributeManager.this.save(); 679 } catch (IOException e) { 680 log.error("Error saving attributes", e); 681 } 682 } 683 }; 684 timer.schedule(currentTask, SAVE_BUFFER_MS); 685 } 686 } 687 688 public static final GBeanInfo GBEAN_INFO; 689 690 static { 691 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(LocalAttributeManager.class, "AttributeStore"); 692 infoFactory.addReference("ServerInfo", ServerInfo.class, "GBean"); 693 infoFactory.addAttribute("configFile", String .class, true); 694 infoFactory.addAttribute("readOnly", boolean.class, true); 695 infoFactory.addInterface(ManageableAttributeStore.class); 696 infoFactory.addInterface(PersistentConfigurationList.class); 697 698 infoFactory.setConstructor(new String []{"configFile", "readOnly", "ServerInfo"}); 699 700 GBEAN_INFO = infoFactory.getBeanInfo(); 701 } 702 703 public static GBeanInfo getGBeanInfo() { 704 return GBEAN_INFO; 705 } 706 } 707 | Popular Tags |