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