001/*
002 *  jDTAUS Core API
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.core.container;
022
023import java.lang.reflect.Constructor;
024import java.lang.reflect.InvocationTargetException;
025import java.lang.reflect.Method;
026
027/**
028 * Factory for the {@code Model} singleton.
029 *
030 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
031 * @version $JDTAUS: ModelFactory.java 8743 2012-10-07 03:06:20Z schulte $
032 */
033public abstract class ModelFactory
034{
035    //--Constants---------------------------------------------------------------
036
037    /** Default {@code Model} implementation. */
038    private static final String DEFAULT_MODEL =
039        "org.jdtaus.core.container.ri.client.DefaultModel";
040
041    /** Empty array. */
042    private static final Class[] EMPTY =
043    {
044    };
045
046    //---------------------------------------------------------------Constants--
047    //--ModelFactory------------------------------------------------------------
048
049    /** Default singleton instance. */
050    private static Model instance;
051
052    /**
053     * Gets the {@code Model} singleton.
054     * <p>By default this class will instantiate a new instance and hold it in
055     * a static class variable as the singleton to return for other calls. This
056     * behaviour can be changed by setting a system property with key
057     * {@code org.jdtaus.core.container.ModelFactory} to the name of a
058     * class defining a {@code public static Model getModel()} method
059     * returning the singleton instance of the model.</p>
060     *
061     * @return the singleton {@code Model} instance.
062     *
063     * @throws ModelError for unrecoverable model errors.
064     *
065     * @see ModelFactory#newModel()
066     */
067    public static Model getModel()
068    {
069        Object ret = null;
070        final String factory = System.getProperty(
071            ModelFactory.class.getName() );
072
073        try
074        {
075            if ( factory != null )
076            {
077                // Call getModel() on that class.
078                final Class clazz = ClassLoaderFactory.loadClass(
079                    ModelFactory.class, factory );
080
081                final Method meth = clazz.getDeclaredMethod( "getModel",
082                                                             EMPTY );
083
084                ret = meth.invoke( null, EMPTY );
085            }
086            else
087            {
088                if ( instance == null )
089                {
090                    instance = newModel();
091                }
092
093                ret = instance;
094            }
095
096            return (Model) ret;
097        }
098        catch ( final SecurityException e )
099        {
100            throw new ModelError( e );
101        }
102        catch ( final NoSuchMethodException e )
103        {
104            throw new ModelError( e );
105        }
106        catch ( final IllegalAccessException e )
107        {
108            throw new ModelError( e );
109        }
110        catch ( final InvocationTargetException e )
111        {
112            final Throwable targetException = e.getTargetException();
113
114            if ( targetException instanceof Error )
115            {
116                throw (Error) targetException;
117            }
118            else if ( targetException instanceof RuntimeException )
119            {
120                throw (RuntimeException) targetException;
121            }
122            else
123            {
124                throw new ModelError( targetException == null
125                                      ? e
126                                      : targetException );
127
128            }
129        }
130        catch ( final ClassCastException e )
131        {
132            throw new ModelError( e );
133        }
134        catch ( final ClassNotFoundException e )
135        {
136            throw new ModelError( e );
137        }
138    }
139
140    /**
141     * Creates a new instance of the configured {@code Model} implementation.
142     * <p>The implementation to be used can be controlled via a system property
143     * with key {@code org.jdtaus.core.container.Model} set to a class
144     * name to be loaded as the {@code Model} implementation.</p>
145     * <p>This method should be used by {@code getModel()} implementors to
146     * retrieve a new {@code Model} instance.</p>
147     *
148     * @return a new instance of the configured {@code Model} implementation.
149     *
150     * @throws ModelError for unrecoverable model errors.
151     */
152    public static Model newModel()
153    {
154        Constructor ctor = null;
155
156        try
157        {
158            final String className = System.getProperty( Model.class.getName(),
159                                                         DEFAULT_MODEL );
160
161            final Class clazz = ClassLoaderFactory.loadClass(
162                ModelFactory.class, className );
163
164            ctor = clazz.getDeclaredConstructor( EMPTY );
165            ctor.setAccessible( true );
166            return (Model) ctor.newInstance( EMPTY );
167        }
168        catch ( final SecurityException e )
169        {
170            throw new ModelError( e );
171        }
172        catch ( final NoSuchMethodException e )
173        {
174            throw new ModelError( e );
175        }
176        catch ( final IllegalArgumentException e )
177        {
178            throw new ModelError( e );
179        }
180        catch ( final IllegalAccessException e )
181        {
182            throw new ModelError( e );
183        }
184        catch ( final java.lang.InstantiationException e )
185        {
186            throw new ModelError( e );
187        }
188        catch ( final InvocationTargetException e )
189        {
190            final Throwable targetException = e.getTargetException();
191
192            if ( targetException instanceof Error )
193            {
194                throw (Error) targetException;
195            }
196            else if ( targetException instanceof RuntimeException )
197            {
198                throw (RuntimeException) targetException;
199            }
200            else
201            {
202                throw new ModelError( targetException == null
203                                      ? e
204                                      : targetException );
205
206            }
207        }
208        catch ( final ClassCastException e )
209        {
210            throw new ModelError( e );
211        }
212        catch ( final ClassNotFoundException e )
213        {
214            throw new ModelError( e );
215        }
216        finally
217        {
218            if ( ctor != null )
219            {
220                ctor.setAccessible( false );
221            }
222        }
223    }
224
225    //------------------------------------------------------------ModelFactory--
226}