| package org.apache.archiva.configuration; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.archiva.configuration.functors.ProxyConnectorConfigurationOrderComparator; |
| import org.apache.archiva.configuration.io.registry.ConfigurationRegistryReader; |
| import org.apache.archiva.configuration.io.registry.ConfigurationRegistryWriter; |
| import org.apache.archiva.policies.AbstractUpdatePolicy; |
| import org.apache.archiva.policies.CachedFailuresPolicy; |
| import org.apache.archiva.policies.ChecksumPolicy; |
| import org.apache.archiva.components.evaluator.DefaultExpressionEvaluator; |
| import org.apache.archiva.components.evaluator.EvaluatorException; |
| import org.apache.archiva.components.evaluator.ExpressionEvaluator; |
| import org.apache.archiva.components.evaluator.sources.SystemPropertyExpressionSource; |
| import org.apache.archiva.components.registry.Registry; |
| import org.apache.archiva.components.registry.RegistryException; |
| import org.apache.archiva.components.registry.RegistryListener; |
| import org.apache.archiva.components.registry.commons.CommonsConfigurationRegistry; |
| import org.apache.commons.collections4.CollectionUtils; |
| import org.apache.commons.collections4.ListUtils; |
| import org.apache.commons.io.FileUtils; |
| import org.apache.commons.lang3.StringUtils; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.springframework.stereotype.Service; |
| |
| import javax.annotation.PostConstruct; |
| import javax.inject.Inject; |
| import javax.inject.Named; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.*; |
| import java.util.Map.Entry; |
| |
| /** |
| * <p> |
| * Implementation of configuration holder that retrieves it from the registry. |
| * </p> |
| * <p> |
| * The registry layers and merges the 2 configuration files: user, and application server. |
| * </p> |
| * <p> |
| * Instead of relying on the model defaults, if the registry is empty a default configuration file is loaded and |
| * applied from a resource. The defaults are not loaded into the registry as the lists (eg repositories) could no longer |
| * be removed if that was the case. |
| * </p> |
| * <p> |
| * When saving the configuration, it is saved to the location it was read from. If it was read from the defaults, it |
| * will be saved to the user location. |
| * However, if the configuration contains information from both sources, an exception is raised as this is currently |
| * unsupported. The reason for this is that it is not possible to identify where to re-save elements, and can result |
| * in list configurations (eg repositories) becoming inconsistent. |
| * </p> |
| * <p> |
| * If the configuration is outdated, it will be upgraded when it is loaded. This is done by checking the version flag |
| * before reading it from the registry. |
| * <p> |
| * FIXME: The synchronization must be improved, the current impl may lead to inconsistent data or multiple getConfiguration() calls (martin_s@apache.org) |
| * </p> |
| */ |
| @Service("archivaConfiguration#default") |
| public class DefaultArchivaConfiguration |
| implements ArchivaConfiguration, RegistryListener { |
| private final Logger log = LoggerFactory.getLogger(DefaultArchivaConfiguration.class); |
| |
| private static String FILE_ENCODING = "UTF-8"; |
| |
| /** |
| * Plexus registry to read the configuration from. |
| */ |
| @Inject |
| @Named(value = "commons-configuration") |
| private Registry registry; |
| |
| /** |
| * The configuration that has been converted. |
| */ |
| private Configuration configuration; |
| |
| /** |
| * see #initialize |
| * default-value="${user.home}/.m2/archiva.xml" |
| */ |
| private String userConfigFilename = "${user.home}/.m2/archiva.xml"; |
| |
| /** |
| * see #initialize |
| * default-value="${appserver.base}/conf/archiva.xml" |
| */ |
| private String altConfigFilename = "${appserver.base}/conf/archiva.xml"; |
| |
| /** |
| * Configuration Listeners we've registered. |
| */ |
| private Set<ConfigurationListener> listeners = new HashSet<>(); |
| |
| /** |
| * Registry Listeners we've registered. |
| */ |
| private Set<RegistryListener> registryListeners = new HashSet<>(); |
| |
| /** |
| * Boolean to help determine if the configuration exists as a result of pulling in |
| * the default-archiva.xml |
| */ |
| private boolean isConfigurationDefaulted = false; |
| |
| private static final String KEY = "org.apache.archiva"; |
| |
| // Section used for default only configuration |
| private static final String KEY_DEFAULT_ONLY = "org.apache.archiva_default"; |
| |
| private Locale defaultLocale = Locale.getDefault(); |
| |
| private List<Locale.LanguageRange> languagePriorities = new ArrayList<>(); |
| |
| private volatile Path dataDirectory; |
| private volatile Path repositoryBaseDirectory; |
| private volatile Path remoteRepositoryBaseDirectory; |
| private volatile Path repositoryGroupBaseDirectory; |
| |
| @PostConstruct |
| private void init() { |
| languagePriorities = Locale.LanguageRange.parse("en,fr,de"); |
| } |
| |
| |
| @Override |
| public Configuration getConfiguration() { |
| return loadConfiguration(); |
| } |
| |
| private synchronized Configuration loadConfiguration() { |
| if (configuration == null) { |
| configuration = load(); |
| configuration = unescapeExpressions(configuration); |
| if (isConfigurationDefaulted) { |
| configuration = checkRepositoryLocations(configuration); |
| } |
| } |
| |
| return configuration; |
| } |
| |
| private boolean hasConfigVersionChanged(Configuration current, Registry defaultOnlyConfiguration) { |
| return current == null || current.getVersion() == null || |
| !current.getVersion().trim().equals(defaultOnlyConfiguration.getString("version", "").trim()); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private Configuration load() { |
| // TODO: should this be the same as section? make sure unnamed sections still work (eg, sys properties) |
| Registry subset = registry.getSubset(KEY); |
| if (subset.getString("version") == null) { |
| if (subset.getSubset("repositoryScanning").isEmpty()) { |
| // only for empty |
| subset = readDefaultConfiguration(); |
| } else { |
| throw new RuntimeException("No version tag found in configuration. Archiva configuration version 1.x is not longer supported."); |
| } |
| } |
| |
| Configuration config = new ConfigurationRegistryReader().read(subset); |
| |
| // Resolving data and repositories directories |
| // If the config entries are absolute, the path is used as it is |
| // if the config entries are empty, they are resolved: |
| // dataDirectory = ${appserver.base}/data |
| // repositoryDirectory = ${dataDirectory}/repositories |
| // If the entries are relative they are resolved |
| // relative to the appserver.base, for dataDirectory |
| // relative to dataDirectory for repositoryBase |
| String dataDir = config.getArchivaRuntimeConfiguration().getDataDirectory(); |
| if (StringUtils.isEmpty(dataDir)) { |
| dataDirectory = getAppServerBaseDir().resolve("data"); |
| } else { |
| Path tmpDataDir = Paths.get(dataDir); |
| if (tmpDataDir.isAbsolute()) { |
| dataDirectory = tmpDataDir; |
| } else { |
| dataDirectory = getAppServerBaseDir().resolve(tmpDataDir); |
| } |
| } |
| config.getArchivaRuntimeConfiguration().setDataDirectory(dataDirectory.normalize().toString()); |
| String repoBaseDir = config.getArchivaRuntimeConfiguration().getRepositoryBaseDirectory(); |
| if (StringUtils.isEmpty(repoBaseDir)) { |
| repositoryBaseDirectory = dataDirectory.resolve("repositories"); |
| |
| } else { |
| Path tmpRepoBaseDir = Paths.get(repoBaseDir); |
| if (tmpRepoBaseDir.isAbsolute()) { |
| repositoryBaseDirectory = tmpRepoBaseDir; |
| } else { |
| dataDirectory.resolve(tmpRepoBaseDir); |
| } |
| } |
| |
| String remoteRepoBaseDir = config.getArchivaRuntimeConfiguration().getRemoteRepositoryBaseDirectory(); |
| if (StringUtils.isEmpty(remoteRepoBaseDir)) { |
| remoteRepositoryBaseDirectory = dataDirectory.resolve("remotes"); |
| } else { |
| Path tmpRemoteRepoDir = Paths.get(remoteRepoBaseDir); |
| if (tmpRemoteRepoDir.isAbsolute()) { |
| remoteRepositoryBaseDirectory = tmpRemoteRepoDir; |
| } else { |
| dataDirectory.resolve(tmpRemoteRepoDir); |
| } |
| } |
| |
| String repositoryGroupBaseDir = config.getArchivaRuntimeConfiguration().getRepositoryGroupBaseDirectory(); |
| if (StringUtils.isEmpty(repositoryGroupBaseDir)) { |
| repositoryGroupBaseDirectory = dataDirectory.resolve("groups"); |
| } else { |
| Path tmpGroupDir = Paths.get(repositoryGroupBaseDir); |
| if (tmpGroupDir.isAbsolute()) { |
| repositoryGroupBaseDirectory = tmpGroupDir; |
| } else { |
| dataDirectory.resolve(tmpGroupDir); |
| } |
| } |
| |
| |
| config.getRepositoryGroups(); |
| config.getRepositoryGroupsAsMap(); |
| if (!CollectionUtils.isEmpty(config.getRemoteRepositories())) { |
| List<RemoteRepositoryConfiguration> remoteRepos = config.getRemoteRepositories(); |
| for (RemoteRepositoryConfiguration repo : remoteRepos) { |
| // [MRM-582] Remote Repositories with empty <username> and <password> fields shouldn't be created in configuration. |
| if (StringUtils.isBlank(repo.getUsername())) { |
| repo.setUsername(null); |
| } |
| |
| if (StringUtils.isBlank(repo.getPassword())) { |
| repo.setPassword(null); |
| } |
| } |
| } |
| |
| if (!config.getProxyConnectors().isEmpty()) { |
| // Fix Proxy Connector Settings. |
| |
| // Create a copy of the list to read from (to prevent concurrent modification exceptions) |
| List<ProxyConnectorConfiguration> proxyConnectorList = new ArrayList<>(config.getProxyConnectors()); |
| // Remove the old connector list. |
| config.getProxyConnectors().clear(); |
| |
| for (ProxyConnectorConfiguration connector : proxyConnectorList) { |
| // Fix policies |
| boolean connectorValid = true; |
| |
| Map<String, String> policies = new HashMap<>(); |
| // Make copy of policies |
| policies.putAll(connector.getPolicies()); |
| // Clear out policies |
| connector.getPolicies().clear(); |
| |
| // Work thru policies. cleaning them up. |
| for (Entry<String, String> entry : policies.entrySet()) { |
| String policyId = entry.getKey(); |
| String setting = entry.getValue(); |
| |
| // Upgrade old policy settings. |
| if ("releases".equals(policyId) || "snapshots".equals(policyId)) { |
| if ("ignored".equals(setting)) { |
| setting = AbstractUpdatePolicy.ALWAYS.getId(); |
| } else if ("disabled".equals(setting)) { |
| setting = AbstractUpdatePolicy.NEVER.getId(); |
| } |
| } else if ("cache-failures".equals(policyId)) { |
| if ("ignored".equals(setting)) { |
| setting = CachedFailuresPolicy.NO.getId(); |
| } else if ("cached".equals(setting)) { |
| setting = CachedFailuresPolicy.YES.getId(); |
| } |
| } else if ("checksum".equals(policyId)) { |
| if ("ignored".equals(setting)) { |
| setting = ChecksumPolicy.IGNORE.getId(); |
| } |
| } |
| |
| // Validate existance of policy key. |
| connector.addPolicy(policyId, setting); |
| } |
| |
| if (connectorValid) { |
| config.addProxyConnector(connector); |
| } |
| } |
| |
| // Normalize the order fields in the proxy connectors. |
| Map<String, java.util.List<ProxyConnectorConfiguration>> proxyConnectorMap = |
| config.getProxyConnectorAsMap(); |
| |
| for (List<ProxyConnectorConfiguration> connectors : proxyConnectorMap.values()) { |
| // Sort connectors by order field. |
| Collections.sort(connectors, ProxyConnectorConfigurationOrderComparator.getInstance()); |
| |
| // Normalize the order field values. |
| int order = 1; |
| for (ProxyConnectorConfiguration connector : connectors) { |
| connector.setOrder(order++); |
| } |
| } |
| } |
| |
| this.defaultLocale = Locale.forLanguageTag(config.getArchivaRuntimeConfiguration().getDefaultLanguage()); |
| this.languagePriorities = Locale.LanguageRange.parse(config.getArchivaRuntimeConfiguration().getLanguageRange()); |
| return config; |
| } |
| |
| /* |
| * Updates the checkpath list for repositories. |
| * |
| * We are replacing existing ones and adding new ones. This allows to update the list with new releases. |
| * |
| * We are also updating existing remote repositories, if they exist already. |
| * |
| * This update method should only be called, if the config version changes to avoid overwriting |
| * user repository settings all the time. |
| */ |
| private void updateCheckPathDefaults(Configuration config, Registry defaultConfiguration) { |
| List<RepositoryCheckPath> existingCheckPathList = config.getArchivaDefaultConfiguration().getDefaultCheckPaths(); |
| HashMap<String, RepositoryCheckPath> existingCheckPaths = new HashMap<>(); |
| HashMap<String, RepositoryCheckPath> newCheckPaths = new HashMap<>(); |
| for (RepositoryCheckPath path : config.getArchivaDefaultConfiguration().getDefaultCheckPaths()) { |
| existingCheckPaths.put(path.getUrl(), path); |
| } |
| List defaultCheckPathsSubsets = defaultConfiguration.getSubsetList("archivaDefaultConfiguration.defaultCheckPaths.defaultCheckPath"); |
| for (Iterator i = defaultCheckPathsSubsets.iterator(); i.hasNext(); ) { |
| RepositoryCheckPath v = readRepositoryCheckPath((Registry) i.next()); |
| if (existingCheckPaths.containsKey(v.getUrl())) { |
| existingCheckPathList.remove(existingCheckPaths.get(v.getUrl())); |
| } |
| existingCheckPathList.add(v); |
| newCheckPaths.put(v.getUrl(), v); |
| } |
| // Remote repositories update |
| for (RemoteRepositoryConfiguration remoteRepositoryConfiguration : config.getRemoteRepositories()) { |
| String url = remoteRepositoryConfiguration.getUrl().toLowerCase(); |
| if (newCheckPaths.containsKey(url)) { |
| String currentPath = remoteRepositoryConfiguration.getCheckPath(); |
| String newPath = newCheckPaths.get(url).getPath(); |
| log.info("Updating connection check path for repository {}, from '{}' to '{}'.", remoteRepositoryConfiguration.getId(), |
| currentPath, newPath); |
| remoteRepositoryConfiguration.setCheckPath(newPath); |
| } |
| } |
| } |
| |
| private RepositoryCheckPath readRepositoryCheckPath(Registry registry) { |
| RepositoryCheckPath value = new RepositoryCheckPath(); |
| |
| String url = registry.getString("url", value.getUrl()); |
| |
| value.setUrl(url); |
| String path = registry.getString("path", value.getPath()); |
| value.setPath(path); |
| return value; |
| } |
| |
| |
| private Registry readDefaultConfiguration() { |
| // if it contains some old configuration, remove it (Archiva 0.9) |
| registry.removeSubset(KEY); |
| |
| try { |
| registry.addConfigurationFromResource("org/apache/archiva/configuration/default-archiva.xml", KEY); |
| this.isConfigurationDefaulted = true; |
| } catch (RegistryException e) { |
| throw new ConfigurationRuntimeException( |
| "Fatal error: Unable to find the built-in default configuration and load it into the registry", e); |
| } |
| return registry.getSubset(KEY); |
| } |
| |
| /* |
| * Reads the default only configuration into a special prefix. This allows to check for changes |
| * of the default configuration. |
| */ |
| private Registry readDefaultOnlyConfiguration() { |
| registry.removeSubset(KEY_DEFAULT_ONLY); |
| try { |
| registry.addConfigurationFromResource("org/apache/archiva/configuration/default-archiva.xml", KEY_DEFAULT_ONLY); |
| } catch (RegistryException e) { |
| throw new ConfigurationRuntimeException( |
| "Fatal error: Unable to find the built-in default configuration and load it into the registry", e); |
| } |
| return registry.getSubset(KEY_DEFAULT_ONLY); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public synchronized void save(Configuration configuration) |
| throws IndeterminateConfigurationException, RegistryException { |
| Registry section = registry.getSection(KEY + ".user"); |
| Registry baseSection = registry.getSection(KEY + ".base"); |
| if (section == null) { |
| section = baseSection; |
| if (section == null) { |
| section = createDefaultConfigurationFile(); |
| } |
| } else if (baseSection != null) { |
| Collection<String> keys = baseSection.getKeys(); |
| boolean foundList = false; |
| for (Iterator<String> i = keys.iterator(); i.hasNext() && !foundList; ) { |
| String key = i.next(); |
| |
| // a little aggressive with the repositoryScanning and databaseScanning - should be no need to split |
| // that configuration |
| if (key.startsWith("repositories") // |
| || key.startsWith("proxyConnectors") // |
| || key.startsWith("networkProxies") // |
| || key.startsWith("repositoryScanning") // |
| || key.startsWith("remoteRepositories") // |
| || key.startsWith("managedRepositories") // |
| || key.startsWith("repositoryGroups")) // |
| { |
| foundList = true; |
| } |
| } |
| |
| if (foundList) { |
| this.configuration = null; |
| |
| throw new IndeterminateConfigurationException( |
| "Configuration can not be saved when it is loaded from two sources"); |
| } |
| } |
| |
| // escape all cron expressions to handle ',' |
| escapeCronExpressions(configuration); |
| |
| // [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. |
| if (section != null) { |
| if (configuration.getManagedRepositories().isEmpty()) { |
| section.removeSubset("managedRepositories"); |
| } |
| if (configuration.getRemoteRepositories().isEmpty()) { |
| section.removeSubset("remoteRepositories"); |
| |
| } |
| if (configuration.getProxyConnectors().isEmpty()) { |
| section.removeSubset("proxyConnectors"); |
| } |
| if (configuration.getNetworkProxies().isEmpty()) { |
| section.removeSubset("networkProxies"); |
| } |
| if (configuration.getLegacyArtifactPaths().isEmpty()) { |
| section.removeSubset("legacyArtifactPaths"); |
| } |
| if (configuration.getRepositoryGroups().isEmpty()) { |
| section.removeSubset("repositoryGroups"); |
| } |
| if (configuration.getRepositoryScanning() != null) { |
| if (configuration.getRepositoryScanning().getKnownContentConsumers().isEmpty()) { |
| section.removeSubset("repositoryScanning.knownContentConsumers"); |
| } |
| if (configuration.getRepositoryScanning().getInvalidContentConsumers().isEmpty()) { |
| section.removeSubset("repositoryScanning.invalidContentConsumers"); |
| } |
| } |
| if (configuration.getArchivaRuntimeConfiguration() != null) { |
| section.removeSubset("archivaRuntimeConfiguration.defaultCheckPaths"); |
| } |
| |
| new ConfigurationRegistryWriter().write(configuration, section); |
| section.save(); |
| } |
| |
| |
| this.configuration = unescapeExpressions(configuration); |
| isConfigurationDefaulted = false; |
| |
| triggerEvent(ConfigurationEvent.SAVED); |
| } |
| |
| private void escapeCronExpressions(Configuration configuration) { |
| for (ManagedRepositoryConfiguration c : configuration.getManagedRepositories()) { |
| c.setRefreshCronExpression(escapeCronExpression(c.getRefreshCronExpression())); |
| } |
| } |
| |
| private Registry createDefaultConfigurationFile() |
| throws RegistryException { |
| // TODO: may not be needed under commons-configuration 1.4 - check |
| |
| String contents = "<configuration />"; |
| |
| String fileLocation = userConfigFilename; |
| |
| if (!writeFile("user configuration", userConfigFilename, contents)) { |
| fileLocation = altConfigFilename; |
| if (!writeFile("alternative configuration", altConfigFilename, contents, true)) { |
| throw new RegistryException( |
| "Unable to create configuration file in either user [" + userConfigFilename + "] or alternative [" |
| + altConfigFilename |
| + "] locations on disk, usually happens when not allowed to write to those locations."); |
| } |
| } |
| |
| // olamy hackish I know :-) |
| contents = "<configuration><xml fileName=\"" + fileLocation |
| + "\" config-forceCreate=\"true\" config-name=\"org.apache.archiva.user\"/>" + "</configuration>"; |
| |
| ((CommonsConfigurationRegistry) registry).setInitialConfiguration(contents); |
| |
| registry.initialize(); |
| |
| for (RegistryListener regListener : registryListeners) { |
| addRegistryChangeListener(regListener); |
| } |
| |
| triggerEvent(ConfigurationEvent.SAVED); |
| |
| Registry section = registry.getSection(KEY + ".user"); |
| if (section == null) { |
| return new CommonsConfigurationRegistry( ); |
| } else { |
| return section; |
| } |
| } |
| |
| private boolean writeFile(String filetype, String path, String contents) { |
| return writeFile( filetype, path, contents, false ); |
| } |
| |
| /** |
| * Attempts to write the contents to a file, if an IOException occurs, return false. |
| * <p/> |
| * The file will be created if the directory to the file exists, otherwise this will return false. |
| * |
| * @param filetype the filetype (freeform text) to use in logging messages when failure to write. |
| * @param path the path to write to. |
| * @param contents the contents to write. |
| * @return true if write successful. |
| */ |
| private boolean writeFile(String filetype, String path, String contents, boolean createDirs) { |
| Path file = Paths.get(path); |
| |
| try { |
| // Check parent directory (if it is declared) |
| final Path parent = file.getParent(); |
| if (parent != null) { |
| // Check that directory exists |
| if (!Files.exists( parent ) && createDirs) { |
| Files.createDirectories( parent ); |
| } |
| if (!Files.isDirectory(parent)) { |
| // Directory to file must exist for file to be created |
| return false; |
| } |
| } |
| FileUtils.writeStringToFile(file.toFile(), contents, FILE_ENCODING); |
| return true; |
| } catch (IOException e) { |
| log.error("Unable to create {} file: {}", filetype, e.getMessage(), e); |
| return false; |
| } |
| } |
| |
| private void triggerEvent(int type) { |
| ConfigurationEvent evt = new ConfigurationEvent(type); |
| for (ConfigurationListener listener : listeners) { |
| listener.configurationEvent(evt); |
| } |
| } |
| |
| @Override |
| public void addListener(ConfigurationListener listener) { |
| if (listener == null) { |
| return; |
| } |
| |
| listeners.add(listener); |
| } |
| |
| @Override |
| public void removeListener(ConfigurationListener listener) { |
| if (listener == null) { |
| return; |
| } |
| |
| listeners.remove(listener); |
| } |
| |
| |
| @Override |
| public void addChangeListener(RegistryListener listener) { |
| addRegistryChangeListener(listener); |
| |
| // keep track for later |
| registryListeners.add(listener); |
| } |
| |
| private void addRegistryChangeListener(RegistryListener listener) { |
| Registry section = registry.getSection(KEY + ".user"); |
| if (section != null) { |
| section.addChangeListener(listener); |
| } |
| section = registry.getSection(KEY + ".base"); |
| if (section != null) { |
| section.addChangeListener(listener); |
| } |
| } |
| |
| @Override |
| public void removeChangeListener(RegistryListener listener) { |
| boolean removed = registryListeners.remove(listener); |
| log.debug("RegistryListener: '{}' removed {}", listener, removed); |
| |
| Registry section = registry.getSection(KEY + ".user"); |
| if (section != null) { |
| section.removeChangeListener(listener); |
| } |
| section = registry.getSection(KEY + ".base"); |
| if (section != null) { |
| section.removeChangeListener(listener); |
| } |
| |
| } |
| |
| @PostConstruct |
| public void initialize() { |
| |
| // Resolve expressions in the userConfigFilename and altConfigFilename |
| try { |
| ExpressionEvaluator expressionEvaluator = new DefaultExpressionEvaluator(); |
| expressionEvaluator.addExpressionSource(new SystemPropertyExpressionSource()); |
| String userConfigFileNameSysProps = System.getProperty(USER_CONFIG_PROPERTY); |
| if (StringUtils.isNotBlank(userConfigFileNameSysProps)) { |
| userConfigFilename = userConfigFileNameSysProps; |
| } else { |
| String userConfigFileNameEnv = System.getenv(USER_CONFIG_ENVVAR); |
| if (StringUtils.isNotBlank(userConfigFileNameEnv)) { |
| userConfigFilename = userConfigFileNameEnv; |
| } else { |
| userConfigFilename = expressionEvaluator.expand(userConfigFilename); |
| } |
| } |
| altConfigFilename = expressionEvaluator.expand(altConfigFilename); |
| loadConfiguration(); |
| handleUpgradeConfiguration(); |
| } catch (IndeterminateConfigurationException | RegistryException e) { |
| throw new RuntimeException("failed during upgrade from previous version" + e.getMessage(), e); |
| } catch (EvaluatorException e) { |
| throw new RuntimeException( |
| "Unable to evaluate expressions found in " + "userConfigFilename or altConfigFilename.", e); |
| } |
| registry.addChangeListener(this); |
| } |
| |
| /** |
| * Handle upgrade to newer version |
| */ |
| private void handleUpgradeConfiguration() |
| throws RegistryException, IndeterminateConfigurationException { |
| |
| List<String> dbConsumers = Arrays.asList("update-db-artifact", "update-db-repository-metadata"); |
| |
| // remove database consumers if here |
| List<String> intersec = |
| ListUtils.intersection(dbConsumers, configuration.getRepositoryScanning().getKnownContentConsumers()); |
| |
| if (!intersec.isEmpty()) { |
| |
| List<String> knowContentConsumers = |
| new ArrayList<>(configuration.getRepositoryScanning().getKnownContentConsumers().size()); |
| for (String knowContentConsumer : configuration.getRepositoryScanning().getKnownContentConsumers()) { |
| if (!dbConsumers.contains(knowContentConsumer)) { |
| knowContentConsumers.add(knowContentConsumer); |
| } |
| } |
| |
| configuration.getRepositoryScanning().setKnownContentConsumers(knowContentConsumers); |
| } |
| |
| // ensure create-archiva-metadata is here |
| if (!configuration.getRepositoryScanning().getKnownContentConsumers().contains("create-archiva-metadata")) { |
| List<String> knowContentConsumers = |
| new ArrayList<>(configuration.getRepositoryScanning().getKnownContentConsumers()); |
| knowContentConsumers.add("create-archiva-metadata"); |
| configuration.getRepositoryScanning().setKnownContentConsumers(knowContentConsumers); |
| } |
| |
| // ensure duplicate-artifacts is here |
| if (!configuration.getRepositoryScanning().getKnownContentConsumers().contains("duplicate-artifacts")) { |
| List<String> knowContentConsumers = |
| new ArrayList<>(configuration.getRepositoryScanning().getKnownContentConsumers()); |
| knowContentConsumers.add("duplicate-artifacts"); |
| configuration.getRepositoryScanning().setKnownContentConsumers(knowContentConsumers); |
| } |
| |
| Registry defaultOnlyConfiguration = readDefaultOnlyConfiguration(); |
| // Currently we check only for configuration version change, not certain version numbers. |
| if (hasConfigVersionChanged(configuration, defaultOnlyConfiguration)) { |
| updateCheckPathDefaults(configuration, defaultOnlyConfiguration); |
| String newVersion = defaultOnlyConfiguration.getString("version"); |
| if (newVersion == null) { |
| throw new IndeterminateConfigurationException("The default configuration has no version information!"); |
| } |
| configuration.setVersion(newVersion); |
| try { |
| save(configuration); |
| } catch (IndeterminateConfigurationException e) { |
| log.error("Error occured during configuration update to new version: {}", e.getMessage()); |
| } catch (RegistryException e) { |
| log.error("Error occured during configuration update to new version: {}", e.getMessage()); |
| } |
| } |
| } |
| |
| @Override |
| public void reload() { |
| this.configuration = null; |
| try { |
| this.registry.initialize(); |
| } catch (RegistryException e) { |
| throw new ConfigurationRuntimeException(e.getMessage(), e); |
| } |
| this.initialize(); |
| } |
| |
| @Override |
| public Locale getDefaultLocale() { |
| return defaultLocale; |
| } |
| |
| @Override |
| public List<Locale.LanguageRange> getLanguagePriorities() { |
| return languagePriorities; |
| } |
| |
| @Override |
| public Path getAppServerBaseDir() { |
| String basePath = registry.getString("appserver.base"); |
| if (!StringUtils.isEmpty(basePath)) { |
| return Paths.get(basePath); |
| } else { |
| return Paths.get(""); |
| } |
| } |
| |
| @Override |
| public Path getRepositoryBaseDir() { |
| if (repositoryBaseDirectory == null) { |
| getConfiguration(); |
| } |
| return repositoryBaseDirectory; |
| |
| } |
| |
| @Override |
| public Path getRemoteRepositoryBaseDir() { |
| if (remoteRepositoryBaseDirectory == null) { |
| getConfiguration(); |
| } |
| return remoteRepositoryBaseDirectory; |
| } |
| |
| @Override |
| public Path getRepositoryGroupBaseDir() { |
| if (repositoryGroupBaseDirectory == null) { |
| getConfiguration(); |
| } |
| return repositoryGroupBaseDirectory; |
| } |
| |
| @Override |
| public Path getDataDirectory() { |
| if (dataDirectory == null) { |
| getConfiguration(); |
| } |
| return dataDirectory; |
| } |
| |
| @Override |
| public void beforeConfigurationChange(Registry registry, String propertyName, Object propertyValue) { |
| // nothing to do here |
| } |
| |
| @Override |
| public synchronized void afterConfigurationChange(Registry registry, String propertyName, Object propertyValue) { |
| // configuration = null; |
| // this.dataDirectory = null; |
| // this.repositoryBaseDirectory = null; |
| } |
| |
| private String removeExpressions(String directory) { |
| String value = StringUtils.replace(directory, "${appserver.base}", |
| registry.getString("appserver.base", "${appserver.base}")); |
| value = StringUtils.replace(value, "${appserver.home}", |
| registry.getString("appserver.home", "${appserver.home}")); |
| return value; |
| } |
| |
| private String unescapeCronExpression(String cronExpression) { |
| return StringUtils.replace(cronExpression, "\\,", ","); |
| } |
| |
| private String escapeCronExpression(String cronExpression) { |
| return StringUtils.replace(cronExpression, ",", "\\,"); |
| } |
| |
| private Configuration unescapeExpressions(Configuration config) { |
| // TODO: for commons-configuration 1.3 only |
| for (ManagedRepositoryConfiguration c : config.getManagedRepositories()) { |
| c.setLocation(removeExpressions(c.getLocation())); |
| c.setRefreshCronExpression(unescapeCronExpression(c.getRefreshCronExpression())); |
| } |
| |
| return config; |
| } |
| |
| private Configuration checkRepositoryLocations(Configuration config) { |
| // additional check for [MRM-789], ensure that the location of the default repositories |
| // are not installed in the server installation |
| for (ManagedRepositoryConfiguration repo : (List<ManagedRepositoryConfiguration>) config.getManagedRepositories()) { |
| String repoPath = repo.getLocation(); |
| Path repoLocation = Paths.get(repoPath); |
| |
| if (Files.exists(repoLocation) && Files.isDirectory(repoLocation) && !repoPath.endsWith( |
| "data/repositories/" + repo.getId())) { |
| repo.setLocation(repoPath + "/data/repositories/" + repo.getId()); |
| } |
| } |
| |
| return config; |
| } |
| |
| public String getUserConfigFilename() { |
| return userConfigFilename; |
| } |
| |
| public String getAltConfigFilename() { |
| return altConfigFilename; |
| } |
| |
| @Override |
| public boolean isDefaulted() { |
| return this.isConfigurationDefaulted; |
| } |
| |
| public Registry getRegistry() { |
| return registry; |
| } |
| |
| public void setRegistry(Registry registry) { |
| this.registry = registry; |
| } |
| |
| |
| public void setUserConfigFilename(String userConfigFilename) { |
| this.userConfigFilename = userConfigFilename; |
| } |
| |
| public void setAltConfigFilename(String altConfigFilename) { |
| this.altConfigFilename = altConfigFilename; |
| } |
| } |