]> source.dussan.org Git - archiva.git/blob
8a83cc84825f9999a1770fd92c9825ba79fcfeaf
[archiva.git] /
1 package org.apache.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.archiva.configuration.functors.ProxyConnectorConfigurationOrderComparator;
23 import org.apache.archiva.configuration.io.registry.ConfigurationRegistryReader;
24 import org.apache.archiva.configuration.io.registry.ConfigurationRegistryWriter;
25 import org.apache.archiva.policies.AbstractUpdatePolicy;
26 import org.apache.archiva.policies.CachedFailuresPolicy;
27 import org.apache.archiva.policies.ChecksumPolicy;
28 import org.apache.archiva.policies.DownloadErrorPolicy;
29 import org.apache.archiva.policies.Policy;
30 import org.apache.archiva.policies.PostDownloadPolicy;
31 import org.apache.archiva.policies.PreDownloadPolicy;
32 import org.apache.archiva.redback.components.evaluator.DefaultExpressionEvaluator;
33 import org.apache.archiva.redback.components.evaluator.EvaluatorException;
34 import org.apache.archiva.redback.components.evaluator.ExpressionEvaluator;
35 import org.apache.archiva.redback.components.evaluator.sources.SystemPropertyExpressionSource;
36 import org.apache.archiva.redback.components.registry.Registry;
37 import org.apache.archiva.redback.components.registry.RegistryException;
38 import org.apache.archiva.redback.components.registry.RegistryListener;
39 import org.apache.archiva.redback.components.registry.commons.CommonsConfigurationRegistry;
40 import org.apache.archiva.redback.components.springutils.ComponentContainer;
41 import org.apache.commons.collections.CollectionUtils;
42 import org.apache.commons.collections.ListUtils;
43 import org.apache.commons.collections.MapUtils;
44 import org.apache.commons.configuration.BaseConfiguration;
45 import org.apache.commons.io.FileUtils;
46 import org.apache.commons.lang.StringUtils;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import org.springframework.stereotype.Service;
50
51 import javax.annotation.PostConstruct;
52 import javax.inject.Inject;
53 import javax.inject.Named;
54 import java.io.File;
55 import java.io.IOException;
56 import java.util.ArrayList;
57 import java.util.Arrays;
58 import java.util.Collection;
59 import java.util.Collections;
60 import java.util.HashMap;
61 import java.util.HashSet;
62 import java.util.Iterator;
63 import java.util.List;
64 import java.util.Map;
65 import java.util.Map.Entry;
66 import java.util.Set;
67
68 /**
69  * <p>
70  * Implementation of configuration holder that retrieves it from the registry.
71  * </p>
72  * <p>
73  * The registry layers and merges the 2 configuration files: user, and application server.
74  * </p>
75  * <p>
76  * Instead of relying on the model defaults, if the registry is empty a default configuration file is loaded and
77  * applied from a resource. The defaults are not loaded into the registry as the lists (eg repositories) could no longer
78  * be removed if that was the case.
79  * </p>
80  * <p>
81  * When saving the configuration, it is saved to the location it was read from. If it was read from the defaults, it
82  * will be saved to the user location.
83  * However, if the configuration contains information from both sources, an exception is raised as this is currently
84  * unsupported. The reason for this is that it is not possible to identify where to re-save elements, and can result
85  * in list configurations (eg repositories) becoming inconsistent.
86  * </p>
87  * <p>
88  * If the configuration is outdated, it will be upgraded when it is loaded. This is done by checking the version flag
89  * before reading it from the registry.
90  * </p>
91  */
92 @Service ( "archivaConfiguration#default" )
93 public class DefaultArchivaConfiguration
94     implements ArchivaConfiguration, RegistryListener
95 {
96     private Logger log = LoggerFactory.getLogger( DefaultArchivaConfiguration.class );
97
98     /**
99      * Plexus registry to read the configuration from.
100      */
101     @Inject
102     @Named ( value = "commons-configuration" )
103     private Registry registry;
104
105     @Inject
106     private ComponentContainer componentContainer;
107
108     /**
109      * The configuration that has been converted.
110      */
111     private Configuration configuration;
112
113     /**
114      * see #initialize
115      *
116      * @todo these don't strictly belong in here
117      */
118     private Map<String, PreDownloadPolicy> prePolicies;
119
120     /**
121      * see #initialize
122      *
123      * @todo these don't strictly belong in here
124      */
125     private Map<String, PostDownloadPolicy> postPolicies;
126
127     /**
128      * see #initialize
129      *
130      * @todo these don't strictly belong in here
131      */
132     private Map<String, DownloadErrorPolicy> downloadErrorPolicies;
133
134
135     /**
136      * see #initialize
137      * default-value="${user.home}/.m2/archiva.xml"
138      */
139     private String userConfigFilename = "${user.home}/.m2/archiva.xml";
140
141     /**
142      * see #initialize
143      * default-value="${appserver.base}/conf/archiva.xml"
144      */
145     private String altConfigFilename = "${appserver.base}/conf/archiva.xml";
146
147     /**
148      * Configuration Listeners we've registered.
149      */
150     private Set<ConfigurationListener> listeners = new HashSet<ConfigurationListener>();
151
152     /**
153      * Registry Listeners we've registered.
154      */
155     private Set<RegistryListener> registryListeners = new HashSet<RegistryListener>();
156
157     /**
158      * Boolean to help determine if the configuration exists as a result of pulling in
159      * the default-archiva.xml
160      */
161     private boolean isConfigurationDefaulted = false;
162
163     private static final String KEY = "org.apache.archiva";
164
165     public Configuration getConfiguration()
166     {
167         return loadConfiguration();
168     }
169
170     private synchronized Configuration loadConfiguration()
171     {
172         if ( configuration == null )
173         {
174             configuration = load();
175             configuration = unescapeExpressions( configuration );
176             if ( isConfigurationDefaulted )
177             {
178                 configuration = checkRepositoryLocations( configuration );
179             }
180         }
181
182         return configuration;
183     }
184
185     @SuppressWarnings ( "unchecked" )
186     private Configuration load()
187     {
188         // TODO: should this be the same as section? make sure unnamed sections still work (eg, sys properties)
189         Registry subset = registry.getSubset( KEY );
190         if ( subset.getString( "version" ) == null )
191         {
192             // a little autodetection of v1, even if version is omitted (this was previously allowed)
193             if ( subset.getSubset( "repositoryScanning" ).isEmpty() )
194             {
195                 // only for empty, or v < 1
196                 subset = readDefaultConfiguration();
197             }
198         }
199
200         Configuration config = new ConfigurationRegistryReader().read( subset );
201
202         config.getRepositoryGroups();
203         config.getRepositoryGroupsAsMap();
204         if ( !config.getRepositories().isEmpty() )
205         {
206             for ( Iterator<V1RepositoryConfiguration> i = config.getRepositories().iterator(); i.hasNext(); )
207             {
208                 V1RepositoryConfiguration r = i.next();
209                 r.setScanned( r.isIndexed() );
210
211                 if ( StringUtils.startsWith( r.getUrl(), "file://" ) )
212                 {
213                     r.setLocation( r.getUrl().substring( 7 ) );
214                     config.addManagedRepository( r );
215                 }
216                 else if ( StringUtils.startsWith( r.getUrl(), "file:" ) )
217                 {
218                     r.setLocation( r.getUrl().substring( 5 ) );
219                     config.addManagedRepository( r );
220                 }
221                 else if ( StringUtils.isEmpty( r.getUrl() ) )
222                 {
223                     // in case of empty url we can consider it as a managed one
224                     // check if location is null
225                     //file://${appserver.base}/repositories/${id}
226                     if ( StringUtils.isEmpty( r.getLocation() ) )
227                     {
228                         r.setLocation( "file://${appserver.base}/repositories/" + r.getId() );
229                     }
230                     config.addManagedRepository( r );
231                 }
232                 else
233                 {
234                     RemoteRepositoryConfiguration repo = new RemoteRepositoryConfiguration();
235                     repo.setId( r.getId() );
236                     repo.setLayout( r.getLayout() );
237                     repo.setName( r.getName() );
238                     repo.setUrl( r.getUrl() );
239                     config.addRemoteRepository( repo );
240                 }
241             }
242
243             // Prevent duplicate repositories from showing up.
244             config.getRepositories().clear();
245
246             registry.removeSubset( KEY + ".repositories" );
247         }
248
249         if ( !CollectionUtils.isEmpty( config.getRemoteRepositories() ) )
250         {
251             List<RemoteRepositoryConfiguration> remoteRepos = config.getRemoteRepositories();
252             for ( RemoteRepositoryConfiguration repo : remoteRepos )
253             {
254                 // [MRM-582] Remote Repositories with empty <username> and <password> fields shouldn't be created in configuration.
255                 if ( StringUtils.isBlank( repo.getUsername() ) )
256                 {
257                     repo.setUsername( null );
258                 }
259
260                 if ( StringUtils.isBlank( repo.getPassword() ) )
261                 {
262                     repo.setPassword( null );
263                 }
264             }
265         }
266
267         if ( !config.getProxyConnectors().isEmpty() )
268         {
269             // Fix Proxy Connector Settings.
270
271             // Create a copy of the list to read from (to prevent concurrent modification exceptions)
272             List<ProxyConnectorConfiguration> proxyConnectorList =
273                 new ArrayList<ProxyConnectorConfiguration>( config.getProxyConnectors() );
274             // Remove the old connector list.
275             config.getProxyConnectors().clear();
276
277             for ( ProxyConnectorConfiguration connector : proxyConnectorList )
278             {
279                 // Fix policies
280                 boolean connectorValid = true;
281
282                 Map<String, String> policies = new HashMap<String, String>();
283                 // Make copy of policies
284                 policies.putAll( connector.getPolicies() );
285                 // Clear out policies
286                 connector.getPolicies().clear();
287
288                 // Work thru policies. cleaning them up.
289                 for ( Entry<String, String> entry : policies.entrySet() )
290                 {
291                     String policyId = entry.getKey();
292                     String setting = entry.getValue();
293
294                     // Upgrade old policy settings.
295                     if ( "releases".equals( policyId ) || "snapshots".equals( policyId ) )
296                     {
297                         if ( "ignored".equals( setting ) )
298                         {
299                             setting = AbstractUpdatePolicy.ALWAYS;
300                         }
301                         else if ( "disabled".equals( setting ) )
302                         {
303                             setting = AbstractUpdatePolicy.NEVER;
304                         }
305                     }
306                     else if ( "cache-failures".equals( policyId ) )
307                     {
308                         if ( "ignored".equals( setting ) )
309                         {
310                             setting = CachedFailuresPolicy.NO;
311                         }
312                         else if ( "cached".equals( setting ) )
313                         {
314                             setting = CachedFailuresPolicy.YES;
315                         }
316                     }
317                     else if ( "checksum".equals( policyId ) )
318                     {
319                         if ( "ignored".equals( setting ) )
320                         {
321                             setting = ChecksumPolicy.IGNORE;
322                         }
323                     }
324
325                     // Validate existance of policy key.
326                     if ( policyExists( policyId ) )
327                     {
328                         Policy policy = findPolicy( policyId );
329                         // Does option exist?
330                         if ( !policy.getOptions().contains( setting ) )
331                         {
332                             setting = policy.getDefaultOption();
333                         }
334                         connector.addPolicy( policyId, setting );
335                     }
336                     else
337                     {
338                         // Policy key doesn't exist. Don't add it to golden version.
339                         log.warn( "Policy [" + policyId + "] does not exist." );
340                     }
341                 }
342
343                 if ( connectorValid )
344                 {
345                     config.addProxyConnector( connector );
346                 }
347             }
348
349             // Normalize the order fields in the proxy connectors.
350             Map<String, java.util.List<ProxyConnectorConfiguration>> proxyConnectorMap =
351                 config.getProxyConnectorAsMap();
352
353             for ( List<ProxyConnectorConfiguration> connectors : proxyConnectorMap.values() )
354             {
355                 // Sort connectors by order field.
356                 Collections.sort( connectors, ProxyConnectorConfigurationOrderComparator.getInstance() );
357
358                 // Normalize the order field values.
359                 int order = 1;
360                 for ( ProxyConnectorConfiguration connector : connectors )
361                 {
362                     connector.setOrder( order++ );
363                 }
364             }
365         }
366
367         return config;
368     }
369
370     private Policy findPolicy( String policyId )
371     {
372         if ( MapUtils.isEmpty( prePolicies ) )
373         {
374             log.error( "No PreDownloadPolicies found!" );
375             return null;
376         }
377
378         if ( MapUtils.isEmpty( postPolicies ) )
379         {
380             log.error( "No PostDownloadPolicies found!" );
381             return null;
382         }
383
384         Policy policy;
385
386         policy = prePolicies.get( policyId );
387         if ( policy != null )
388         {
389             return policy;
390         }
391
392         policy = postPolicies.get( policyId );
393         if ( policy != null )
394         {
395             return policy;
396         }
397
398         policy = downloadErrorPolicies.get( policyId );
399         if ( policy != null )
400         {
401             return policy;
402         }
403
404         return null;
405     }
406
407     private boolean policyExists( String policyId )
408     {
409         if ( MapUtils.isEmpty( prePolicies ) )
410         {
411             log.error( "No PreDownloadPolicies found!" );
412             return false;
413         }
414
415         if ( MapUtils.isEmpty( postPolicies ) )
416         {
417             log.error( "No PostDownloadPolicies found!" );
418             return false;
419         }
420
421         return ( prePolicies.containsKey( policyId ) || postPolicies.containsKey( policyId )
422             || downloadErrorPolicies.containsKey( policyId ) );
423     }
424
425     private Registry readDefaultConfiguration()
426     {
427         // if it contains some old configuration, remove it (Archiva 0.9)
428         registry.removeSubset( KEY );
429
430         try
431         {
432             registry.addConfigurationFromResource( "org/apache/archiva/configuration/default-archiva.xml", KEY );
433             this.isConfigurationDefaulted = true;
434         }
435         catch ( RegistryException e )
436         {
437             throw new ConfigurationRuntimeException(
438                 "Fatal error: Unable to find the built-in default configuration and load it into the registry", e );
439         }
440         return registry.getSubset( KEY );
441     }
442
443     @SuppressWarnings ( "unchecked" )
444     public synchronized void save( Configuration configuration )
445         throws IndeterminateConfigurationException, RegistryException
446     {
447         Registry section = registry.getSection( KEY + ".user" );
448         Registry baseSection = registry.getSection( KEY + ".base" );
449         if ( section == null )
450         {
451             section = baseSection;
452             if ( section == null )
453             {
454                 section = createDefaultConfigurationFile();
455             }
456         }
457         else if ( baseSection != null )
458         {
459             Collection<String> keys = baseSection.getKeys();
460             boolean foundList = false;
461             for ( Iterator<String> i = keys.iterator(); i.hasNext() && !foundList; )
462             {
463                 String key = i.next();
464
465                 // a little aggressive with the repositoryScanning and databaseScanning - should be no need to split
466                 // that configuration
467                 if ( key.startsWith( "repositories" ) || key.startsWith( "proxyConnectors" ) || key.startsWith(
468                     "networkProxies" ) || key.startsWith( "repositoryScanning" ) || key.startsWith(
469                     "remoteRepositories" ) || key.startsWith( "managedRepositories" ) || key.startsWith(
470                     "repositoryGroups" ) )
471                 {
472                     foundList = true;
473                 }
474             }
475
476             if ( foundList )
477             {
478                 this.configuration = null;
479
480                 throw new IndeterminateConfigurationException(
481                     "Configuration can not be saved when it is loaded from two sources" );
482             }
483         }
484
485         // escape all cron expressions to handle ','
486         escapeCronExpressions( configuration );
487
488         // [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.
489         if ( configuration.getManagedRepositories().isEmpty() && section != null )
490         {
491             section.removeSubset( "managedRepositories" );
492         }
493         if ( configuration.getRemoteRepositories().isEmpty() && section != null )
494         {
495             section.removeSubset( "remoteRepositories" );
496
497         }
498         if ( configuration.getProxyConnectors().isEmpty() && section != null )
499         {
500             section.removeSubset( "proxyConnectors" );
501         }
502         if ( configuration.getNetworkProxies().isEmpty() && section != null )
503         {
504             section.removeSubset( "networkProxies" );
505         }
506         if ( configuration.getLegacyArtifactPaths().isEmpty() && section != null )
507         {
508             section.removeSubset( "legacyArtifactPaths" );
509         }
510         if ( configuration.getRepositoryGroups().isEmpty() && section != null )
511         {
512             section.removeSubset( "repositoryGroups" );
513         }
514         if ( configuration.getRepositoryScanning() != null )
515         {
516             if ( configuration.getRepositoryScanning().getKnownContentConsumers().isEmpty() && section != null )
517             {
518                 section.removeSubset( "repositoryScanning.knownContentConsumers" );
519             }
520             if ( configuration.getRepositoryScanning().getInvalidContentConsumers().isEmpty() && section != null )
521             {
522                 section.removeSubset( "repositoryScanning.invalidContentConsumers" );
523             }
524         }
525
526         new ConfigurationRegistryWriter().write( configuration, section );
527         section.save();
528
529         this.configuration = unescapeExpressions( configuration );
530
531         triggerEvent( ConfigurationEvent.SAVED );
532     }
533
534     private void escapeCronExpressions( Configuration configuration )
535     {
536         for ( ManagedRepositoryConfiguration c : configuration.getManagedRepositories() )
537         {
538             c.setRefreshCronExpression( escapeCronExpression( c.getRefreshCronExpression() ) );
539         }
540
541
542     }
543
544     private Registry createDefaultConfigurationFile()
545         throws RegistryException
546     {
547         // TODO: may not be needed under commons-configuration 1.4 - check
548
549         String contents = "<configuration />";
550
551         String fileLocation = userConfigFilename;
552
553         if ( !writeFile( "user configuration", userConfigFilename, contents ) )
554         {
555             fileLocation = altConfigFilename;
556             if ( !writeFile( "alternative configuration", altConfigFilename, contents ) )
557             {
558                 throw new RegistryException(
559                     "Unable to create configuration file in either user [" + userConfigFilename + "] or alternative ["
560                         + altConfigFilename
561                         + "] locations on disk, usually happens when not allowed to write to those locations." );
562             }
563         }
564
565         // olamy hackish I know :-)
566         contents = "<configuration><xml fileName=\"" + fileLocation
567             + "\" config-forceCreate=\"true\" config-name=\"org.apache.archiva.user\"/>" + "</configuration>";
568
569         ( (CommonsConfigurationRegistry) registry ).setProperties( contents );
570
571         registry.initialize();
572
573         for ( RegistryListener regListener : registryListeners )
574         {
575             addRegistryChangeListener( regListener );
576         }
577
578         triggerEvent( ConfigurationEvent.SAVED );
579
580         Registry section = registry.getSection( KEY + ".user" );
581         return section == null ? new CommonsConfigurationRegistry( new BaseConfiguration() ) : section;
582     }
583
584     /**
585      * Attempts to write the contents to a file, if an IOException occurs, return false.
586      * <p/>
587      * The file will be created if the directory to the file exists, otherwise this will return false.
588      *
589      * @param filetype the filetype (freeform text) to use in logging messages when failure to write.
590      * @param path     the path to write to.
591      * @param contents the contents to write.
592      * @return true if write successful.
593      */
594     private boolean writeFile( String filetype, String path, String contents )
595     {
596         File file = new File( path );
597
598         try
599         {
600             // Check parent directory (if it is declared)
601             if ( file.getParentFile() != null )
602             {
603                 // Check that directory exists
604                 if ( ( file.getParentFile().exists() == false ) || ( file.getParentFile().isDirectory() == false ) )
605                 {
606                     // Directory to file must exist for file to be created
607                     return false;
608                 }
609             }
610
611             FileUtils.writeStringToFile( file, contents, "UTF-8" );
612             return true;
613         }
614         catch ( IOException e )
615         {
616             log.error( "Unable to create " + filetype + " file: " + e.getMessage(), e );
617             return false;
618         }
619     }
620
621     private void triggerEvent( int type )
622     {
623         ConfigurationEvent evt = new ConfigurationEvent( type );
624         for ( ConfigurationListener listener : listeners )
625         {
626             listener.configurationEvent( evt );
627         }
628     }
629
630     public void addListener( ConfigurationListener listener )
631     {
632         if ( listener == null )
633         {
634             return;
635         }
636
637         listeners.add( listener );
638     }
639
640     public void removeListener( ConfigurationListener listener )
641     {
642         if ( listener == null )
643         {
644             return;
645         }
646
647         listeners.remove( listener );
648     }
649
650     public void addChangeListener( RegistryListener listener )
651     {
652         addRegistryChangeListener( listener );
653
654         // keep track for later
655         registryListeners.add( listener );
656     }
657
658     private void addRegistryChangeListener( RegistryListener listener )
659     {
660         Registry section = registry.getSection( KEY + ".user" );
661         if ( section != null )
662         {
663             section.addChangeListener( listener );
664         }
665         section = registry.getSection( KEY + ".base" );
666         if ( section != null )
667         {
668             section.addChangeListener( listener );
669         }
670     }
671
672     @PostConstruct
673     public void initialize()
674     {
675
676         this.postPolicies = componentContainer.buildMapWithRole( PostDownloadPolicy.class );
677         this.prePolicies = componentContainer.buildMapWithRole( PreDownloadPolicy.class );
678         this.downloadErrorPolicies = componentContainer.buildMapWithRole( DownloadErrorPolicy.class );
679         // Resolve expressions in the userConfigFilename and altConfigFilename
680         try
681         {
682             ExpressionEvaluator expressionEvaluator = new DefaultExpressionEvaluator();
683             expressionEvaluator.addExpressionSource( new SystemPropertyExpressionSource() );
684             String userConfigFileNameSysProps = System.getProperty( "archiva.user.configFileName" );
685             if ( StringUtils.isNotBlank( userConfigFileNameSysProps ) )
686             {
687                 userConfigFilename = userConfigFileNameSysProps;
688             }
689             else
690             {
691                 userConfigFilename = expressionEvaluator.expand( userConfigFilename );
692             }
693             altConfigFilename = expressionEvaluator.expand( altConfigFilename );
694             loadConfiguration();
695             handleUpgradeConfiguration();
696         }
697         catch ( IndeterminateConfigurationException e )
698         {
699             throw new RuntimeException( "failed during upgrade from previous version" + e.getMessage(), e );
700         }
701         catch ( RegistryException e )
702         {
703             throw new RuntimeException( "failed during upgrade from previous version" + e.getMessage(), e );
704         }
705         catch ( EvaluatorException e )
706         {
707             throw new RuntimeException(
708                 "Unable to evaluate expressions found in " + "userConfigFilename or altConfigFilename.", e);
709         }
710         registry.addChangeListener( this );
711     }
712
713     /**
714      * upgrade from 1.3
715      */
716     private void handleUpgradeConfiguration()
717         throws RegistryException, IndeterminateConfigurationException
718     {
719
720         List<String> dbConsumers = Arrays.asList( "update-db-artifact", "update-db-repository-metadata" );
721
722         // remove database consumers  if here
723         List<String> intersec =
724             ListUtils.intersection( dbConsumers, configuration.getRepositoryScanning().getKnownContentConsumers() );
725
726         if ( !intersec.isEmpty() )
727         {
728
729             List<String> knowContentConsumers =
730                 new ArrayList<String>( configuration.getRepositoryScanning().getKnownContentConsumers().size() );
731             for ( String knowContentConsumer : configuration.getRepositoryScanning().getKnownContentConsumers() )
732             {
733                 if ( !dbConsumers.contains( knowContentConsumer ) )
734                 {
735                     knowContentConsumers.add( knowContentConsumer );
736                 }
737             }
738
739             configuration.getRepositoryScanning().setKnownContentConsumers( knowContentConsumers );
740         }
741
742         // ensure create-archiva-metadata is here
743         if ( !configuration.getRepositoryScanning().getKnownContentConsumers().contains( "create-archiva-metadata" ) )
744         {
745             List<String> knowContentConsumers =
746                 new ArrayList<String>( configuration.getRepositoryScanning().getKnownContentConsumers() );
747             knowContentConsumers.add( "create-archiva-metadata" );
748             configuration.getRepositoryScanning().setKnownContentConsumers( knowContentConsumers );
749         }
750
751         // ensure duplicate-artifacts is here
752         if ( !configuration.getRepositoryScanning().getKnownContentConsumers().contains( "duplicate-artifacts" ) )
753         {
754             List<String> knowContentConsumers =
755                 new ArrayList<String>( configuration.getRepositoryScanning().getKnownContentConsumers() );
756             knowContentConsumers.add( "duplicate-artifacts" );
757             configuration.getRepositoryScanning().setKnownContentConsumers( knowContentConsumers );
758         }
759         // save ??
760         //save( configuration );
761     }
762
763     public void reload()
764     {
765         this.configuration = null;
766         try
767         {
768             this.registry.initialize();
769         }
770         catch ( RegistryException e )
771         {
772             throw new ConfigurationRuntimeException( e.getMessage(), e );
773         }
774         this.initialize();
775     }
776
777     public void beforeConfigurationChange( Registry registry, String propertyName, Object propertyValue )
778     {
779         // nothing to do here
780     }
781
782     public synchronized void afterConfigurationChange( Registry registry, String propertyName, Object propertyValue )
783     {
784         configuration = null;
785     }
786
787     private String removeExpressions( String directory )
788     {
789         String value = StringUtils.replace( directory, "${appserver.base}",
790                                             registry.getString( "appserver.base", "${appserver.base}" ) );
791         value = StringUtils.replace( value, "${appserver.home}",
792                                      registry.getString( "appserver.home", "${appserver.home}" ) );
793         return value;
794     }
795
796     private String unescapeCronExpression( String cronExpression )
797     {
798         return StringUtils.replace( cronExpression, "\\,", "," );
799     }
800
801     private String escapeCronExpression( String cronExpression )
802     {
803         return StringUtils.replace( cronExpression, ",", "\\," );
804     }
805
806     private Configuration unescapeExpressions( Configuration config )
807     {
808         // TODO: for commons-configuration 1.3 only
809         for ( Iterator<ManagedRepositoryConfiguration> i = config.getManagedRepositories().iterator(); i.hasNext(); )
810         {
811             ManagedRepositoryConfiguration c = i.next();
812             c.setLocation( removeExpressions( c.getLocation() ) );
813             c.setRefreshCronExpression( unescapeCronExpression( c.getRefreshCronExpression() ) );
814         }
815
816         return config;
817     }
818
819     private Configuration checkRepositoryLocations( Configuration config )
820     {
821         // additional check for [MRM-789], ensure that the location of the default repositories 
822         // are not installed in the server installation        
823         for ( ManagedRepositoryConfiguration repo : (List<ManagedRepositoryConfiguration>) config.getManagedRepositories() )
824         {
825             String repoPath = repo.getLocation();
826             File repoLocation = new File( repoPath );
827
828             if ( repoLocation.exists() && repoLocation.isDirectory() && !repoPath.endsWith(
829                 "data/repositories/" + repo.getId() ) )
830             {
831                 repo.setLocation( repoPath + "/data/repositories/" + repo.getId() );
832             }
833         }
834
835         return config;
836     }
837
838     public String getUserConfigFilename()
839     {
840         return userConfigFilename;
841     }
842
843     public String getAltConfigFilename()
844     {
845         return altConfigFilename;
846     }
847
848     public boolean isDefaulted()
849     {
850         return this.isConfigurationDefaulted;
851     }
852
853     public Registry getRegistry()
854     {
855         return registry;
856     }
857
858     public void setRegistry( Registry registry )
859     {
860         this.registry = registry;
861     }
862
863
864     public void setUserConfigFilename( String userConfigFilename )
865     {
866         this.userConfigFilename = userConfigFilename;
867     }
868
869     public void setAltConfigFilename( String altConfigFilename )
870     {
871         this.altConfigFilename = altConfigFilename;
872     }
873 }