]> source.dussan.org Git - archiva.git/blob
7ed026b7bbd674c9da63d35727f225c7df35dd20
[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             configuration = processExpressions( configuration );
99         }
100
101         return configuration;
102     }
103
104     private Configuration load()
105     {
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 )
109         {
110             // a little autodetection of v1, even if version is omitted (this was previously allowed)
111             if ( subset.getSubset( "repositoryScanning" ).isEmpty() )
112             {
113                 // only for empty, or v < 1
114                 subset = readDefaultConfiguration();
115             }
116         }
117
118         Configuration config = new ConfigurationRegistryReader().read( subset );
119
120         return config;
121     }
122
123     private Registry readDefaultConfiguration()
124     {
125         // if it contains some old configuration, remove it (Archiva 0.9)
126         registry.removeSubset( KEY );
127
128         try
129         {
130             registry.addConfigurationFromResource( "org/apache/maven/archiva/configuration/default-archiva.xml", KEY );
131         }
132         catch ( RegistryException e )
133         {
134             throw new ConfigurationRuntimeException(
135                 "Fatal error: Unable to find the built-in default configuration and load it into the registry", e );
136         }
137         return registry.getSubset( KEY );
138     }
139
140     public synchronized void save( Configuration configuration )
141         throws RegistryException, IndeterminateConfigurationException
142     {
143         Registry section = registry.getSection( KEY + ".user" );
144         Registry baseSection = registry.getSection( KEY + ".base" );
145         if ( section == null )
146         {
147             section = baseSection;
148             if ( section == null )
149             {
150                 section = createDefaultConfigurationFile();
151             }
152         }
153         else if ( baseSection != null )
154         {
155             Collection keys = baseSection.getKeys();
156             boolean foundList = false;
157             for ( Iterator i = keys.iterator(); i.hasNext() && !foundList; )
158             {
159                 String key = (String) i.next();
160
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" ) )
166                 {
167                     foundList = true;
168                 }
169             }
170
171             if ( foundList )
172             {
173                 this.configuration = null;
174
175                 throw new IndeterminateConfigurationException(
176                     "Configuration can not be saved when it is loaded from two sources" );
177             }
178         }
179
180         // escape all cron expressions to handle ','
181         for ( Iterator i = configuration.getRepositories().iterator(); i.hasNext(); )
182         {
183             RepositoryConfiguration c = (RepositoryConfiguration) i.next();
184             c.setRefreshCronExpression( escapeCronExpression( c.getRefreshCronExpression() ) );
185         }
186
187         if ( configuration.getDatabaseScanning() != null )
188         {
189             configuration.getDatabaseScanning().setCronExpression( escapeCronExpression(
190                 configuration.getDatabaseScanning().getCronExpression() ) );
191         }
192
193         new ConfigurationRegistryWriter().write( configuration, section );
194         section.save();
195
196         this.configuration = processExpressions( configuration );
197     }
198
199     private Registry createDefaultConfigurationFile()
200         throws RegistryException
201     {
202         // TODO: may not be needed under commons-configuration 1.4 - check
203         File file = new File( getFilteredUserConfigFilename() );
204         try
205         {
206             FileUtils.writeStringToFile( file, "<configuration/>", "UTF-8" );
207         }
208         catch ( IOException e )
209         {
210             throw new RegistryException( "Unable to create configuration file: " + e.getMessage(), e );
211         }
212
213         try
214         {
215             ( (Initializable) registry ).initialize();
216
217             for ( Iterator i = listeners.iterator(); i.hasNext(); )
218             {
219                 RegistryListener l = (RegistryListener) i.next();
220
221                 addRegistryChangeListener( l );
222             }
223         }
224         catch ( InitializationException e )
225         {
226             throw new RegistryException( "Unable to reinitialize configuration: " + e.getMessage(), e );
227         }
228
229         return registry.getSection( KEY + ".user" );
230     }
231
232     public void addChangeListener( RegistryListener listener )
233     {
234         addRegistryChangeListener( listener );
235
236         // keep track for later
237         listeners.add( listener );
238     }
239
240     private void addRegistryChangeListener( RegistryListener listener )
241     {
242         Registry section = registry.getSection( KEY + ".user" );
243         if ( section != null )
244         {
245             section.addChangeListener( listener );
246         }
247         section = registry.getSection( KEY + ".base" );
248         if ( section != null )
249         {
250             section.addChangeListener( listener );
251         }
252     }
253
254     public void initialize()
255         throws InitializationException
256     {
257         registry.addChangeListener( this );
258     }
259
260     public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
261     {
262         // nothing to do here
263     }
264
265     public void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
266     {
267         synchronized( configuration )
268         {
269             configuration = null;
270         }
271     }
272
273     private String removeExpressions( String directory )
274     {
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}" ) );
279         return value;
280     }
281
282     private String unescapeCronExpression( String cronExpression )
283     {
284         return StringUtils.replace( cronExpression, "\\,", "," );
285     }
286
287     private String escapeCronExpression( String cronExpression )
288     {
289         return StringUtils.replace( cronExpression, ",", "\\," );
290     }
291
292     private Configuration processExpressions( Configuration config )
293     {
294         // TODO: for commons-configuration 1.3 only
295         for ( Iterator i = config.getRepositories().iterator(); i.hasNext(); )
296         {
297             RepositoryConfiguration c = (RepositoryConfiguration) i.next();
298             c.setUrl( removeExpressions( c.getUrl() ) );
299             c.setRefreshCronExpression( unescapeCronExpression( c.getRefreshCronExpression() ) );
300         }
301
302         DatabaseScanningConfiguration databaseScanning = config.getDatabaseScanning();
303         if ( databaseScanning != null )
304         {
305             String cron = databaseScanning.getCronExpression();
306             databaseScanning.setCronExpression( unescapeCronExpression( cron ) );
307         }
308
309         return config;
310     }
311 }