1 /*
2 * Copyright (C) Christian Schulte, 2012-22
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * o Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * o Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $JOMC: ModelContextFactory.java 4760 2013-04-08 17:56:26Z schulte $
29 *
30 */
31 package org.jomc.modlet;
32
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.text.MessageFormat;
36 import java.util.Locale;
37 import java.util.ResourceBundle;
38
39 /**
40 * Interface to creating model contexts.
41 *
42 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
43 * @version $JOMC: ModelContextFactory.java 4760 2013-04-08 17:56:26Z schulte $
44 * @since 1.2
45 */
46 public abstract class ModelContextFactory
47 {
48
49 /** Constant for the name of the default {@code ModelContextFactory} implementation. */
50 private static final String DEFAULT_MODEL_CONTEXT_FACTORY_CLASS_NAME = "org.jomc.modlet.DefaultModelContextFactory";
51
52 /** Constant for the name of the system property controlling {@code ModelContextFactory} implementations. */
53 private static final String MODEL_CONTEXT_FACTORY_CLASS_NAME_PROPERTY =
54 "org.jomc.modlet.ModelContextFactory";
55
56 /** Creates a new {@code ModelContextFactory} instance. */
57 protected ModelContextFactory()
58 {
59 super();
60 }
61
62 /**
63 * Creates a new {@code ModelContextFactory} instance.
64 * <p>The name of the class providing the {@code ModelContextFactory} implementation loaded by this method is
65 * controlled by system property {@code org.jomc.modlet.ModelContextFactory}. If that property is not set, this
66 * methods returns a new default instance.</p>
67 *
68 * @return A new {@code ModelContextFactory} instance.
69 *
70 * @throws ModelContextFactoryError if creating a new instance fails.
71 */
72 public static ModelContextFactory newInstance() throws ModelContextFactoryError
73 {
74 return newInstance( AccessController.doPrivileged( new PrivilegedAction<String>()
75 {
76
77 public String run()
78 {
79 return System.getProperty( MODEL_CONTEXT_FACTORY_CLASS_NAME_PROPERTY,
80 DEFAULT_MODEL_CONTEXT_FACTORY_CLASS_NAME );
81
82 }
83
84 } ) );
85 }
86
87 /**
88 * Creates a new {@code ModelContextFactory} instance.
89 *
90 * @param factoryClassName The name of the {@code ModelContextFactory} class to create an instance of.
91 *
92 * @return A new {@code ModelContextFactory} instance.
93 *
94 * @throws NullPointerException if {@code factoryClassName} is {@code null}.
95 * @throws ModelContextFactoryError if creating a new instance fails.
96 */
97 public static ModelContextFactory newInstance( final String factoryClassName ) throws ModelContextFactoryError
98 {
99 if ( factoryClassName == null )
100 {
101 throw new NullPointerException( "factoryClassName" );
102 }
103
104 try
105 {
106 final Class<?> factoryClass = Class.forName( factoryClassName );
107
108 if ( !ModelContextFactory.class.isAssignableFrom( factoryClass ) )
109 {
110 throw new ModelContextFactoryError( getMessage( "illegalFactory", factoryClassName,
111 ModelContextFactory.class.getName() ) );
112
113 }
114
115 return factoryClass.asSubclass( ModelContextFactory.class ).newInstance();
116 }
117 catch ( final ClassNotFoundException e )
118 {
119 throw new ModelContextFactoryError( getMessage( "classNotFound", factoryClassName ), e );
120 }
121 catch ( final InstantiationException e )
122 {
123 final String message = getMessage( e );
124 throw new ModelContextFactoryError( getMessage( "instantiationException", factoryClassName,
125 message != null ? " " + message : "" ), e );
126
127 }
128 catch ( final IllegalAccessException e )
129 {
130 final String message = getMessage( e );
131 throw new ModelContextFactoryError( getMessage( "accessDenied", factoryClassName,
132 message != null ? " " + message : "" ), e );
133
134 }
135 }
136
137 /**
138 * Creates a new {@code ModelContext} instance.
139 *
140 * @return A new {@code ModelContext} instance.
141 */
142 public abstract ModelContext newModelContext();
143
144 /**
145 * Creates a new {@code ModelContext} instance.
146 *
147 * @param classLoader The class loader to create a new instance with or {@code null}, to create a new instance
148 * using the bootstrap class loader.
149 *
150 * @return A new {@code ModelContext} instance for {@code classLoader}.
151 */
152 public abstract ModelContext newModelContext( final ClassLoader classLoader );
153
154 private static String getMessage( final String key, final Object... args )
155 {
156 return MessageFormat.format( ResourceBundle.getBundle( ModelContextFactory.class.getName().replace( '.', '/' ),
157 Locale.getDefault() ).getString( key ), args );
158
159 }
160
161 private static String getMessage( final Throwable t )
162 {
163 return t != null
164 ? t.getMessage() != null && t.getMessage().trim().length() > 0
165 ? t.getMessage()
166 : getMessage( t.getCause() )
167 : null;
168
169 }
170
171 }