2 Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 package com.mysql.clusterj.openjpa;
20 import com.mysql.clusterj.ClusterJFatalInternalException;
21 import com.mysql.clusterj.ClusterJHelper;
22 import com.mysql.clusterj.SessionFactory;
24 import com.mysql.clusterj.core.SessionFactoryImpl;
26 import com.mysql.clusterj.core.spi.DomainTypeHandler;
27 import com.mysql.clusterj.core.spi.DomainTypeHandlerFactory;
28 import com.mysql.clusterj.core.store.Dictionary;
29 import com.mysql.clusterj.core.util.I18NHelper;
30 import com.mysql.clusterj.core.util.Logger;
31 import com.mysql.clusterj.core.util.LoggerFactoryService;
33 import java.lang.reflect.InvocationTargetException;
34 import java.lang.reflect.Method;
35 import java.util.HashMap;
37 import java.util.Properties;
39 import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
40 import org.apache.openjpa.jdbc.meta.ClassMapping;
41 import org.apache.openjpa.lib.conf.BooleanValue;
42 import org.apache.openjpa.lib.conf.IntValue;
43 import org.apache.openjpa.lib.conf.ProductDerivations;
44 import org.apache.openjpa.lib.conf.StringValue;
47 * Default implementation of the {@link NdbOpenJPAConfiguration} interface.
48 * This implementation extends the JDBCConfiguration so both access
49 * to MySQLd via JDBC and access to Ndb via ClusterJ are supported.
50 * Type safety: The return type Map for getCacheMarshallerInstances()
51 * from the type OpenJPAConfigurationImpl needs unchecked conversion
52 * to conform to Map<String,CacheMarshaller> from the type OpenJPAConfiguration
54 @SuppressWarnings("unchecked")
55 public class NdbOpenJPAConfigurationImpl extends JDBCConfigurationImpl
56 implements NdbOpenJPAConfiguration, com.mysql.clusterj.Constants, DomainTypeHandlerFactory {
58 /** My message translator */
59 static final I18NHelper local = I18NHelper.getInstance(NdbOpenJPAConfigurationImpl.class);
62 static final Logger logger = LoggerFactoryService.getFactory().getInstance(NdbOpenJPAConfigurationImpl.class);
64 public StringValue connectString;
65 public IntValue connectRetries;
66 public IntValue connectDelay;
67 public IntValue connectVerbose;
68 public IntValue connectTimeoutBefore;
69 public IntValue connectTimeoutAfter;
70 public StringValue username;
71 public StringValue password;
72 public StringValue database;
73 public IntValue maxTransactions;
74 public BooleanValue failOnJDBCPath;
75 public SessionFactoryImpl sessionFactory;
76 private final Map<Class<?>, NdbOpenJPADomainTypeHandlerImpl<?>> domainTypeHandlerMap =
77 new HashMap<Class<?>, NdbOpenJPADomainTypeHandlerImpl<?>>();
80 * These are to bridge an incompatibility between OpenJPA 1.x and 2.x in the handling of configuration
81 * values. In 1.x, the IntValue.get() method returns int and in 2.x it returns Integer.
82 * Similarly, in 1.x BooleanValue.get() returns boolean and in 2.x it returns Boolean.
84 static private Method intValueMethod;
85 static private Method booleanValueMethod;
88 intValueMethod = IntValue.class.getMethod("get", (Class[])null);
89 booleanValueMethod = BooleanValue.class.getMethod("get", (Class[])null);
90 } catch (SecurityException e) {
91 throw new ClusterJFatalInternalException(e);
92 } catch (NoSuchMethodException e) {
93 throw new ClusterJFatalInternalException(e);
97 /** Return the int value from a configuration IntValue.
100 int getIntValue(IntValue value) {
102 return (Integer)intValueMethod.invoke(value);
103 } catch (IllegalArgumentException e) {
104 throw new ClusterJFatalInternalException(e);
105 } catch (IllegalAccessException e) {
106 throw new ClusterJFatalInternalException(e);
107 } catch (InvocationTargetException e) {
108 throw new ClusterJFatalInternalException(e);
111 /** Return the boolean value from a configuration BooleanValue.
114 boolean getBooleanValue(BooleanValue value) {
116 return (Boolean) booleanValueMethod.invoke(value);
117 } catch (IllegalArgumentException e) {
118 throw new ClusterJFatalInternalException(e);
119 } catch (IllegalAccessException e) {
120 throw new ClusterJFatalInternalException(e);
121 } catch (InvocationTargetException e) {
122 throw new ClusterJFatalInternalException(e);
126 * Default constructor. Attempts to load default properties.
128 public NdbOpenJPAConfigurationImpl() {
135 * @param loadGlobals whether to attempt to load the global properties
137 public NdbOpenJPAConfigurationImpl(boolean loadGlobals) {
138 this(true, loadGlobals);
144 * @param derivations whether to apply product derivations
145 * @param loadGlobals whether to attempt to load the global properties
147 public NdbOpenJPAConfigurationImpl(boolean derivations, boolean loadGlobals) {
150 connectString = addString("ndb.connectString");
151 connectRetries = addInt("ndb.connectRetries");
152 connectRetries.set(4);
153 connectDelay = addInt("ndb.connectDelay");
155 connectVerbose = addInt("ndb.connectVerbose");
156 connectVerbose.set(0);
157 connectTimeoutBefore = addInt("ndb.connectTimeoutBefore");
158 connectTimeoutBefore.set(30);
159 connectTimeoutAfter = addInt("ndb.connectTimeoutAfter");
160 connectTimeoutAfter.set(20);
161 username = addString("ndb.username");
162 password = addString("ndb.password");
163 database = addString("ndb.database");
164 database.set("test");
165 maxTransactions = addInt("ndb.maxTransactions");
166 maxTransactions.set(1024);
167 failOnJDBCPath = addBoolean("ndb.failOnJDBCPath");
168 failOnJDBCPath.set(false);
170 sessionFactory = null;
173 ProductDerivations.beforeConfigurationLoad(this);
181 public NdbOpenJPAConfigurationImpl(NdbOpenJPAConfiguration conf) {
184 fromProperties(conf.toProperties(false));
187 public String getConnectString() {
188 return connectString.get();
191 public void setConnectString(String value) {
192 connectString.set(value);
195 public int getConnectRetries() {
196 return getIntValue(connectRetries);
199 public void setConnectRetries(int value) {
200 connectRetries.set(value);
203 public int getConnectDelay() {
204 return getIntValue(connectDelay);
207 public void setConnectDelay(int value) {
208 connectDelay.set(value);
211 public int getConnectVerbose() {
212 return getIntValue(connectVerbose);
215 public void setConnectVerbose(int value) {
216 connectVerbose.set(value);
219 public int getConnectTimeoutBefore() {
220 return getIntValue(connectTimeoutBefore);
223 public void setConnectTimeoutBefore(int value) {
224 connectTimeoutBefore.set(value);
227 public int getConnectTimeoutAfter() {
228 return getIntValue(connectTimeoutAfter);
231 public void setConnectTimeoutAfter(int value) {
232 connectTimeoutAfter.set(value);
235 public String getUsername() {
236 return username.getString();
239 public void setUsername(String value) {
240 username.setString(value);
243 public String getPassword() {
244 return password.getString();
247 public void setPassword(String value) {
248 password.setString(value);
251 public String getDatabase() {
252 return database.getString();
255 public void setDatabase(String value) {
256 database.setString(value);
259 public int getMaxTransactions() {
260 return getIntValue(maxTransactions);
263 public void setMaxTransactions(int value) {
264 maxTransactions.set(value);
267 public boolean getFailOnJDBCPath() {
268 return getBooleanValue(failOnJDBCPath);
271 public void setFailOnJDBCPath(boolean value) {
272 failOnJDBCPath.set(value);
275 public SessionFactoryImpl getSessionFactory() {
276 if (sessionFactory == null) {
277 sessionFactory = createSessionFactory();
279 return (SessionFactoryImpl) sessionFactory;
282 public void setSessionFactory(SessionFactory value) {
283 sessionFactory = (SessionFactoryImpl) value;
286 public SessionFactoryImpl createSessionFactory() {
287 // require connectString to be specified
288 if (connectString.get() == null) {
289 throw new IllegalStateException(
290 local.message("ERR_Missing_Connect_String"));
292 // map OpenJPA properties to ClusterJ properties
293 Properties props = new Properties();
294 props.put(PROPERTY_CLUSTER_CONNECTSTRING,
295 connectString.get());
296 props.put(PROPERTY_CLUSTER_CONNECT_RETRIES,
297 connectRetries.getString());
298 props.put(PROPERTY_CLUSTER_CONNECT_DELAY,
299 connectDelay.getString());
300 props.put(PROPERTY_CLUSTER_CONNECT_VERBOSE,
301 connectVerbose.getString());
302 props.put(PROPERTY_CLUSTER_CONNECT_TIMEOUT_BEFORE,
303 connectTimeoutBefore.getString());
304 props.put(PROPERTY_CLUSTER_CONNECT_TIMEOUT_AFTER,
305 connectTimeoutAfter.getString());
306 props.put(PROPERTY_CLUSTER_DATABASE,
307 database.getString());
308 props.put(PROPERTY_CLUSTER_MAX_TRANSACTIONS,
309 maxTransactions.getString());
310 SessionFactoryImpl factory = (SessionFactoryImpl)
311 ClusterJHelper.getSessionFactory(props);
312 factory.setDomainTypeHandlerFactory(this);
316 /** Get the domain type handler for this class mapping. A cached handler is
317 * returned if possible. Synchronize on the class-to-handler map.
318 * @param cmd the openjpa class mapping
319 * @return the domain type handler
321 public NdbOpenJPADomainTypeHandlerImpl<?> getDomainTypeHandler(
322 ClassMapping cmd, Dictionary dictionary) {
323 NdbOpenJPADomainTypeHandlerImpl<?> result;
324 Class<?> domainClass = cmd.getDescribedType();
325 synchronized(domainTypeHandlerMap) {
326 result = domainTypeHandlerMap.get(domainClass);
327 if (result == null) {
328 if (logger.isDebugEnabled()) logger.debug("domain class: " + domainClass.getName());
329 result = createDomainTypeHandler(cmd, dictionary);
330 domainTypeHandlerMap.put(domainClass, result);
331 result.initializeRelations();
332 logger.info("New domain type " + result.getName()
333 + (result.isSupportedType()?" is supported.":
334 " is not known to be supported because " + result.getReasons()));
340 /** Create a new domain type handler for the class mapping.
342 * @param classMapping the openjpa class mapping
343 * @return the domain type handler
345 private NdbOpenJPADomainTypeHandlerImpl<?> createDomainTypeHandler(
346 ClassMapping classMapping, Dictionary dictionary) {
347 return new NdbOpenJPADomainTypeHandlerImpl<Object>(dictionary, classMapping, this);
351 * Free the data sources.
354 protected void preClose() {
355 if (sessionFactory != null) {
356 sessionFactory.close();
362 protected boolean isInvalidProperty(String propName) {
363 if (super.isInvalidProperty(propName))
366 // handle openjpa.ndb.SomeMisspelledProperty, but not
367 // openjpa.someotherimplementation.SomeProperty
368 String lowerCasePropName = propName.toLowerCase();
369 String[] prefixes = ProductDerivations.getConfigurationPrefixes();
370 for (int i = 0; i < prefixes.length; i++)
371 if (lowerCasePropName.startsWith(prefixes[i] + ".ndb"))
376 /** Get the domain type handler for the class. This method is called by the query
377 * handler when performing a clusterj query for an openjpa entity. The class
378 * must have already been registered via the openjpa clusterj path.
380 public <T> DomainTypeHandler<T> createDomainTypeHandler(
381 Class<T> domainClass, Dictionary dictionary) {
382 DomainTypeHandler<T> result = (DomainTypeHandler<T>) domainTypeHandlerMap.get(domainClass);
383 if (result == null) {
384 throw new ClusterJFatalInternalException(
385 local.message("ERR_Create_Domain_Type_Handler_First", domainClass.getName()));