001package org.andromda.core.configuration;
002
003import java.io.InputStream;
004import java.io.InputStreamReader;
005import java.io.Serializable;
006import java.net.URL;
007import java.util.ArrayList;
008import java.util.Arrays;
009import java.util.Collection;
010import org.andromda.core.common.ResourceUtils;
011import org.andromda.core.common.XmlObjectFactory;
012import org.andromda.core.mapping.Mappings;
013import org.apache.commons.lang.StringUtils;
014
015/**
016 * This object is configured from the AndroMDA configuration
017 * XML file.  Its used to configure AndroMDA before modeling
018 * processing occurs.
019 *
020 * @author Chad Brandon
021 */
022public class Configuration
023    implements Serializable
024{
025    private static final long serialVersionUID = 34L;
026
027    /**
028     * Gets a Configuration instance from the given <code>uri</code>.
029     *
030     * @param uri the URI to the configuration file.
031     * @return the configured instance.
032     */
033    public static Configuration getInstance(final URL uri)
034    {
035        final Configuration configuration =
036            (Configuration)XmlObjectFactory.getInstance(Configuration.class).getObject(uri);
037        configuration.setContents(ResourceUtils.getContents(uri));
038        return configuration;
039    }
040
041    /**
042     * Gets a Configuration instance from the given <code>stream</code>.
043     *
044     * @param stream the InputStream containing the configuration file.
045     * @return the configured instance.
046     */
047    public static Configuration getInstance(final InputStream stream)
048    {
049        final Configuration configuration =
050            (Configuration)XmlObjectFactory.getInstance(Configuration.class).getObject(new InputStreamReader(stream));
051        configuration.setContents(ResourceUtils.getContents(new InputStreamReader(stream)));
052        return configuration;
053    }
054
055    /**
056     * Gets a Configuration instance from the given <code>string</code>.
057     *
058     * @param string the String containing the configuration.
059     * @return the configured instance.
060     */
061    public static Configuration getInstance(final String string)
062    {
063        final Configuration configuration =
064            (Configuration)XmlObjectFactory.getInstance(Configuration.class).getObject(string);
065        configuration.setContents(string);
066        return configuration;
067    }
068
069    /**
070     * Initializes this configuration instance.
071     */
072    public void initialize()
073    {
074        this.initializeNamespaces();
075        this.initializeMappings();
076    }
077
078    /**
079     * Stores the repositories for this Configuration instance.
080     */
081    private final Collection<Repository> repositories = new ArrayList<Repository>();
082
083    /**
084     * Adds the repository to this configuration.
085     *
086     * @param repository the repository instance.
087     */
088    public void addRepository(final Repository repository)
089    {
090        this.repositories.add(repository);
091    }
092
093    /**
094     * Gets the repository instances belonging to this configuration.
095     *
096     * @return the collection of repository instances.
097     */
098    public Repository[] getRepositories()
099    {
100        return this.repositories.toArray(new Repository[this.repositories.size()]);
101    }
102
103    /**
104     * Stores the configuration namespaces.
105     */
106    private final Collection<Namespace> namespaces = new ArrayList<Namespace>();
107
108    /**
109     * Adds a namespace to this configuration.
110     *
111     * @param namespace the configured namespace to add.
112     */
113    public void addNamespace(final Namespace namespace)
114    {
115        this.namespaces.add(namespace);
116    }
117
118    /**
119     * Gets the configuration namespaces.
120     *
121     * @return the array of {@link Namespace} instances.
122     */
123    public Namespace[] getNamespaces()
124    {
125        return this.namespaces.toArray(new Namespace[this.namespaces.size()]);
126    }
127
128    /**
129     * Stores the properties for this configuration (these
130     * gobally configure AndroMDA).
131     */
132    private final Collection<Property> properties = new ArrayList<Property>();
133
134    /**
135     * Adds a property to this configuration instance.
136     *
137     * @param property the property to add.
138     */
139    public void addProperty(final Property property)
140    {
141        this.properties.add(property);
142    }
143
144    /**
145     * Gets the properties belonging to this configuration.
146     *
147     * @return the collection of {@link Property} instances.
148     */
149    public Property[] getProperties()
150    {
151        return this.properties.toArray(new Property[this.properties.size()]);
152    }
153
154    /**
155     * Stores the AndroMDA server configuration information.
156     */
157    private Server server;
158
159    /**
160     * Sets the server instance for this configuration.
161     *
162     * @param server the information which configures the AndroMDA server.
163     */
164    public void setServer(final Server server)
165    {
166        this.server = server;
167    }
168
169    /**
170     * Gets the server instance for this configuration.
171     * The {@link Server} holds the information to configure
172     * the AndroMDA server.
173     *
174     * @return the andromda server.
175     */
176    public Server getServer()
177    {
178        return this.server;
179    }
180
181    /**
182     * The locations in which to search for mappings.
183     */
184    private final Collection<Location> mappingsSearchLocations = new ArrayList<Location>();
185
186    /**
187     * Adds a mappings search location (these are the locations
188     * in which a search for mappings is performed).
189     *
190     * @param location a location path.
191     * @see #addMappingsSearchLocation(String)
192     */
193    public void addMappingsSearchLocation(final Location location)
194    {
195        if (location != null)
196        {
197            this.mappingsSearchLocations.add(location);
198        }
199    }
200
201    /**
202     * Adds a mappings search location path (a location
203     * without a pattern defined).
204     *
205     * @param path a location path.
206     * @see #addMappingsSearchLocation(Location)
207     */
208    public void addMappingsSearchLocation(final String path)
209    {
210        if (path != null)
211        {
212            final Location location = new Location();
213            location.setPath(path);
214            this.mappingsSearchLocations.add(location);
215        }
216    }
217
218    /**
219     * Gets the mappings search locations for this configuration instance.
220     *
221     * @return the mappings search locations.
222     */
223    public Location[] getMappingsSearchLocations()
224    {
225        return this.mappingsSearchLocations.toArray(new Location[this.mappingsSearchLocations.size()]);
226    }
227
228    /**
229     * Stores the contents of the configuration as a string.
230     */
231    private String contents = null;
232
233    /**
234     * Gets the URI from which this instance was
235     * configured or null (it it was not set).
236     * @return the URI as a String instance
237     */
238    public String getContents()
239    {
240        return this.contents;
241    }
242
243    /**
244     * Clears out any caches used by this configuration.
245     */
246    public static void clearCaches()
247    {
248        Model.clearLastModifiedTimes();
249    }
250
251    /**
252     * Sets the contents of this configuration as a
253     * string.
254     * @param contents the contents of this configuration as a string.
255     */
256    private void setContents(final String contents)
257    {
258        this.contents = StringUtils.trimToEmpty(contents);
259    }
260
261    /**
262     * Initializes the namespaces with the namespaces from
263     * this configuration.
264     */
265    private void initializeNamespaces()
266    {
267        final Namespaces namespaces = Namespaces.instance();
268        namespaces.clear();
269        namespaces.addNamespaces(this.getNamespaces());
270    }
271
272    /**
273     * Loads all mappings from the specified mapping search locations.
274     * If the location points to a directory the directory
275     * contents will be loaded, otherwise just the mapping itself will be loaded.
276     */
277    private void initializeMappings()
278    {
279        if (this.mappingsSearchLocations != null)
280        {
281            final Collection<URL> mappingsLocations = new ArrayList<URL>();
282            final Location[] locations = this.getMappingsSearchLocations();
283            for (final Location location : locations)
284            {
285                mappingsLocations.addAll(Arrays.asList(location.getResources()));
286            }
287
288            // clear out any old cached mappings
289            Mappings.clearLogicalMappings();
290
291            for (final URL mappingsUri : mappingsLocations)
292            {
293                try
294                {
295                    Mappings.addLogicalMappings(mappingsUri);
296                }
297                catch (final Throwable throwable)
298                {
299                    // - ignore the exception (probably means its a file
300                    //   other than a mapping and in that case we don't care)
301                }
302            }
303            // - now initialize the logical mappings since we've found them all
304            Mappings.initializeLogicalMappings();
305        }
306    }
307}