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();
100 configuration = processExpressions( configuration );
102 return configuration;
105 private Configuration load()
107 // TODO: should this be the same as section? make sure unnamed sections still work (eg, sys properties)
108 Registry subset = registry.getSubset( KEY );
109 if ( subset.getString( "version" ) == null )
111 // a little autodetection of v1, even if version is omitted (this was previously allowed)
112 if ( subset.getSubset( "repositoryScanning" ).isEmpty() )
114 // only for empty, or v < 1
115 subset = readDefaultConfiguration();
119 Configuration config = new ConfigurationRegistryReader().read( subset );
121 if ( !config.getRepositories().isEmpty() )
123 for ( Iterator i = config.getRepositories().iterator(); i.hasNext(); )
125 V1RepositoryConfiguration r = (V1RepositoryConfiguration) i.next();
127 if ( r.getUrl().startsWith( "file://" ) )
129 r.setLocation( r.getUrl().substring( 7 ) );
130 config.addManagedRepository( r );
134 RemoteRepositoryConfiguration repo = new RemoteRepositoryConfiguration();
135 repo.setId( r.getId() );
136 repo.setLayout( r.getLayout() );
137 repo.setName( r.getName() );
138 repo.setUrl( r.getUrl() );
139 config.addRemoteRepository( repo );
147 private Registry readDefaultConfiguration()
149 // if it contains some old configuration, remove it (Archiva 0.9)
150 registry.removeSubset( KEY );
154 registry.addConfigurationFromResource( "org/apache/maven/archiva/configuration/default-archiva.xml", KEY );
156 catch ( RegistryException e )
158 throw new ConfigurationRuntimeException(
159 "Fatal error: Unable to find the built-in default configuration and load it into the registry", e );
161 return registry.getSubset( KEY );
164 public void save( Configuration configuration )
165 throws RegistryException, IndeterminateConfigurationException
167 Registry section = registry.getSection( KEY + ".user" );
168 Registry baseSection = registry.getSection( KEY + ".base" );
169 if ( section == null )
171 section = baseSection;
172 if ( section == null )
174 section = createDefaultConfigurationFile();
177 else if ( baseSection != null )
179 Collection keys = baseSection.getKeys();
180 boolean foundList = false;
181 for ( Iterator i = keys.iterator(); i.hasNext() && !foundList; )
183 String key = (String) i.next();
185 // a little aggressive with the repositoryScanning and databaseScanning - should be no need to split
186 // that configuration
187 if ( key.startsWith( "repositories" ) || key.startsWith( "proxyConnectors" ) ||
188 key.startsWith( "networkProxies" ) || key.startsWith( "repositoryScanning" ) ||
189 key.startsWith( "databaseScanning" ) || key.startsWith( "remoteRepositories" ) ||
190 key.startsWith( "managedRepositories" ) )
198 this.configuration = null;
200 throw new IndeterminateConfigurationException(
201 "Configuration can not be saved when it is loaded from two sources" );
205 configuration = escapeCronExpressions( configuration );
207 new ConfigurationRegistryWriter().write( configuration, section );
210 this.configuration = configuration;
213 private Registry createDefaultConfigurationFile()
214 throws RegistryException
216 // TODO: may not be needed under commons-configuration 1.4 - check
217 File file = new File( getFilteredUserConfigFilename() );
220 FileUtils.writeStringToFile( file, "<configuration/>", "UTF-8" );
222 catch ( IOException e )
224 throw new RegistryException( "Unable to create configuration file: " + e.getMessage(), e );
229 ( (Initializable) registry ).initialize();
231 for ( Iterator i = listeners.iterator(); i.hasNext(); )
233 RegistryListener l = (RegistryListener) i.next();
235 addRegistryChangeListener( l );
238 catch ( InitializationException e )
240 throw new RegistryException( "Unable to reinitialize configuration: " + e.getMessage(), e );
243 return registry.getSection( KEY + ".user" );
246 public void addChangeListener( RegistryListener listener )
248 addRegistryChangeListener( listener );
250 // keep track for later
251 listeners.add( listener );
254 private void addRegistryChangeListener( RegistryListener listener )
256 Registry section = registry.getSection( KEY + ".user" );
257 if ( section != null )
259 section.addChangeListener( listener );
261 section = registry.getSection( KEY + ".base" );
262 if ( section != null )
264 section.addChangeListener( listener );
268 public void initialize()
269 throws InitializationException
271 registry.addChangeListener( this );
274 public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
276 // nothing to do here
279 public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
281 configuration = null;
284 private String removeExpressions( String directory )
286 String value = StringUtils.replace( directory, "${appserver.base}",
287 registry.getString( "appserver.base", "${appserver.base}" ) );
288 value = StringUtils.replace( value, "${appserver.home}",
289 registry.getString( "appserver.home", "${appserver.home}" ) );
293 private String unescapeCronExpression( String cronExpression )
295 return StringUtils.replace( cronExpression, "\\,", "," );
298 private String escapeCronExpression( String cronExpression )
300 return StringUtils.replace( cronExpression, ",", "\\," );
303 private Configuration processExpressions( Configuration config )
305 // TODO: for commons-configuration 1.3 only
306 for ( Iterator i = config.getManagedRepositories().iterator(); i.hasNext(); )
308 ManagedRepositoryConfiguration c = (ManagedRepositoryConfiguration) i.next();
309 c.setLocation( removeExpressions( c.getLocation() ) );
310 c.setRefreshCronExpression( unescapeCronExpression( c.getRefreshCronExpression() ) );
313 DatabaseScanningConfiguration databaseScanning = config.getDatabaseScanning();
314 if ( databaseScanning != null )
316 String cron = databaseScanning.getCronExpression();
317 databaseScanning.setCronExpression( unescapeCronExpression( cron ) );
323 private Configuration escapeCronExpressions( Configuration config )
325 for ( Iterator i = config.getManagedRepositories().iterator(); i.hasNext(); )
327 ManagedRepositoryConfiguration c = (ManagedRepositoryConfiguration) i.next();
329 c.setRefreshCronExpression( escapeCronExpression( c.getRefreshCronExpression() ) );
332 DatabaseScanningConfiguration databaseScanning = config.getDatabaseScanning();
333 if ( databaseScanning != null )
335 String cron = databaseScanning.getCronExpression();
336 databaseScanning.setCronExpression( escapeCronExpression( cron ) );