1 package org.apache.archiva.configuration;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.archiva.configuration.functors.ProxyConnectorConfigurationOrderComparator;
23 import org.apache.archiva.configuration.io.registry.ConfigurationRegistryReader;
24 import org.apache.archiva.configuration.io.registry.ConfigurationRegistryWriter;
25 import org.apache.archiva.policies.AbstractUpdatePolicy;
26 import org.apache.archiva.policies.CachedFailuresPolicy;
27 import org.apache.archiva.policies.ChecksumPolicy;
28 import org.apache.archiva.policies.DownloadErrorPolicy;
29 import org.apache.archiva.policies.Policy;
30 import org.apache.archiva.policies.PostDownloadPolicy;
31 import org.apache.archiva.policies.PreDownloadPolicy;
32 import org.apache.archiva.redback.components.evaluator.DefaultExpressionEvaluator;
33 import org.apache.archiva.redback.components.evaluator.EvaluatorException;
34 import org.apache.archiva.redback.components.evaluator.ExpressionEvaluator;
35 import org.apache.archiva.redback.components.evaluator.sources.SystemPropertyExpressionSource;
36 import org.apache.archiva.redback.components.registry.Registry;
37 import org.apache.archiva.redback.components.registry.RegistryException;
38 import org.apache.archiva.redback.components.registry.RegistryListener;
39 import org.apache.archiva.redback.components.registry.commons.CommonsConfigurationRegistry;
40 import org.apache.archiva.redback.components.springutils.ComponentContainer;
41 import org.apache.commons.collections4.CollectionUtils;
42 import org.apache.commons.collections4.ListUtils;
43 import org.apache.commons.collections4.MapUtils;
44 import org.apache.commons.configuration.BaseConfiguration;
45 import org.apache.commons.io.FileUtils;
46 import org.apache.commons.lang3.StringUtils;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import org.springframework.stereotype.Service;
51 import javax.annotation.PostConstruct;
52 import javax.inject.Inject;
53 import javax.inject.Named;
54 import java.io.IOException;
55 import java.nio.file.Files;
56 import java.nio.file.Path;
57 import java.nio.file.Paths;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Collection;
61 import java.util.Collections;
62 import java.util.HashMap;
63 import java.util.HashSet;
64 import java.util.Iterator;
65 import java.util.List;
66 import java.util.Locale;
68 import java.util.Map.Entry;
73 * Implementation of configuration holder that retrieves it from the registry.
76 * The registry layers and merges the 2 configuration files: user, and application server.
79 * Instead of relying on the model defaults, if the registry is empty a default configuration file is loaded and
80 * applied from a resource. The defaults are not loaded into the registry as the lists (eg repositories) could no longer
81 * be removed if that was the case.
84 * When saving the configuration, it is saved to the location it was read from. If it was read from the defaults, it
85 * will be saved to the user location.
86 * However, if the configuration contains information from both sources, an exception is raised as this is currently
87 * unsupported. The reason for this is that it is not possible to identify where to re-save elements, and can result
88 * in list configurations (eg repositories) becoming inconsistent.
91 * If the configuration is outdated, it will be upgraded when it is loaded. This is done by checking the version flag
92 * before reading it from the registry.
94 * FIXME: The synchronization must be improved, the current impl may lead to inconsistent data or multiple getConfiguration() calls (martin_s@apache.org)
97 @Service("archivaConfiguration#default")
98 public class DefaultArchivaConfiguration
99 implements ArchivaConfiguration, RegistryListener {
100 private final Logger log = LoggerFactory.getLogger(DefaultArchivaConfiguration.class);
102 private static String FILE_ENCODING = "UTF-8";
105 * Plexus registry to read the configuration from.
108 @Named(value = "commons-configuration")
109 private Registry registry;
112 private ComponentContainer componentContainer;
115 * The configuration that has been converted.
117 private Configuration configuration;
122 * @todo these don't strictly belong in here
124 private Map<String, PreDownloadPolicy> prePolicies;
129 * @todo these don't strictly belong in here
131 private Map<String, PostDownloadPolicy> postPolicies;
136 * @todo these don't strictly belong in here
138 private Map<String, DownloadErrorPolicy> downloadErrorPolicies;
143 * default-value="${user.home}/.m2/archiva.xml"
145 private String userConfigFilename = "${user.home}/.m2/archiva.xml";
149 * default-value="${appserver.base}/conf/archiva.xml"
151 private String altConfigFilename = "${appserver.base}/conf/archiva.xml";
154 * Configuration Listeners we've registered.
156 private Set<ConfigurationListener> listeners = new HashSet<>();
159 * Registry Listeners we've registered.
161 private Set<RegistryListener> registryListeners = new HashSet<>();
164 * Boolean to help determine if the configuration exists as a result of pulling in
165 * the default-archiva.xml
167 private boolean isConfigurationDefaulted = false;
169 private static final String KEY = "org.apache.archiva";
171 // Section used for default only configuration
172 private static final String KEY_DEFAULT_ONLY = "org.apache.archiva_default";
174 private Locale defaultLocale = Locale.getDefault();
176 private List<Locale.LanguageRange> languagePriorities = new ArrayList<>();
178 private volatile Path dataDirectory;
179 private volatile Path repositoryBaseDirectory;
180 private volatile Path remoteRepositoryBaseDirectory;
181 private volatile Path repositoryGroupBaseDirectory;
184 private void init() {
185 languagePriorities = Locale.LanguageRange.parse("en,fr,de");
190 public Configuration getConfiguration() {
191 return loadConfiguration();
194 private synchronized Configuration loadConfiguration() {
195 if (configuration == null) {
196 configuration = load();
197 configuration = unescapeExpressions(configuration);
198 if (isConfigurationDefaulted) {
199 configuration = checkRepositoryLocations(configuration);
203 return configuration;
206 private boolean hasConfigVersionChanged(Configuration current, Registry defaultOnlyConfiguration) {
207 return current == null || current.getVersion() == null ||
208 !current.getVersion().trim().equals(defaultOnlyConfiguration.getString("version", "").trim());
211 @SuppressWarnings("unchecked")
212 private Configuration load() {
213 // TODO: should this be the same as section? make sure unnamed sections still work (eg, sys properties)
214 Registry subset = registry.getSubset(KEY);
215 if (subset.getString("version") == null) {
216 if (subset.getSubset("repositoryScanning").isEmpty()) {
218 subset = readDefaultConfiguration();
220 throw new RuntimeException("No version tag found in configuration. Archiva configuration version 1.x is not longer supported.");
224 Configuration config = new ConfigurationRegistryReader().read(subset);
226 // Resolving data and repositories directories
227 // If the config entries are absolute, the path is used as it is
228 // if the config entries are empty, they are resolved:
229 // dataDirectory = ${appserver.base}/data
230 // repositoryDirectory = ${dataDirectory}/repositories
231 // If the entries are relative they are resolved
232 // relative to the appserver.base, for dataDirectory
233 // relative to dataDirectory for repositoryBase
234 String dataDir = config.getArchivaRuntimeConfiguration().getDataDirectory();
235 if (StringUtils.isEmpty(dataDir)) {
236 dataDirectory = getAppServerBaseDir().resolve("data");
238 Path tmpDataDir = Paths.get(dataDir);
239 if (tmpDataDir.isAbsolute()) {
240 dataDirectory = tmpDataDir;
242 dataDirectory = getAppServerBaseDir().resolve(tmpDataDir);
245 config.getArchivaRuntimeConfiguration().setDataDirectory(dataDirectory.normalize().toString());
246 String repoBaseDir = config.getArchivaRuntimeConfiguration().getRepositoryBaseDirectory();
247 if (StringUtils.isEmpty(repoBaseDir)) {
248 repositoryBaseDirectory = dataDirectory.resolve("repositories");
251 Path tmpRepoBaseDir = Paths.get(repoBaseDir);
252 if (tmpRepoBaseDir.isAbsolute()) {
253 repositoryBaseDirectory = tmpRepoBaseDir;
255 dataDirectory.resolve(tmpRepoBaseDir);
259 String remoteRepoBaseDir = config.getArchivaRuntimeConfiguration().getRemoteRepositoryBaseDirectory();
260 if (StringUtils.isEmpty(remoteRepoBaseDir)) {
261 remoteRepositoryBaseDirectory = dataDirectory.resolve("remotes");
263 Path tmpRemoteRepoDir = Paths.get(remoteRepoBaseDir);
264 if (tmpRemoteRepoDir.isAbsolute()) {
265 remoteRepositoryBaseDirectory = tmpRemoteRepoDir;
267 dataDirectory.resolve(tmpRemoteRepoDir);
271 String repositoryGroupBaseDir = config.getArchivaRuntimeConfiguration().getRepositoryGroupBaseDirectory();
272 if (StringUtils.isEmpty(repositoryGroupBaseDir)) {
273 repositoryGroupBaseDirectory = dataDirectory.resolve("groups");
275 Path tmpGroupDir = Paths.get(repositoryGroupBaseDir);
276 if (tmpGroupDir.isAbsolute()) {
277 repositoryGroupBaseDirectory = tmpGroupDir;
279 dataDirectory.resolve(tmpGroupDir);
284 config.getRepositoryGroups();
285 config.getRepositoryGroupsAsMap();
286 if (!CollectionUtils.isEmpty(config.getRemoteRepositories())) {
287 List<RemoteRepositoryConfiguration> remoteRepos = config.getRemoteRepositories();
288 for (RemoteRepositoryConfiguration repo : remoteRepos) {
289 // [MRM-582] Remote Repositories with empty <username> and <password> fields shouldn't be created in configuration.
290 if (StringUtils.isBlank(repo.getUsername())) {
291 repo.setUsername(null);
294 if (StringUtils.isBlank(repo.getPassword())) {
295 repo.setPassword(null);
300 if (!config.getProxyConnectors().isEmpty()) {
301 // Fix Proxy Connector Settings.
303 // Create a copy of the list to read from (to prevent concurrent modification exceptions)
304 List<ProxyConnectorConfiguration> proxyConnectorList = new ArrayList<>(config.getProxyConnectors());
305 // Remove the old connector list.
306 config.getProxyConnectors().clear();
308 for (ProxyConnectorConfiguration connector : proxyConnectorList) {
310 boolean connectorValid = true;
312 Map<String, String> policies = new HashMap<>();
313 // Make copy of policies
314 policies.putAll(connector.getPolicies());
315 // Clear out policies
316 connector.getPolicies().clear();
318 // Work thru policies. cleaning them up.
319 for (Entry<String, String> entry : policies.entrySet()) {
320 String policyId = entry.getKey();
321 String setting = entry.getValue();
323 // Upgrade old policy settings.
324 if ("releases".equals(policyId) || "snapshots".equals(policyId)) {
325 if ("ignored".equals(setting)) {
326 setting = AbstractUpdatePolicy.ALWAYS.getId();
327 } else if ("disabled".equals(setting)) {
328 setting = AbstractUpdatePolicy.NEVER.getId();
330 } else if ("cache-failures".equals(policyId)) {
331 if ("ignored".equals(setting)) {
332 setting = CachedFailuresPolicy.NO.getId();
333 } else if ("cached".equals(setting)) {
334 setting = CachedFailuresPolicy.YES.getId();
336 } else if ("checksum".equals(policyId)) {
337 if ("ignored".equals(setting)) {
338 setting = ChecksumPolicy.IGNORE.getId();
342 // Validate existance of policy key.
343 if (policyExists(policyId)) {
344 Policy policy = findPolicy(policyId);
345 // Does option exist?
346 if (!policy.getOptions().contains(setting)) {
347 setting = policy.getDefaultOption().getId();
349 connector.addPolicy(policyId, setting);
351 // Policy key doesn't exist. Don't add it to golden version.
352 log.warn("Policy [{}] does not exist.", policyId);
356 if (connectorValid) {
357 config.addProxyConnector(connector);
361 // Normalize the order fields in the proxy connectors.
362 Map<String, java.util.List<ProxyConnectorConfiguration>> proxyConnectorMap =
363 config.getProxyConnectorAsMap();
365 for (List<ProxyConnectorConfiguration> connectors : proxyConnectorMap.values()) {
366 // Sort connectors by order field.
367 Collections.sort(connectors, ProxyConnectorConfigurationOrderComparator.getInstance());
369 // Normalize the order field values.
371 for (ProxyConnectorConfiguration connector : connectors) {
372 connector.setOrder(order++);
377 this.defaultLocale = Locale.forLanguageTag(config.getArchivaRuntimeConfiguration().getDefaultLanguage());
378 this.languagePriorities = Locale.LanguageRange.parse(config.getArchivaRuntimeConfiguration().getLanguageRange());
383 * Updates the checkpath list for repositories.
385 * We are replacing existing ones and adding new ones. This allows to update the list with new releases.
387 * We are also updating existing remote repositories, if they exist already.
389 * This update method should only be called, if the config version changes to avoid overwriting
390 * user repository settings all the time.
392 private void updateCheckPathDefaults(Configuration config, Registry defaultConfiguration) {
393 List<RepositoryCheckPath> existingCheckPathList = config.getArchivaDefaultConfiguration().getDefaultCheckPaths();
394 HashMap<String, RepositoryCheckPath> existingCheckPaths = new HashMap<>();
395 HashMap<String, RepositoryCheckPath> newCheckPaths = new HashMap<>();
396 for (RepositoryCheckPath path : config.getArchivaDefaultConfiguration().getDefaultCheckPaths()) {
397 existingCheckPaths.put(path.getUrl(), path);
399 List defaultCheckPathsSubsets = defaultConfiguration.getSubsetList("archivaDefaultConfiguration.defaultCheckPaths.defaultCheckPath");
400 for (Iterator i = defaultCheckPathsSubsets.iterator(); i.hasNext(); ) {
401 RepositoryCheckPath v = readRepositoryCheckPath((Registry) i.next());
402 if (existingCheckPaths.containsKey(v.getUrl())) {
403 existingCheckPathList.remove(existingCheckPaths.get(v.getUrl()));
405 existingCheckPathList.add(v);
406 newCheckPaths.put(v.getUrl(), v);
408 // Remote repositories update
409 for (RemoteRepositoryConfiguration remoteRepositoryConfiguration : config.getRemoteRepositories()) {
410 String url = remoteRepositoryConfiguration.getUrl().toLowerCase();
411 if (newCheckPaths.containsKey(url)) {
412 String currentPath = remoteRepositoryConfiguration.getCheckPath();
413 String newPath = newCheckPaths.get(url).getPath();
414 log.info("Updating connection check path for repository {}, from '{}' to '{}'.", remoteRepositoryConfiguration.getId(),
415 currentPath, newPath);
416 remoteRepositoryConfiguration.setCheckPath(newPath);
421 private RepositoryCheckPath readRepositoryCheckPath(Registry registry) {
422 RepositoryCheckPath value = new RepositoryCheckPath();
424 String url = registry.getString("url", value.getUrl());
427 String path = registry.getString("path", value.getPath());
432 private Policy findPolicy(String policyId) {
433 if (MapUtils.isEmpty(prePolicies)) {
434 log.error("No PreDownloadPolicies found!");
438 if (MapUtils.isEmpty(postPolicies)) {
439 log.error("No PostDownloadPolicies found!");
445 policy = prePolicies.get(policyId);
446 if (policy != null) {
450 policy = postPolicies.get(policyId);
451 if (policy != null) {
455 policy = downloadErrorPolicies.get(policyId);
456 if (policy != null) {
463 private boolean policyExists(String policyId) {
464 if (MapUtils.isEmpty(prePolicies)) {
465 log.error("No PreDownloadPolicies found!");
469 if (MapUtils.isEmpty(postPolicies)) {
470 log.error("No PostDownloadPolicies found!");
474 return (prePolicies.containsKey(policyId) || postPolicies.containsKey(policyId)
475 || downloadErrorPolicies.containsKey(policyId));
478 private Registry readDefaultConfiguration() {
479 // if it contains some old configuration, remove it (Archiva 0.9)
480 registry.removeSubset(KEY);
483 registry.addConfigurationFromResource("org/apache/archiva/configuration/default-archiva.xml", KEY);
484 this.isConfigurationDefaulted = true;
485 } catch (RegistryException e) {
486 throw new ConfigurationRuntimeException(
487 "Fatal error: Unable to find the built-in default configuration and load it into the registry", e);
489 return registry.getSubset(KEY);
493 * Reads the default only configuration into a special prefix. This allows to check for changes
494 * of the default configuration.
496 private Registry readDefaultOnlyConfiguration() {
497 registry.removeSubset(KEY_DEFAULT_ONLY);
499 registry.addConfigurationFromResource("org/apache/archiva/configuration/default-archiva.xml", KEY_DEFAULT_ONLY);
500 } catch (RegistryException e) {
501 throw new ConfigurationRuntimeException(
502 "Fatal error: Unable to find the built-in default configuration and load it into the registry", e);
504 return registry.getSubset(KEY_DEFAULT_ONLY);
507 @SuppressWarnings("unchecked")
509 public synchronized void save(Configuration configuration)
510 throws IndeterminateConfigurationException, RegistryException {
511 Registry section = registry.getSection(KEY + ".user");
512 Registry baseSection = registry.getSection(KEY + ".base");
513 if (section == null) {
514 section = baseSection;
515 if (section == null) {
516 section = createDefaultConfigurationFile();
518 } else if (baseSection != null) {
519 Collection<String> keys = baseSection.getKeys();
520 boolean foundList = false;
521 for (Iterator<String> i = keys.iterator(); i.hasNext() && !foundList; ) {
522 String key = i.next();
524 // a little aggressive with the repositoryScanning and databaseScanning - should be no need to split
525 // that configuration
526 if (key.startsWith("repositories") //
527 || key.startsWith("proxyConnectors") //
528 || key.startsWith("networkProxies") //
529 || key.startsWith("repositoryScanning") //
530 || key.startsWith("remoteRepositories") //
531 || key.startsWith("managedRepositories") //
532 || key.startsWith("repositoryGroups")) //
539 this.configuration = null;
541 throw new IndeterminateConfigurationException(
542 "Configuration can not be saved when it is loaded from two sources");
546 // escape all cron expressions to handle ','
547 escapeCronExpressions(configuration);
549 // [MRM-661] Due to a bug in the modello registry writer, we need to take these out by hand. They'll be put back by the writer.
550 if (section != null) {
551 if (configuration.getManagedRepositories().isEmpty()) {
552 section.removeSubset("managedRepositories");
554 if (configuration.getRemoteRepositories().isEmpty()) {
555 section.removeSubset("remoteRepositories");
558 if (configuration.getProxyConnectors().isEmpty()) {
559 section.removeSubset("proxyConnectors");
561 if (configuration.getNetworkProxies().isEmpty()) {
562 section.removeSubset("networkProxies");
564 if (configuration.getLegacyArtifactPaths().isEmpty()) {
565 section.removeSubset("legacyArtifactPaths");
567 if (configuration.getRepositoryGroups().isEmpty()) {
568 section.removeSubset("repositoryGroups");
570 if (configuration.getRepositoryScanning() != null) {
571 if (configuration.getRepositoryScanning().getKnownContentConsumers().isEmpty()) {
572 section.removeSubset("repositoryScanning.knownContentConsumers");
574 if (configuration.getRepositoryScanning().getInvalidContentConsumers().isEmpty()) {
575 section.removeSubset("repositoryScanning.invalidContentConsumers");
578 if (configuration.getArchivaRuntimeConfiguration() != null) {
579 section.removeSubset("archivaRuntimeConfiguration.defaultCheckPaths");
582 new ConfigurationRegistryWriter().write(configuration, section);
587 this.configuration = unescapeExpressions(configuration);
588 isConfigurationDefaulted = false;
590 triggerEvent(ConfigurationEvent.SAVED);
593 private void escapeCronExpressions(Configuration configuration) {
594 for (ManagedRepositoryConfiguration c : configuration.getManagedRepositories()) {
595 c.setRefreshCronExpression(escapeCronExpression(c.getRefreshCronExpression()));
599 private Registry createDefaultConfigurationFile()
600 throws RegistryException {
601 // TODO: may not be needed under commons-configuration 1.4 - check
603 String contents = "<configuration />";
605 String fileLocation = userConfigFilename;
607 if (!writeFile("user configuration", userConfigFilename, contents)) {
608 fileLocation = altConfigFilename;
609 if (!writeFile("alternative configuration", altConfigFilename, contents, true)) {
610 throw new RegistryException(
611 "Unable to create configuration file in either user [" + userConfigFilename + "] or alternative ["
613 + "] locations on disk, usually happens when not allowed to write to those locations.");
617 // olamy hackish I know :-)
618 contents = "<configuration><xml fileName=\"" + fileLocation
619 + "\" config-forceCreate=\"true\" config-name=\"org.apache.archiva.user\"/>" + "</configuration>";
621 ((CommonsConfigurationRegistry) registry).setProperties(contents);
623 registry.initialize();
625 for (RegistryListener regListener : registryListeners) {
626 addRegistryChangeListener(regListener);
629 triggerEvent(ConfigurationEvent.SAVED);
631 Registry section = registry.getSection(KEY + ".user");
632 return section == null ? new CommonsConfigurationRegistry(new BaseConfiguration()) : section;
635 private boolean writeFile(String filetype, String path, String contents) {
636 return writeFile( filetype, path, contents, false );
640 * Attempts to write the contents to a file, if an IOException occurs, return false.
642 * The file will be created if the directory to the file exists, otherwise this will return false.
644 * @param filetype the filetype (freeform text) to use in logging messages when failure to write.
645 * @param path the path to write to.
646 * @param contents the contents to write.
647 * @return true if write successful.
649 private boolean writeFile(String filetype, String path, String contents, boolean createDirs) {
650 Path file = Paths.get(path);
653 // Check parent directory (if it is declared)
654 final Path parent = file.getParent();
655 if (parent != null) {
656 // Check that directory exists
657 if (!Files.exists( parent ) && createDirs) {
658 Files.createDirectories( parent );
660 if (!Files.isDirectory(parent)) {
661 // Directory to file must exist for file to be created
665 FileUtils.writeStringToFile(file.toFile(), contents, FILE_ENCODING);
667 } catch (IOException e) {
668 log.error("Unable to create {} file: {}", filetype, e.getMessage(), e);
673 private void triggerEvent(int type) {
674 ConfigurationEvent evt = new ConfigurationEvent(type);
675 for (ConfigurationListener listener : listeners) {
676 listener.configurationEvent(evt);
681 public void addListener(ConfigurationListener listener) {
682 if (listener == null) {
686 listeners.add(listener);
690 public void removeListener(ConfigurationListener listener) {
691 if (listener == null) {
695 listeners.remove(listener);
700 public void addChangeListener(RegistryListener listener) {
701 addRegistryChangeListener(listener);
703 // keep track for later
704 registryListeners.add(listener);
707 private void addRegistryChangeListener(RegistryListener listener) {
708 Registry section = registry.getSection(KEY + ".user");
709 if (section != null) {
710 section.addChangeListener(listener);
712 section = registry.getSection(KEY + ".base");
713 if (section != null) {
714 section.addChangeListener(listener);
719 public void removeChangeListener(RegistryListener listener) {
720 boolean removed = registryListeners.remove(listener);
721 log.debug("RegistryListener: '{}' removed {}", listener, removed);
723 Registry section = registry.getSection(KEY + ".user");
724 if (section != null) {
725 section.removeChangeListener(listener);
727 section = registry.getSection(KEY + ".base");
728 if (section != null) {
729 section.removeChangeListener(listener);
735 public void initialize() {
737 this.postPolicies = componentContainer.buildMapWithRole(PostDownloadPolicy.class);
738 this.prePolicies = componentContainer.buildMapWithRole(PreDownloadPolicy.class);
739 this.downloadErrorPolicies = componentContainer.buildMapWithRole(DownloadErrorPolicy.class);
740 // Resolve expressions in the userConfigFilename and altConfigFilename
742 ExpressionEvaluator expressionEvaluator = new DefaultExpressionEvaluator();
743 expressionEvaluator.addExpressionSource(new SystemPropertyExpressionSource());
744 String userConfigFileNameSysProps = System.getProperty(USER_CONFIG_PROPERTY);
745 if (StringUtils.isNotBlank(userConfigFileNameSysProps)) {
746 userConfigFilename = userConfigFileNameSysProps;
748 String userConfigFileNameEnv = System.getenv(USER_CONFIG_ENVVAR);
749 if (StringUtils.isNotBlank(userConfigFileNameEnv)) {
750 userConfigFilename = userConfigFileNameEnv;
752 userConfigFilename = expressionEvaluator.expand(userConfigFilename);
755 altConfigFilename = expressionEvaluator.expand(altConfigFilename);
757 handleUpgradeConfiguration();
758 } catch (IndeterminateConfigurationException | RegistryException e) {
759 throw new RuntimeException("failed during upgrade from previous version" + e.getMessage(), e);
760 } catch (EvaluatorException e) {
761 throw new RuntimeException(
762 "Unable to evaluate expressions found in " + "userConfigFilename or altConfigFilename.", e);
764 registry.addChangeListener(this);
768 * Handle upgrade to newer version
770 private void handleUpgradeConfiguration()
771 throws RegistryException, IndeterminateConfigurationException {
773 List<String> dbConsumers = Arrays.asList("update-db-artifact", "update-db-repository-metadata");
775 // remove database consumers if here
776 List<String> intersec =
777 ListUtils.intersection(dbConsumers, configuration.getRepositoryScanning().getKnownContentConsumers());
779 if (!intersec.isEmpty()) {
781 List<String> knowContentConsumers =
782 new ArrayList<>(configuration.getRepositoryScanning().getKnownContentConsumers().size());
783 for (String knowContentConsumer : configuration.getRepositoryScanning().getKnownContentConsumers()) {
784 if (!dbConsumers.contains(knowContentConsumer)) {
785 knowContentConsumers.add(knowContentConsumer);
789 configuration.getRepositoryScanning().setKnownContentConsumers(knowContentConsumers);
792 // ensure create-archiva-metadata is here
793 if (!configuration.getRepositoryScanning().getKnownContentConsumers().contains("create-archiva-metadata")) {
794 List<String> knowContentConsumers =
795 new ArrayList<>(configuration.getRepositoryScanning().getKnownContentConsumers());
796 knowContentConsumers.add("create-archiva-metadata");
797 configuration.getRepositoryScanning().setKnownContentConsumers(knowContentConsumers);
800 // ensure duplicate-artifacts is here
801 if (!configuration.getRepositoryScanning().getKnownContentConsumers().contains("duplicate-artifacts")) {
802 List<String> knowContentConsumers =
803 new ArrayList<>(configuration.getRepositoryScanning().getKnownContentConsumers());
804 knowContentConsumers.add("duplicate-artifacts");
805 configuration.getRepositoryScanning().setKnownContentConsumers(knowContentConsumers);
808 Registry defaultOnlyConfiguration = readDefaultOnlyConfiguration();
809 // Currently we check only for configuration version change, not certain version numbers.
810 if (hasConfigVersionChanged(configuration, defaultOnlyConfiguration)) {
811 updateCheckPathDefaults(configuration, defaultOnlyConfiguration);
812 String newVersion = defaultOnlyConfiguration.getString("version");
813 if (newVersion == null) {
814 throw new IndeterminateConfigurationException("The default configuration has no version information!");
816 configuration.setVersion(newVersion);
819 } catch (IndeterminateConfigurationException e) {
820 log.error("Error occured during configuration update to new version: {}", e.getMessage());
821 } catch (RegistryException e) {
822 log.error("Error occured during configuration update to new version: {}", e.getMessage());
828 public void reload() {
829 this.configuration = null;
831 this.registry.initialize();
832 } catch (RegistryException e) {
833 throw new ConfigurationRuntimeException(e.getMessage(), e);
839 public Locale getDefaultLocale() {
840 return defaultLocale;
844 public List<Locale.LanguageRange> getLanguagePriorities() {
845 return languagePriorities;
849 public Path getAppServerBaseDir() {
850 String basePath = registry.getString("appserver.base");
851 if (!StringUtils.isEmpty(basePath)) {
852 return Paths.get(basePath);
854 return Paths.get("");
859 public Path getRepositoryBaseDir() {
860 if (repositoryBaseDirectory == null) {
863 return repositoryBaseDirectory;
868 public Path getRemoteRepositoryBaseDir() {
869 if (remoteRepositoryBaseDirectory == null) {
872 return remoteRepositoryBaseDirectory;
876 public Path getRepositoryGroupBaseDir() {
877 if (repositoryGroupBaseDirectory == null) {
880 return repositoryGroupBaseDirectory;
884 public Path getDataDirectory() {
885 if (dataDirectory == null) {
888 return dataDirectory;
892 public void beforeConfigurationChange(Registry registry, String propertyName, Object propertyValue) {
893 // nothing to do here
897 public synchronized void afterConfigurationChange(Registry registry, String propertyName, Object propertyValue) {
898 configuration = null;
899 this.dataDirectory = null;
900 this.repositoryBaseDirectory = null;
903 private String removeExpressions(String directory) {
904 String value = StringUtils.replace(directory, "${appserver.base}",
905 registry.getString("appserver.base", "${appserver.base}"));
906 value = StringUtils.replace(value, "${appserver.home}",
907 registry.getString("appserver.home", "${appserver.home}"));
911 private String unescapeCronExpression(String cronExpression) {
912 return StringUtils.replace(cronExpression, "\\,", ",");
915 private String escapeCronExpression(String cronExpression) {
916 return StringUtils.replace(cronExpression, ",", "\\,");
919 private Configuration unescapeExpressions(Configuration config) {
920 // TODO: for commons-configuration 1.3 only
921 for (ManagedRepositoryConfiguration c : config.getManagedRepositories()) {
922 c.setLocation(removeExpressions(c.getLocation()));
923 c.setRefreshCronExpression(unescapeCronExpression(c.getRefreshCronExpression()));
929 private Configuration checkRepositoryLocations(Configuration config) {
930 // additional check for [MRM-789], ensure that the location of the default repositories
931 // are not installed in the server installation
932 for (ManagedRepositoryConfiguration repo : (List<ManagedRepositoryConfiguration>) config.getManagedRepositories()) {
933 String repoPath = repo.getLocation();
934 Path repoLocation = Paths.get(repoPath);
936 if (Files.exists(repoLocation) && Files.isDirectory(repoLocation) && !repoPath.endsWith(
937 "data/repositories/" + repo.getId())) {
938 repo.setLocation(repoPath + "/data/repositories/" + repo.getId());
945 public String getUserConfigFilename() {
946 return userConfigFilename;
949 public String getAltConfigFilename() {
950 return altConfigFilename;
954 public boolean isDefaulted() {
955 return this.isConfigurationDefaulted;
958 public Registry getRegistry() {
962 public void setRegistry(Registry registry) {
963 this.registry = registry;
967 public void setUserConfigFilename(String userConfigFilename) {
968 this.userConfigFilename = userConfigFilename;
971 public void setAltConfigFilename(String altConfigFilename) {
972 this.altConfigFilename = altConfigFilename;