001package org.andromda.core;
002
003import java.io.EOFException;
004import java.io.InputStream;
005import java.net.ConnectException;
006import java.net.URL;
007import org.andromda.core.common.AndroMDALogger;
008import org.andromda.core.common.ComponentContainer;
009import org.andromda.core.common.ExceptionUtils;
010import org.andromda.core.configuration.Configuration;
011import org.andromda.core.engine.Engine;
012import org.andromda.core.metafacade.ModelValidationMessage;
013import org.andromda.core.server.Client;
014import org.apache.log4j.Logger;
015
016/**
017 * The main entry point to the framework. Handles the processing of models.
018 * Facilitates Model Driven Architecture by enabling the generation of source
019 * code, configuration files, and other such artifacts from a single or multiple
020 * models.
021 *
022 * @see Engine
023 * @author Chad Brandon
024 */
025public final class AndroMDA
026{
027    /**
028     * The logger instance.
029     */
030    private static final Logger LOGGER = Logger.getLogger(AndroMDA.class);
031
032    /**
033     * The AndroMDA engine instance.
034     */
035    private Engine engine;
036
037    /**
038     * Gets a new instance of AndroMDA.
039     *
040     * @return the new instance of AndroMDA.
041     */
042    public static AndroMDA newInstance()
043    {
044        return new AndroMDA();
045    }
046
047    /**
048     * Hidden constructor.
049     */
050    private AndroMDA()
051    {
052        AndroMDALogger.initialize();
053        this.engine = Engine.newInstance();
054    }
055
056    /**
057     * Runs AndroMDA with the given configuration.
058     *
059     * @param configurationUri the URI to the configuration file that configures
060     *        AndroMDA.
061     */
062    public void run(final URL configurationUri)
063    {
064        ExceptionUtils.checkNull(
065            "configurationUri",
066            configurationUri);
067        this.run(Configuration.getInstance(configurationUri), false, null);
068    }
069
070    /**
071     * Runs AndroMDA with the given configuration.
072     *
073     * @param configurationStream the InputStream that contains the
074     *        configuration contents for configuring AndroMDA.
075     */
076    public void run(final InputStream configurationStream)
077    {
078        ExceptionUtils.checkNull(
079            "configurationStream",
080            configurationStream);
081        this.run(Configuration.getInstance(configurationStream), false, null);
082    }
083
084    /**
085     * Runs AndroMDA with the given configuration.
086     *
087     * @param configuration the String that contains the configuration contents
088     *        for configuring AndroMDA.
089     */
090    public void run(final String configuration)
091    {
092        ExceptionUtils.checkEmpty(
093            "configuration",
094            configuration);
095        this.run(Configuration.getInstance(configuration), false, null);
096    }
097
098    /**
099     * Initializes AndroMDA without running the engine.
100     *
101     * @param configuration the configuration from which to initialize AndroMDA
102     */
103    public void initialize(final Configuration configuration)
104    {
105        ExceptionUtils.checkNull(
106            "configuration",
107            configuration);
108        this.engine.initialize(configuration);
109    }
110
111    /**
112     * Initializes AndroMDA without running the engine.
113     *
114     * @param configurationStream the InputStream that contains the
115     *        configuration contents for configuring AndroMDA.
116     */
117    public void initialize(final InputStream configurationStream)
118    {
119        ExceptionUtils.checkNull(
120            "configurationStream",
121            configurationStream);
122        this.engine.initialize(Configuration.getInstance(configurationStream));
123    }
124
125    /**
126     * Initializes AndroMDA without running the engine.
127     *
128     * @param configuration the String that contains the configuration contents
129     *        for configuring AndroMDA.
130     */
131    public void initialize(final String configuration)
132    {
133        ExceptionUtils.checkEmpty(
134            "configuration",
135            configuration);
136        this.engine.initialize(Configuration.getInstance(configuration));
137    }
138
139    /**
140     * Initializes AndroMDA without running the engine.
141     *
142     * @param configurationUri the URI to the configuration file that configures
143     *        AndroMDA.
144     */
145    public void initialize(final URL configurationUri)
146    {
147        ExceptionUtils.checkNull(
148            "configurationUri",
149            configurationUri);
150        this.run(Configuration.getInstance(configurationUri), false, null);
151    }
152
153    /**
154     * Runs AndroMDA with the given configuration. Determines whether or not
155     * AndroMDA should be run in client/server mode (if the client can contact
156     * the AndroMDA server), or just stand-alone mode if the server can NOT be
157     * contacted.
158     *
159     * @param configuration the configuration instance that configures AndroMDA.
160     * @param lastModifiedCheck true=don't regenerate code if no changes made since last model update.
161     * @param historyDir Output location for model generation history file (i.e. /target/history)
162     * @return an array of model validation messages (if there have been any collected
163     *         during AndroMDA execution).
164     */
165    public ModelValidationMessage[] run(final Configuration configuration,
166        boolean lastModifiedCheck, final String historyDir)
167    {
168        ModelValidationMessage[] messages = null;
169        if (configuration != null)
170        {
171            final Client serverClient = (Client)ComponentContainer.instance().findRequiredComponent(Client.class);
172            boolean client = true;
173
174            // only attempt to run with the client, if they
175            // have a server defined in their configuration
176            if (configuration.getServer() != null)
177            {
178                try
179                {
180                    serverClient.start(configuration);
181                }
182                catch (final Throwable throwable)
183                {
184                    final Throwable cause = ExceptionUtils.getRootCause(throwable);
185                    if (cause instanceof ConnectException ||
186                        cause instanceof EOFException)
187                    {
188                        // - if we can't connect to the server, it means
189                        //   we aren't running in client mode
190                        client = false;
191                    }
192                    else
193                    {
194                        throw new RuntimeException(throwable);
195                    }
196                }
197            }
198            else
199            {
200                client = false;
201            }
202
203            // - since we aren't running in 'client' mode, run the engine as usual
204            if (!client)
205            {
206                this.engine.initialize(configuration);
207                messages = this.engine.run(configuration, lastModifiedCheck, historyDir);
208            }
209        }
210        else
211        {
212            LOGGER.warn("AndroMDA could not run because no configuration was defined");
213        }
214        return messages == null ? new ModelValidationMessage[0] : messages;
215    }
216
217    /**
218     * Shuts down AndroMDA.
219     */
220    public void shutdown()
221    {
222        this.engine.shutdown();
223    }
224}