]> source.dussan.org Git - archiva.git/blob
345a1dfead391500ad384dd6b2a38cca73ce8a3c
[archiva.git] /
1 package org.apache.maven.archiva.configuration;
2
3 /*
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
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
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;
32
33 import java.io.File;
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;
39
40 /**
41  * Implementation of configuration holder that retrieves it from the registry.
42  * <p/>
43  * The registry layers and merges the 2 configuration files: user, and application server.
44  * <p/>
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.
48  * <p/>
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.
54  * <p/>
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.
57  *
58  * @plexus.component role="org.apache.maven.archiva.configuration.ArchivaConfiguration"
59  */
60 public class DefaultArchivaConfiguration
61     extends AbstractLogEnabled
62     implements ArchivaConfiguration, RegistryListener, Initializable
63 {
64     /**
65      * Plexus registry to read the configuration from.
66      *
67      * @plexus.requirement role-hint="commons-configuration"
68      */
69     private Registry registry;
70
71     /**
72      * The configuration that has been converted.
73      */
74     private Configuration configuration;
75
76     private static final String KEY = "org.apache.maven.archiva";
77
78     /**
79      * @plexus.configuration default-value="${user.home}/.m2/archiva.xml"
80      */
81     private String userConfigFilename;
82
83     /**
84      * Listeners we've registered.
85      */
86     private List listeners = new LinkedList();
87
88     public String getFilteredUserConfigFilename()
89     {
90         return StringUtils.replace( userConfigFilename, "${user.home}", System.getProperty( "user.home" ) );
91     }
92
93     public synchronized Configuration getConfiguration()
94     {
95         if ( configuration == null )
96         {
97             configuration = load();
98         }
99
100         configuration = processExpressions( configuration );
101
102         return configuration;
103     }
104
105     private Configuration load()
106     {
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 )
110         {
111             // a little autodetection of v1, even if version is omitted (this was previously allowed)
112             if ( subset.getSubset( "repositoryScanning" ).isEmpty() )
113             {
114                 // only for empty, or v < 1
115                 subset = readDefaultConfiguration();
116             }
117         }
118
119         Configuration config = new ConfigurationRegistryReader().read( subset );
120
121         if ( !config.getRepositories().isEmpty() )
122         {
123             for ( Iterator i = config.getRepositories().iterator(); i.hasNext(); )
124             {
125                 V1RepositoryConfiguration r = (V1RepositoryConfiguration) i.next();
126
127                 if ( r.getUrl().startsWith( "file://" ) )
128                 {
129                     r.setLocation( r.getUrl().substring( 7 ) );
130                     config.addManagedRepository( r );
131                 }
132                 else
133                 {
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 );
140                 }
141             }
142         }
143
144         return config;
145     }
146
147     private Registry readDefaultConfiguration()
148     {
149         // if it contains some old configuration, remove it (Archiva 0.9)
150         registry.removeSubset( KEY );
151
152         try
153         {
154             registry.addConfigurationFromResource( "org/apache/maven/archiva/configuration/default-archiva.xml", KEY );
155         }
156         catch ( RegistryException e )
157         {
158             throw new ConfigurationRuntimeException(
159                 "Fatal error: Unable to find the built-in default configuration and load it into the registry", e );
160         }
161         return registry.getSubset( KEY );
162     }
163
164     public void save( Configuration configuration )
165         throws RegistryException, IndeterminateConfigurationException
166     {
167         Registry section = registry.getSection( KEY + ".user" );
168         Registry baseSection = registry.getSection( KEY + ".base" );
169         if ( section == null )
170         {
171             section = baseSection;
172             if ( section == null )
173             {
174                 section = createDefaultConfigurationFile();
175             }
176         }
177         else if ( baseSection != null )
178         {
179             Collection keys = baseSection.getKeys();
180             boolean foundList = false;
181             for ( Iterator i = keys.iterator(); i.hasNext() && !foundList; )
182             {
183                 String key = (String) i.next();
184
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" ) )
191                 {
192                     foundList = true;
193                 }
194             }
195
196             if ( foundList )
197             {
198                 this.configuration = null;
199
200                 throw new IndeterminateConfigurationException(
201                     "Configuration can not be saved when it is loaded from two sources" );
202             }
203         }
204
205         configuration = escapeCronExpressions( configuration );
206
207         new ConfigurationRegistryWriter().write( configuration, section );
208         section.save();
209
210         this.configuration = configuration;
211     }
212
213     private Registry createDefaultConfigurationFile()
214         throws RegistryException
215     {
216         // TODO: may not be needed under commons-configuration 1.4 - check
217         File file = new File( getFilteredUserConfigFilename() );
218         try
219         {
220             FileUtils.writeStringToFile( file, "<configuration/>", "UTF-8" );
221         }
222         catch ( IOException e )
223         {
224             throw new RegistryException( "Unable to create configuration file: " + e.getMessage(), e );
225         }
226
227         try
228         {
229             ( (Initializable) registry ).initialize();
230
231             for ( Iterator i = listeners.iterator(); i.hasNext(); )
232             {
233                 RegistryListener l = (RegistryListener) i.next();
234
235                 addRegistryChangeListener( l );
236             }
237         }
238         catch ( InitializationException e )
239         {
240             throw new RegistryException( "Unable to reinitialize configuration: " + e.getMessage(), e );
241         }
242
243         return registry.getSection( KEY + ".user" );
244     }
245
246     public void addChangeListener( RegistryListener listener )
247     {
248         addRegistryChangeListener( listener );
249
250         // keep track for later
251         listeners.add( listener );
252     }
253
254     private void addRegistryChangeListener( RegistryListener listener )
255     {
256         Registry section = registry.getSection( KEY + ".user" );
257         if ( section != null )
258         {
259             section.addChangeListener( listener );
260         }
261         section = registry.getSection( KEY + ".base" );
262         if ( section != null )
263         {
264             section.addChangeListener( listener );
265         }
266     }
267
268     public void initialize()
269         throws InitializationException
270     {
271         registry.addChangeListener( this );
272     }
273
274     public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
275     {
276         // nothing to do here
277     }
278
279     public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
280     {
281         configuration = null;
282     }
283
284     private String removeExpressions( String directory )
285     {
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}" ) );
290         return value;
291     }
292
293     private String unescapeCronExpression( String cronExpression )
294     {
295         return StringUtils.replace( cronExpression, "\\,", "," );
296     }
297
298     private String escapeCronExpression( String cronExpression )
299     {
300         return StringUtils.replace( cronExpression, ",", "\\," );
301     }
302
303     private Configuration processExpressions( Configuration config )
304     {
305         // TODO: for commons-configuration 1.3 only
306         for ( Iterator i = config.getManagedRepositories().iterator(); i.hasNext(); )
307         {
308             ManagedRepositoryConfiguration c = (ManagedRepositoryConfiguration) i.next();
309             c.setLocation( removeExpressions( c.getLocation() ) );
310             c.setRefreshCronExpression( unescapeCronExpression( c.getRefreshCronExpression() ) );
311         }
312
313         DatabaseScanningConfiguration databaseScanning = config.getDatabaseScanning();
314         if ( databaseScanning != null )
315         {
316             String cron = databaseScanning.getCronExpression();
317             databaseScanning.setCronExpression( unescapeCronExpression( cron ) );
318         }
319
320         return config;
321     }
322
323     private Configuration escapeCronExpressions( Configuration config )
324     {
325         for ( Iterator i = config.getManagedRepositories().iterator(); i.hasNext(); )
326         {
327             ManagedRepositoryConfiguration c = (ManagedRepositoryConfiguration) i.next();
328
329             c.setRefreshCronExpression( escapeCronExpression( c.getRefreshCronExpression() ) );
330         }
331
332         DatabaseScanningConfiguration databaseScanning = config.getDatabaseScanning();
333         if ( databaseScanning != null )
334         {
335             String cron = databaseScanning.getCronExpression();
336             databaseScanning.setCronExpression( escapeCronExpression( cron ) );
337         }
338
339         return config;
340     }
341
342 }