001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.config; 017 018import java.io.File; 019import java.io.FileOutputStream; 020import java.io.OutputStream; 021import java.util.ArrayList; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.HashMap; 026import java.util.Iterator; 027import java.util.List; 028import java.util.Map; 029import java.util.Properties; 030 031import javax.xml.transform.OutputKeys; 032import javax.xml.transform.TransformerFactory; 033import javax.xml.transform.TransformerFactoryConfigurationError; 034import javax.xml.transform.sax.SAXTransformerFactory; 035import javax.xml.transform.sax.TransformerHandler; 036import javax.xml.transform.stream.StreamResult; 037 038import org.apache.avalon.framework.activity.Initializable; 039import org.apache.avalon.framework.configuration.ConfigurationException; 040import org.apache.avalon.framework.context.Context; 041import org.apache.avalon.framework.context.Contextualizable; 042import org.apache.avalon.framework.service.ServiceException; 043import org.apache.avalon.framework.service.ServiceManager; 044import org.apache.avalon.framework.service.Serviceable; 045import org.apache.cocoon.xml.XMLUtils; 046import org.apache.commons.lang3.StringUtils; 047import org.apache.xml.serializer.OutputPropertiesFactory; 048import org.slf4j.Logger; 049import org.slf4j.LoggerFactory; 050import org.xml.sax.SAXException; 051 052import org.ametys.core.util.I18nUtils; 053import org.ametys.core.util.I18nizableTextComparator; 054import org.ametys.core.util.I18nizableTextKeyComparator; 055import org.ametys.runtime.i18n.I18nizableText; 056import org.ametys.runtime.model.CategorizedElementDefinitionHelper; 057import org.ametys.runtime.model.DefinitionAndValue; 058import org.ametys.runtime.model.ElementDefinition; 059import org.ametys.runtime.model.Enumerator; 060import org.ametys.runtime.model.I18nizableTextModelItemComparator; 061import org.ametys.runtime.model.Model; 062import org.ametys.runtime.model.ModelHelper; 063import org.ametys.runtime.model.ModelItem; 064import org.ametys.runtime.model.ModelItemGroup; 065import org.ametys.runtime.model.View; 066import org.ametys.runtime.model.checker.ItemChecker; 067import org.ametys.runtime.model.disableconditions.DisableConditions; 068import org.ametys.runtime.model.disableconditions.DisableConditionsEvaluator; 069import org.ametys.runtime.model.exception.UndefinedItemPathException; 070import org.ametys.runtime.model.type.ElementType; 071import org.ametys.runtime.model.type.ModelItemTypeConstants; 072import org.ametys.runtime.model.type.ModelItemTypeExtensionPoint; 073import org.ametys.runtime.model.type.xml.XMLElementType; 074import org.ametys.runtime.parameter.ValidationResult; 075import org.ametys.runtime.parameter.Validator; 076import org.ametys.runtime.plugin.component.ThreadSafeComponentManager; 077 078/** 079 * This manager handle the parameters of the application that have to be stored by the plugins. 080 */ 081public final class ConfigManager implements Model, Contextualizable, Serviceable, Initializable 082{ 083 // shared instance 084 private static ConfigManager __manager; 085 086 // Logger for traces 087 private Logger _logger = LoggerFactory.getLogger(ConfigManager.class); 088 private Logger _threadSafeComponentLogger = LoggerFactory.getLogger("runtime.plugin.threadsafecomponent"); 089 090 // Avalon stuff 091 private ServiceManager _serviceManager; 092 private Context _context; 093 094 // ComponentManager for the validators 095 private ThreadSafeComponentManager<Validator> _validatorManager; 096 // ComponentManager for the enumerators 097 private ThreadSafeComponentManager<Enumerator> _enumeratorManager; 098 // ComponentManager for the parameter checkers 099 private ThreadSafeComponentManager<ItemChecker> _parameterCheckerManager; 100 101 private Map<String, ConfigParameterInfo> _declaredParams; 102 private Map<String, ConfigParameterInfo> _declaredParamCheckers; 103 private Collection<String> _usedParamIds; 104 private Map<String, ConfigParameterDefinitionWrapper> _configParameterWrappers; 105 private Map<String, ConfigParameterCheckerDescriptor> _parameterCheckers; 106 107 // The configuration model items 108 private List<ModelItem> _categorizedDefinitions; 109 private Map<String, ElementDefinition> _flatDefinitions; 110 111 // Determines if the extension point is initialized 112 private boolean _isInitialized; 113 // Determines if all parameters are valued 114 private boolean _isComplete; 115 116 private ModelItemTypeExtensionPoint _configParameterTypeEP; 117 private DisableConditionsEvaluator<Config> _disableConditionsEvaluator; 118 119 private ConfigManager() 120 { 121 // empty constructor 122 } 123 124 /** 125 * Returns the shared instance of the ConfigManager 126 * @return the shared instance of the ConfigManager 127 */ 128 public static ConfigManager getInstance() 129 { 130 if (__manager == null) 131 { 132 __manager = new ConfigManager(); 133 } 134 135 return __manager; 136 } 137 138 @Override 139 public void contextualize(Context context) 140 { 141 _context = context; 142 } 143 144 @SuppressWarnings("unchecked") 145 @Override 146 public void service(ServiceManager manager) throws ServiceException 147 { 148 _serviceManager = manager; 149 _configParameterTypeEP = (ModelItemTypeExtensionPoint) _serviceManager.lookup(ModelItemTypeExtensionPoint.ROLE_CONFIG); 150 _disableConditionsEvaluator = (DisableConditionsEvaluator<Config>) _serviceManager.lookup(ConfigDisableConditionsEvaluator.ROLE_FOR_CONFIG_EVALUATOR); 151 } 152 153 @Override 154 public void initialize() 155 { 156 _usedParamIds = new ArrayList<>(); 157 _declaredParams = new HashMap<>(); 158 _configParameterWrappers = new HashMap<>(); 159 _declaredParamCheckers = new HashMap<>(); 160 _parameterCheckers = new HashMap<>(); 161 _flatDefinitions = new HashMap<>(); 162 163 _validatorManager = new ThreadSafeComponentManager<>(); 164 _validatorManager.setLogger(_threadSafeComponentLogger); 165 _validatorManager.contextualize(_context); 166 _validatorManager.service(_serviceManager); 167 168 _enumeratorManager = new ThreadSafeComponentManager<>(); 169 _enumeratorManager.setLogger(_threadSafeComponentLogger); 170 _enumeratorManager.contextualize(_context); 171 _enumeratorManager.service(_serviceManager); 172 173 _parameterCheckerManager = new ThreadSafeComponentManager<>(); 174 _parameterCheckerManager.setLogger(_threadSafeComponentLogger); 175 _parameterCheckerManager.contextualize(_context); 176 _parameterCheckerManager.service(_serviceManager); 177 } 178 179 /** 180 * Registers new available parameters. 181 * The addFeatureConfig() method allows to select which ones are actually useful. 182 * @param pluginName the name of the plugin defining the parameters 183 * @param parameters the configuration parameters definition 184 * @param parameterCheckers the parameters checkers definition 185 */ 186 public void addPluginConfig(String pluginName, Map<String, ConfigParameterInfo> parameters, Map<String, ConfigParameterInfo> parameterCheckers) 187 { 188 _logger.debug("Adding parameters and parameters checkers for plugin {}.", pluginName); 189 190 // declare parameters and parameter checkers configured in the plugin 191 _declareParameters(parameters); 192 _declareParameterCheckers(parameterCheckers); 193 } 194 195 /** 196 * Registers a new parameter or references a globalConfig parameter.<br> 197 * @param featureId the id of the feature defining the parameters 198 * @param parameters the configuration parameters definition 199 * @param parameterCheckers the parameters checkers definition 200 * @param parameterReferences references to already defined parameters 201 */ 202 public void addFeatureConfig(String featureId, Map<String, ConfigParameterInfo> parameters, Map<String, ConfigParameterInfo> parameterCheckers, Collection<String> parameterReferences) 203 { 204 _logger.debug("Selecting parameters for feature {}.", featureId); 205 206 // declare parameters and parameter checkers configured in the feature 207 _declareParameters(parameters); 208 _declareParameterCheckers(parameterCheckers); 209 210 // Add parameters declared in feature to the list of used parameters 211 _usedParamIds.addAll(parameters.keySet()); 212 213 // Add referenced parameters to the list of used parameters 214 _usedParamIds.addAll(parameterReferences); 215 } 216 217 private void _declareParameters(Map<String, ConfigParameterInfo> parameters) 218 { 219 for (String id : parameters.keySet()) 220 { 221 ConfigParameterInfo info = parameters.get(id); 222 223 // Check if the parameter is not already declared 224 if (_declaredParams.containsKey(id)) 225 { 226 throw new IllegalArgumentException("The config parameter '" + id + "' is already declared. Parameters ids must be unique"); 227 } 228 229 // Add the new parameter to the list of declared ones 230 _declaredParams.put(id, info); 231 232 _logger.debug("Parameter added: {}", id); 233 } 234 235 _logger.debug("{} parameter(s) added", parameters.size()); 236 } 237 238 private void _declareParameterCheckers(Map<String, ConfigParameterInfo> parameterCheckers) 239 { 240 for (String id : parameterCheckers.keySet()) 241 { 242 ConfigParameterInfo info = parameterCheckers.get(id); 243 244 // Check if the parameter checker is not already declared 245 if (_declaredParamCheckers.containsKey(id)) 246 { 247 throw new IllegalArgumentException("The config parameter checker '" + id + "' is already declared. Parameter checkers ids must be unique."); 248 } 249 250 // Add the new parameter checker to the list of declared ones 251 _declaredParamCheckers.put(id, info); 252 253 _logger.debug("Parameter checker added: {}", id); 254 } 255 256 _logger.debug("{} parameter checker(s) added", parameterCheckers.size()); 257 } 258 259 /** 260 * Ends the initialization of the config parameters, by checking against the 261 * already valued parameters.<br> 262 * If at least one parameter has no value, the application won't start. 263 */ 264 public void parseAndValidate() 265 { 266 _logger.debug("Initialization"); 267 268 _isInitialized = false; 269 _isComplete = true; 270 271 ConfigParameterDefinitionParser parser = new ConfigParameterDefinitionParser(_configParameterTypeEP, _enumeratorManager, _validatorManager); 272 _parseParameters(parser); 273 274 ConfigParameterCheckerParser parameterCheckerParser = new ConfigParameterCheckerParser(_parameterCheckerManager); 275 _parseParameterCheckers(parameterCheckerParser); 276 277 _categorizeParameters(); 278 279 try 280 { 281 parser.lookupComponents(); 282 parameterCheckerParser.lookupComponents(); 283 } 284 catch (Exception e) 285 { 286 throw new RuntimeException("Unable to lookup parameter local components", e); 287 } 288 289 _validateParametersForReading(); 290 291 _usedParamIds.clear(); 292 _declaredParams.clear(); 293 _declaredParamCheckers.clear(); 294 295 _isInitialized = true; 296 297 Config.setInitialized(_isComplete); 298 299 _logger.debug("Initialization ended"); 300 } 301 302 private void _parseParameters(ConfigParameterDefinitionParser definitionParser) 303 { 304 ConfigParameterDefinitionWrapperParser parser = new ConfigParameterDefinitionWrapperParser(definitionParser); 305 for (String id : _usedParamIds) 306 { 307 // Check if the parameter is not already used 308 if (_configParameterWrappers.get(id) == null) 309 { 310 // Move the parameter from the unused list, to the used list 311 ConfigParameterInfo parameterInfo = _declaredParams.get(id); 312 313 if (parameterInfo == null) 314 { 315 throw new RuntimeException("The parameter '" + id + "' is used but not declared"); 316 } 317 318 ConfigParameterDefinitionWrapper configParameterWrapper = null; 319 320 try 321 { 322 configParameterWrapper = parser.parse(_serviceManager, parameterInfo.getPluginName(), parameterInfo.getConfiguration(), getInstance(), null); 323 } 324 catch (ConfigurationException ex) 325 { 326 throw new RuntimeException("Unable to configure the config parameter : " + id, ex); 327 } 328 329 _configParameterWrappers.put(id, configParameterWrapper); 330 } 331 } 332 } 333 334 private void _parseParameterCheckers(ConfigParameterCheckerParser parameterCheckerParser) 335 { 336 for (String id : _declaredParamCheckers.keySet()) 337 { 338 boolean invalidParameters = false; 339 340 // Check if the parameter checker is not already used 341 if (_parameterCheckers.get(id) == null) 342 { 343 ConfigParameterInfo info = _declaredParamCheckers.get(id); 344 345 ConfigParameterCheckerDescriptor parameterChecker = null; 346 try 347 { 348 349 parameterChecker = parameterCheckerParser.parseParameterChecker(info.getPluginName(), info.getConfiguration()); 350 } 351 catch (ConfigurationException ex) 352 { 353 throw new RuntimeException("Unable to configure the parameter checker: " + id, ex); 354 } 355 356 for (String linkedParameterPath : parameterChecker.getLinkedParamsPaths()) 357 { 358 ConfigParameterDefinitionWrapper linkedParameter = null; 359 360 // Linked parameters can be declared with an absolute path, in which case they are prefixed with '/ 361 if (linkedParameterPath.startsWith(ModelItem.ITEM_PATH_SEPARATOR)) 362 { 363 linkedParameter = _configParameterWrappers.get(linkedParameterPath.substring(ModelItem.ITEM_PATH_SEPARATOR.length())); 364 } 365 else 366 { 367 linkedParameter = _configParameterWrappers.get(linkedParameterPath); 368 } 369 370 // If at least one parameter used is invalid, the parameter checker is invalidated 371 if (linkedParameter == null) 372 { 373 invalidParameters = true; 374 break; 375 } 376 } 377 378 if (invalidParameters) 379 { 380 _logger.debug("All the configuration parameters associated to the parameter checker '{}' are not used.\nThis parameter checker will be ignored.", parameterChecker.getName()); 381 } 382 else 383 { 384 _parameterCheckers.put(id, parameterChecker); 385 } 386 } 387 } 388 } 389 390 private void _categorizeParameters() 391 { 392 Collection<ConfigParameterDefinitionWrapper> categorizedParameterProxiesValues = _configParameterWrappers.values(); 393 _categorizedDefinitions = ConfigParameterDefinitionHelper.categorizeConfigParameters(categorizedParameterProxiesValues); 394 _flatDefinitions = ConfigParameterDefinitionHelper.getFlatDefinitions(categorizedParameterProxiesValues); 395 396 // Add parameter checkers to categories, groups and element definitions 397 _addParameterCheckersToModelItems(); 398 } 399 400 private void _addParameterCheckersToModelItems() 401 { 402 for (ConfigParameterCheckerDescriptor parameterChecker: _parameterCheckers.values()) 403 { 404 I18nizableText uiCategory = parameterChecker.getUiRefCategory(); 405 if (uiCategory != null) 406 { 407 ModelItemGroup category = _getModelItemGroup(_categorizedDefinitions, uiCategory); 408 if (category == null) 409 { 410 _logger.warn("The category {} doesn't exist, thus the parameter checker {} will not be added.", uiCategory, parameterChecker.getName()); 411 } 412 else 413 { 414 I18nizableText uiGroup = parameterChecker.getUiRefGroup(); 415 if (uiGroup == null) 416 { 417 category.addItemChecker(parameterChecker); 418 } 419 else 420 { 421 ModelItemGroup group = _getModelItemGroup(category.getChildren(), uiGroup); 422 if (group == null) 423 { 424 _logger.warn("The group {} doesn't exist, thus the parameter checker {} will not be added.", uiGroup, parameterChecker.getName()); 425 } 426 else 427 { 428 group.addItemChecker(parameterChecker); 429 } 430 } 431 } 432 } 433 else 434 { 435 String uiParameterId = parameterChecker.getUiRefParamId(); 436 if (uiParameterId != null) 437 { 438 ElementDefinition definition = _flatDefinitions.get(uiParameterId); 439 if (definition == null) 440 { 441 _logger.warn("The parameter {} doesn't exist, thus the parameter checker {} will not be added.", uiParameterId, parameterChecker.getName()); 442 } 443 else 444 { 445 definition.addItemChecker(parameterChecker); 446 } 447 } 448 } 449 } 450 } 451 452 private ModelItemGroup _getModelItemGroup(List<ModelItem> items, I18nizableText itemGroupLabel) 453 { 454 for (ModelItem item : items) 455 { 456 if (itemGroupLabel.equals(item.getLabel()) && item instanceof ModelItemGroup) 457 { 458 return (ModelItemGroup) item; 459 } 460 } 461 462 return null; 463 } 464 465 private void _validateParametersForReading() 466 { 467 // Dispose potential previous parameters 468 Config.dispose(); 469 470 // Get configuration values 471 Map<String, Object> values = null; 472 try 473 { 474 Config.setModel(this); 475 Map<String, DefinitionAndValue> definitionAndValues = Config.__read(); 476 values = Config.__extractValues(definitionAndValues); 477 } 478 catch (Exception e) 479 { 480 _logger.error("Cannot read the configuration file.", e); 481 _isComplete = false; 482 } 483 484 if (_isComplete && values != null) 485 { 486 for (ElementDefinition definition : _flatDefinitions.values()) 487 { 488 boolean isGroupSwitchOn = ModelHelper.isGroupSwitchOn(definition, values); 489 boolean isDisabled = _disableConditionsEvaluator.evaluateDisableConditions(definition, definition.getName(), values); 490 491 if (isGroupSwitchOn && !isDisabled) 492 { 493 if (!values.containsKey(definition.getName())) 494 { 495 _logger.warn("The parameter '" + definition.getName() + "' is not valued. Configuration is not initialized."); 496 _isComplete = false; 497 } 498 else 499 { 500 Object value = values.get(definition.getName()); 501 ValidationResult result = ModelHelper.validateValue(definition, value); 502 if (result.hasErrors()) 503 { 504 if (_logger.isWarnEnabled()) 505 { 506 StringBuilder sb = new StringBuilder("The parameter '" + definition.getName() + "' is not valid with value '" + value + "' :"); 507 508 for (I18nizableText error : result.getErrors()) 509 { 510 sb.append("\n* " + error.toString()); 511 } 512 sb.append("\nConfiguration is not initialized"); 513 514 _logger.warn(sb.toString()); 515 } 516 517 _isComplete = false; 518 } 519 } 520 521 } 522 } 523 524 } 525 } 526 527 /** 528 * Update the configuration file with the given values<br> 529 * Values are untyped (all are of type String) and might be null. 530 * @param values A map (key, value). 531 * @param fileName the configuration file absolute path 532 * @return errors The fields in error 533 * @throws Exception If an error occurred while saving values 534 */ 535 public Map<String, List<I18nizableText>> save(Map<String, Object> values, String fileName) throws Exception 536 { 537 // Retrieve the old values for password purposes 538 Map<String, Object> oldValues = getOldValues(); 539 540 // Resolve each value and associate it to its definition 541 Map<String, Object> resolvedValues = _resolveValues(values, oldValues); 542 543 // Validate parameters 544 Map<String, List<I18nizableText>> errorFields = CategorizedElementDefinitionHelper.validateValuesForWriting(resolvedValues, _flatDefinitions.values(), _disableConditionsEvaluator, _logger) 545 .getAllErrors(); 546 if (!errorFields.isEmpty()) 547 { 548 return errorFields; 549 } 550 551 // SAX 552 _saxConfigurationFile(fileName, resolvedValues); 553 554 return Collections.EMPTY_MAP; 555 } 556 557 /** 558 * Retrieves old values if the configuration is not well initialized 559 * @return the old values 560 */ 561 public Map<String, Object> getOldValues() 562 { 563 if (Config.getInstance() == null) 564 { 565 try 566 { 567 Map<String, DefinitionAndValue> oldDefinitionAndValues = Config.__read(); 568 return Config.__extractValues(oldDefinitionAndValues); 569 } 570 catch (Exception e) 571 { 572 return new HashMap<>(); 573 } 574 } 575 576 return null; 577 } 578 579 private Map<String, Object> _resolveValues(Map<String, Object> values, Map<String, Object> oldValues) 580 { 581 Map<String, Object> resolvedValues = new HashMap<>(); 582 for (Map.Entry<String, Object> value : values.entrySet()) 583 { 584 ElementDefinition definition = _flatDefinitions.get(value.getKey()); 585 if (definition != null) 586 { 587 Object resolvedValue = _resolveValue(definition, value.getValue(), oldValues); 588 resolvedValues.put(value.getKey(), resolvedValue); 589 } 590 } 591 return resolvedValues; 592 } 593 594 /** 595 * Resolve the given value for the parameter check 596 * @param parameterName name of the parameter to resolve 597 * @param value the value to resolve 598 * @param oldValues the old values if the configuration is not initialized 599 * @return the resolved value as a String 600 */ 601 public String resolveValueForParameterChecker(String parameterName, Object value, Map<String, Object> oldValues) 602 { 603 ElementDefinition definition = _flatDefinitions.get(parameterName); 604 605 if (definition == null) 606 { 607 return null; 608 } 609 610 Object resolvedValue = _resolveValue(definition, value, oldValues); 611 return definition.getType().toString(resolvedValue); 612 } 613 614 private Object _resolveValue(ElementDefinition definition, Object value, Map<String, Object> oldValues) 615 { 616 String parameterId = definition.getName(); 617 ElementType type = definition.getType(); 618 Object resolvedValue = value; 619 620 // keeps the value of an empty password field 621 if (value == null && ModelItemTypeConstants.PASSWORD_ELEMENT_TYPE_ID.equals(type.getId())) 622 { 623 if (Config.getInstance() != null) 624 { 625 resolvedValue = Config.getInstance().getValue(parameterId); 626 } 627 else if (oldValues != null) 628 { 629 resolvedValue = oldValues.get(definition.getName()); 630 } 631 } 632 633 return resolvedValue; 634 } 635 636 private void _saxConfigurationFile(String fileName, Map<String, Object> values) throws TransformerFactoryConfigurationError, Exception 637 { 638 // create the result where to write 639 File outputFile = new File(fileName); 640 outputFile.getParentFile().mkdirs(); 641 642 try (OutputStream os = new FileOutputStream(fileName)) 643 { 644 // create a transformer for saving sax into a file 645 TransformerHandler th = ((SAXTransformerFactory) TransformerFactory.newInstance()).newTransformerHandler(); 646 647 StreamResult result = new StreamResult(os); 648 th.setResult(result); 649 650 // create the format of result 651 Properties format = new Properties(); 652 format.put(OutputKeys.METHOD, "xml"); 653 format.put(OutputKeys.INDENT, "yes"); 654 format.put(OutputKeys.ENCODING, "UTF-8"); 655 format.put(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, "2"); 656 th.getTransformer().setOutputProperties(format); 657 658 // sax the configuration into the transformer 659 _saxParameters(th, values); 660 } 661 catch (Exception e) 662 { 663 throw new Exception("An error occured while saving the config values.", e); 664 } 665 } 666 667 private void _saxParameters(TransformerHandler handler, Map<String, Object> values) throws SAXException 668 { 669 handler.startDocument(); 670 XMLUtils.startElement(handler, "config"); 671 672 673 // Iterate over categorized parameters 674 for (ModelItem category : _categorizedDefinitions) 675 { 676 if (!(category instanceof ModelItemGroup)) 677 { 678 // Should not happen, categories are created in categorizeParameters method 679 continue; 680 } 681 682 StringBuilder categoryLabel = new StringBuilder(); 683 categoryLabel.append("+\n | "); 684 categoryLabel.append(category.getLabel().toString()); 685 categoryLabel.append("\n +"); 686 687 // Comment on current category 688 XMLUtils.data(handler, "\n "); 689 handler.comment(categoryLabel.toString().toCharArray(), 0, categoryLabel.length()); 690 XMLUtils.data(handler, "\n"); 691 XMLUtils.data(handler, "\n"); 692 693 Iterator<ModelItem> groups = ((ModelItemGroup) category).getChildren().iterator(); 694 while (groups.hasNext()) 695 { 696 ModelItem group = groups.next(); 697 if (!(group instanceof ModelItemGroup)) 698 { 699 // Should not happen, groups are created in categorizeParameters method 700 continue; 701 } 702 703 StringBuilder groupLabel = new StringBuilder(); 704 groupLabel.append(" "); 705 groupLabel.append(group.getLabel().toString()); 706 groupLabel.append(" "); 707 708 // Comment on current group 709 XMLUtils.data(handler, " "); 710 handler.comment(groupLabel.toString().toCharArray(), 0, groupLabel.length()); 711 XMLUtils.data(handler, "\n "); 712 713 for (ModelItem definition : ((ModelItemGroup) group).getChildren()) 714 { 715 if (!(definition instanceof ElementDefinition)) 716 { 717 // Should not happen, parameter references are created in categorizeParameters method 718 continue; 719 } 720 721 Object value = values.get(definition.getName()); 722 ElementType<Object> type = ((ElementDefinition) definition).getType(); 723 724 if (!(type instanceof XMLElementType)) 725 { 726 // Should not happen, configuration parameters only work with XML element types 727 continue; 728 } 729 730 ((XMLElementType<Object>) type).write(handler, definition.getName(), value); 731 } 732 733 if (groups.hasNext()) 734 { 735 XMLUtils.data(handler, "\n"); 736 } 737 } 738 739 XMLUtils.data(handler, "\n"); 740 } 741 742 XMLUtils.endElement(handler, "config"); 743 handler.endDocument(); 744 } 745 746 /** 747 * Evaluate the {@link DisableConditions} of the given configuration parameter against the configuration values 748 * @param definition the configuration parameter 749 * @param config the {@link Config} instance 750 * @return <code>true</code> if the parameter is disabled, <code>false</code> otherwise 751 */ 752 public boolean evaluateDisableConditions(ElementDefinition definition, Config config) 753 { 754 return _disableConditionsEvaluator.evaluateDisableConditions(definition, definition.getName(), config); 755 } 756 757 public ModelItem getModelItem(String itemPath) throws UndefinedItemPathException 758 { 759 ModelItem item = _flatDefinitions.get(itemPath); 760 if (item != null) 761 { 762 return item; 763 } 764 else 765 { 766 throw new UndefinedItemPathException("The parameter '" + itemPath + "' is not defined in the configuration."); 767 } 768 } 769 770 /** 771 * Retrieves all configuration parameters 772 * @return all configuration parameters 773 */ 774 public Collection<ElementDefinition> getConfigurationParameters() 775 { 776 return _flatDefinitions.values(); 777 } 778 779 public Collection<ModelItem> getModelItems() 780 { 781 return _categorizedDefinitions; 782 } 783 784 /** 785 * Retrieves the view of Configuration 786 * @param i18nUtils the i18nUtils to use categories's sorting 787 * @return the configuration's view 788 */ 789 public View getView(I18nUtils i18nUtils) 790 { 791 Comparator<ModelItem> categoriesComparator = new I18nizableTextModelItemComparator(new I18nizableTextComparator(i18nUtils)); 792 Comparator<ModelItem> groupsComparator = new I18nizableTextModelItemComparator(new I18nizableTextKeyComparator()); 793 Comparator<ModelItem> elementsComparator = new ConfigParameterDefinitionComparator(_configParameterWrappers.values()); 794 795 return ConfigParameterDefinitionHelper.buildConfigParametersView(_categorizedDefinitions, categoriesComparator, groupsComparator, elementsComparator); 796 } 797 798 /** 799 * Gets the parameter checker with its id 800 * @param id the id of the parameter checker to get 801 * @return the associated parameter checker descriptor 802 */ 803 public ConfigParameterCheckerDescriptor getParameterChecker(String id) 804 { 805 return _parameterCheckers.get(id); 806 } 807 808 /** 809 * Returns true if the model is initialized and all parameters are valued 810 * @return true if the model is initialized and all parameters are valued 811 */ 812 public boolean isComplete() 813 { 814 return _isInitialized && _isComplete; 815 } 816 817 /** 818 * Returns true if the config file does not exist 819 * @return true if the config file does not exist 820 */ 821 public boolean isEmpty() 822 { 823 return !Config.fileExists(); 824 } 825 826 /** 827 * Dispose the manager before restarting it 828 */ 829 public void dispose() 830 { 831 _isInitialized = false; 832 _isComplete = true; 833 834 _usedParamIds = null; 835 _declaredParams = null; 836 _configParameterWrappers = null; 837 _declaredParamCheckers = null; 838 _parameterCheckers = null; 839 _flatDefinitions = null; 840 841 if (_validatorManager != null) 842 { 843 _validatorManager.dispose(); 844 _validatorManager = null; 845 } 846 if (_enumeratorManager != null) 847 { 848 _enumeratorManager.dispose(); 849 _enumeratorManager = null; 850 } 851 if (_parameterCheckerManager != null) 852 { 853 _parameterCheckerManager.dispose(); 854 _parameterCheckerManager = null; 855 } 856 } 857 858 public String getId() 859 { 860 return StringUtils.EMPTY; 861 } 862 863 public String getFamilyId() 864 { 865 return this.getClass().getName(); 866 } 867}