001: /*
002: * HA-JDBC: High-Availability JDBC
003: * Copyright (c) 2004-2007 Paul Ferraro
004: *
005: * This library is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU Lesser General Public License as published by the
007: * Free Software Foundation; either version 2.1 of the License, or (at your
008: * option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
013: * for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public License
016: * along with this library; if not, write to the Free Software Foundation,
017: * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: *
019: * Contact: ferraro@users.sourceforge.net
020: */
021: package net.sf.hajdbc;
022:
023: import java.lang.management.ManagementFactory;
024: import java.lang.reflect.InvocationTargetException;
025: import java.net.MalformedURLException;
026: import java.net.URL;
027: import java.sql.SQLException;
028: import java.text.MessageFormat;
029: import java.util.Hashtable;
030: import java.util.ResourceBundle;
031:
032: import javax.management.JMException;
033: import javax.management.MBeanServer;
034: import javax.management.MBeanServerInvocationHandler;
035: import javax.management.MalformedObjectNameException;
036: import javax.management.ObjectName;
037:
038: import net.sf.hajdbc.util.SQLExceptionFactory;
039:
040: /**
041: * @author Paul Ferraro
042: */
043: public class DatabaseClusterFactory {
044: private static final String CONFIGURATION_PROPERTY = "ha-jdbc.configuration"; //$NON-NLS-1$
045: private static final String DEFAULT_RESOURCE = "ha-jdbc-{0}.xml"; //$NON-NLS-1$
046: private static final String MBEAN_CLUSTER_KEY = "cluster"; //$NON-NLS-1$
047: private static final String MBEAN_DATABASE_KEY = "database"; //$NON-NLS-1$
048: private static final String VERSION = "version"; //$NON-NLS-1$
049:
050: private static ResourceBundle resource = ResourceBundle
051: .getBundle(DatabaseClusterFactory.class.getName());
052:
053: /**
054: * Convenience method for constructing a standardized mbean ObjectName for this cluster.
055: * @param clusterId a cluster identifier
056: * @return an ObjectName for this cluster
057: * @throws MalformedObjectNameException if the ObjectName could not be constructed
058: */
059: public static ObjectName getObjectName(String clusterId)
060: throws MalformedObjectNameException {
061: return ObjectName.getInstance(getDomain(),
062: createProperties(clusterId));
063: }
064:
065: /**
066: * Convenience method for constructing a standardized mbean ObjectName for this database.
067: * @param clusterId a cluster identifier
068: * @param databaseId a database identifier
069: * @return an ObjectName for this cluster
070: * @throws MalformedObjectNameException if the ObjectName could not be constructed
071: */
072: public static ObjectName getObjectName(String clusterId,
073: String databaseId) throws MalformedObjectNameException {
074: Hashtable<String, String> properties = createProperties(clusterId);
075:
076: properties.put(MBEAN_DATABASE_KEY, databaseId);
077:
078: return ObjectName.getInstance(getDomain(), properties);
079: }
080:
081: private static Hashtable<String, String> createProperties(
082: String clusterId) {
083: Hashtable<String, String> properties = new Hashtable<String, String>();
084:
085: properties.put(MBEAN_CLUSTER_KEY, clusterId);
086:
087: return properties;
088: }
089:
090: private static String getDomain() {
091: return DatabaseClusterFactory.class.getPackage().getName();
092: }
093:
094: /**
095: * Returns the current HA-JDBC version.
096: * @return a version label
097: */
098: public static String getVersion() {
099: return resource.getString(VERSION);
100: }
101:
102: public static synchronized <C extends DatabaseCluster<?>> C getDatabaseCluster(
103: String id, Class<? extends C> targetClass,
104: Class<C> mbeanInterface, String resource)
105: throws SQLException {
106: try {
107: ObjectName name = getObjectName(id);
108:
109: MBeanServer server = ManagementFactory
110: .getPlatformMBeanServer();
111:
112: if (!server.isRegistered(name)) {
113: URL url = getResourceURL((resource == null) ? MessageFormat
114: .format(System.getProperty(
115: CONFIGURATION_PROPERTY,
116: DEFAULT_RESOURCE), id)
117: : resource);
118:
119: C cluster = targetClass.getConstructor(String.class,
120: URL.class).newInstance(id, url);
121:
122: server.registerMBean(cluster, name);
123: }
124:
125: return MBeanServerInvocationHandler.newProxyInstance(
126: server, name, mbeanInterface, false);
127: } catch (JMException e) {
128: throw SQLExceptionFactory.createSQLException(e);
129: } catch (InstantiationException e) {
130: throw SQLExceptionFactory.createSQLException(e);
131: } catch (IllegalAccessException e) {
132: throw SQLExceptionFactory.createSQLException(e);
133: } catch (NoSuchMethodException e) {
134: throw SQLExceptionFactory.createSQLException(e);
135: } catch (InvocationTargetException e) {
136: throw SQLExceptionFactory.createSQLException(e);
137: }
138: }
139:
140: /**
141: * Algorithm for searching class loaders for HA-JDBC url.
142: * @param resource a resource name
143: * @return a URL for the HA-JDBC configuration resource
144: */
145: private static URL getResourceURL(String resource)
146: throws SQLException {
147: try {
148: return new URL(resource);
149: } catch (MalformedURLException e) {
150: URL url = Thread.currentThread().getContextClassLoader()
151: .getResource(resource);
152:
153: if (url == null) {
154: url = DatabaseClusterFactory.class.getClassLoader()
155: .getResource(resource);
156: }
157:
158: if (url == null) {
159: url = ClassLoader.getSystemResource(resource);
160: }
161:
162: if (url == null) {
163: throw new SQLException(Messages.getMessage(
164: Messages.CONFIG_NOT_FOUND, resource));
165: }
166:
167: return url;
168: }
169: }
170: }
|