1 package org.apache.maven.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.commons.io.FileUtils;
23 import org.apache.maven.archiva.configuration.io.registry.ConfigurationRegistryReader;
24 import org.apache.maven.archiva.configuration.io.registry.ConfigurationRegistryWriter;
25 import org.codehaus.plexus.logging.AbstractLogEnabled;
26 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
27 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
28 import org.codehaus.plexus.registry.Registry;
29 import org.codehaus.plexus.registry.RegistryException;
30 import org.codehaus.plexus.registry.RegistryListener;
31 import org.codehaus.plexus.util.StringUtils;
34 import java.io.IOException;
35 import java.util.Collection;
36 import java.util.Iterator;
37 import java.util.LinkedList;
38 import java.util.List;
41 * Implementation of configuration holder that retrieves it from the registry.
43 * The registry layers and merges the 2 configuration files: user, and application server.
45 * Instead of relying on the model defaults, if the registry is empty a default configuration file is loaded and
46 * applied from a resource. The defaults are not loaded into the registry as the lists (eg repositories) could no longer
47 * be removed if that was the case.
49 * When saving the configuration, it is saved to the location it was read from. If it was read from the defaults, it
50 * will be saved to the user location.
51 * However, if the configuration contains information from both sources, an exception is raised as this is currently
52 * unsupported. The reason for this is that it is not possible to identify where to re-save elements, and can result
53 * in list configurations (eg repositories) becoming inconsistent.
55 * If the configuration is outdated, it will be upgraded when it is loaded. This is done by checking the version flag
56 * before reading it from the registry.
58 * @plexus.component role="org.apache.maven.archiva.configuration.ArchivaConfiguration"
60 public class DefaultArchivaConfiguration
61 extends AbstractLogEnabled
62 implements ArchivaConfiguration, RegistryListener, Initializable
65 * Plexus registry to read the configuration from.
67 * @plexus.requirement role-hint="commons-configuration"
69 private Registry registry;
72 * The configuration that has been converted.
74 private Configuration configuration;
76 private static final String KEY = "org.apache.maven.archiva";
79 * @plexus.configuration default-value="${user.home}/.m2/archiva.xml"
81 private String userConfigFilename;
84 * Listeners we've registered.
86 private List listeners = new LinkedList();
88 public String getFilteredUserConfigFilename()
90 return StringUtils.replace( userConfigFilename, "${user.home}", System.getProperty( "user.home" ) );
93 public synchronized Configuration getConfiguration()
95 if ( configuration == null )
97 configuration = load();
98 configuration = processExpressions( configuration );
101 return configuration;
104 private Configuration load()
106 // TODO: should this be the same as section? make sure unnamed sections still work (eg, sys properties)
107 Registry subset = registry.getSubset( KEY );
108 if ( subset.getString( "version" ) == null )
110 // a little autodetection of v1, even if version is omitted (this was previously allowed)
111 if ( subset.getSubset( "repositoryScanning" ).isEmpty() )
113 // only for empty, or v < 1
114 subset = readDefaultConfiguration();
118 Configuration config = new ConfigurationRegistryReader().read( subset );
123 private Registry readDefaultConfiguration()
125 // if it contains some old configuration, remove it (Archiva 0.9)
126 registry.removeSubset( KEY );
130 registry.addConfigurationFromResource( "org/apache/maven/archiva/configuration/default-archiva.xml", KEY );
132 catch ( RegistryException e )
134 throw new ConfigurationRuntimeException(
135 "Fatal error: Unable to find the built-in default configuration and load it into the registry", e );
137 return registry.getSubset( KEY );
140 public synchronized void save( Configuration configuration )
141 throws RegistryException, IndeterminateConfigurationException
143 Registry section = registry.getSection( KEY + ".user" );
144 Registry baseSection = registry.getSection( KEY + ".base" );
145 if ( section == null )
147 section = baseSection;
148 if ( section == null )
150 section = createDefaultConfigurationFile();
153 else if ( baseSection != null )
155 Collection keys = baseSection.getKeys();
156 boolean foundList = false;
157 for ( Iterator i = keys.iterator(); i.hasNext() && !foundList; )
159 String key = (String) i.next();
161 // a little aggressive with the repositoryScanning and databaseScanning - should be no need to split
162 // that configuration
163 if ( key.startsWith( "repositories" ) || key.startsWith( "proxyConnectors" ) ||
164 key.startsWith( "networkProxies" ) || key.startsWith( "repositoryScanning" ) ||
165 key.startsWith( "databaseScanning" ) )
173 this.configuration = null;
175 throw new IndeterminateConfigurationException(
176 "Configuration can not be saved when it is loaded from two sources" );
180 // escape all cron expressions to handle ','
181 for ( Iterator i = configuration.getRepositories().iterator(); i.hasNext(); )
183 RepositoryConfiguration c = (RepositoryConfiguration) i.next();
184 c.setRefreshCronExpression( escapeCronExpression( c.getRefreshCronExpression() ) );
187 if ( configuration.getDatabaseScanning() != null )
189 configuration.getDatabaseScanning().setCronExpression( escapeCronExpression(
190 configuration.getDatabaseScanning().getCronExpression() ) );
193 new ConfigurationRegistryWriter().write( configuration, section );
196 this.configuration = processExpressions( configuration );
199 private Registry createDefaultConfigurationFile()
200 throws RegistryException
202 // TODO: may not be needed under commons-configuration 1.4 - check
203 File file = new File( getFilteredUserConfigFilename() );
206 FileUtils.writeStringToFile( file, "<configuration/>", "UTF-8" );
208 catch ( IOException e )
210 throw new RegistryException( "Unable to create configuration file: " + e.getMessage(), e );
215 ( (Initializable) registry ).initialize();
217 for ( Iterator i = listeners.iterator(); i.hasNext(); )
219 RegistryListener l = (RegistryListener) i.next();
221 addRegistryChangeListener( l );
224 catch ( InitializationException e )
226 throw new RegistryException( "Unable to reinitialize configuration: " + e.getMessage(), e );
229 return registry.getSection( KEY + ".user" );
232 public void addChangeListener( RegistryListener listener )
234 addRegistryChangeListener( listener );
236 // keep track for later
237 listeners.add( listener );
240 private void addRegistryChangeListener( RegistryListener listener )
242 Registry section = registry.getSection( KEY + ".user" );
243 if ( section != null )
245 section.addChangeListener( listener );
247 section = registry.getSection( KEY + ".base" );
248 if ( section != null )
250 section.addChangeListener( listener );
254 public void initialize()
255 throws InitializationException
257 registry.addChangeListener( this );
260 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
262 // nothing to do here
265 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
267 synchronized( configuration )
269 configuration = null;
273 private String removeExpressions( String directory )
275 String value = StringUtils.replace( directory, "${appserver.base}",
276 registry.getString( "appserver.base", "${appserver.base}" ) );
277 value = StringUtils.replace( value, "${appserver.home}",
278 registry.getString( "appserver.home", "${appserver.home}" ) );
282 private String unescapeCronExpression( String cronExpression )
284 return StringUtils.replace( cronExpression, "\\,", "," );
287 private String escapeCronExpression( String cronExpression )
289 return StringUtils.replace( cronExpression, ",", "\\," );
292 private Configuration processExpressions( Configuration config )
294 // TODO: for commons-configuration 1.3 only
295 for ( Iterator i = config.getRepositories().iterator(); i.hasNext(); )
297 RepositoryConfiguration c = (RepositoryConfiguration) i.next();
298 c.setUrl( removeExpressions( c.getUrl() ) );
299 c.setRefreshCronExpression( unescapeCronExpression( c.getRefreshCronExpression() ) );
302 DatabaseScanningConfiguration databaseScanning = config.getDatabaseScanning();
303 if ( databaseScanning != null )
305 String cron = databaseScanning.getCronExpression();
306 databaseScanning.setCronExpression( unescapeCronExpression( cron ) );