KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > hajdbc > DatabaseClusterFactory


1 /*
2  * HA-JDBC: High-Availability JDBC
3  * Copyright (c) 2004-2006 Paul Ferraro
4  *
5  * This library is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by the
7  * Free Software Foundation; either version 2.1 of the License, or (at your
8  * option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: ferraro@users.sourceforge.net
20  */

21 package net.sf.hajdbc;
22
23 import java.io.File JavaDoc;
24 import java.io.FileInputStream JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.FileWriter JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.net.MalformedURLException JavaDoc;
30 import java.net.URL JavaDoc;
31 import java.net.URLConnection JavaDoc;
32 import java.nio.channels.Channels JavaDoc;
33 import java.nio.channels.FileChannel JavaDoc;
34 import java.nio.channels.WritableByteChannel JavaDoc;
35 import java.util.ArrayList JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.List JavaDoc;
39 import java.util.Map JavaDoc;
40 import java.util.Properties JavaDoc;
41 import java.util.ResourceBundle JavaDoc;
42
43 import javax.management.MBeanServer JavaDoc;
44 import javax.management.MBeanServerFactory JavaDoc;
45 import javax.management.MalformedObjectNameException JavaDoc;
46 import javax.management.ObjectName JavaDoc;
47
48 import net.sf.hajdbc.local.LocalDatabaseCluster;
49
50 import org.jibx.runtime.BindingDirectory;
51 import org.jibx.runtime.IMarshallingContext;
52 import org.jibx.runtime.IUnmarshallingContext;
53 import org.jibx.runtime.JiBXException;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57 /**
58  * @author Paul Ferraro
59  * @version $Revision: 1433 $
60  * @since 1.0
61  */

62 public final class DatabaseClusterFactory
63 {
64     private static final String JavaDoc JMX_AGENT_PROPERTY = "ha-jdbc.jmx-agent";
65     private static final String JavaDoc CONFIGURATION_PROPERTY = "ha-jdbc.configuration";
66     
67     private static final String JavaDoc DEFAULT_RESOURCE = "ha-jdbc.xml";
68     
69     private static final String JavaDoc MBEAN_DOMAIN = "net.sf.hajdbc";
70     private static final String JavaDoc MBEAN_CLUSTER_KEY = "cluster";
71     private static final String JavaDoc MBEAN_DATABASE_KEY = "database";
72     
73     static Logger logger = LoggerFactory.getLogger(DatabaseClusterFactory.class);
74     
75     private static DatabaseClusterFactory instance = null;
76     private static ResourceBundle JavaDoc resource = ResourceBundle.getBundle(DatabaseClusterFactory.class.getName());
77         
78     /**
79      * Convenience method for constructing a standardized mbean ObjectName for this cluster.
80      * @param databaseClusterId a cluster identifier
81      * @return an ObjectName for this cluster
82      * @throws MalformedObjectNameException if the ObjectName could not be constructed
83      */

84     public static ObjectName JavaDoc getObjectName(String JavaDoc databaseClusterId) throws MalformedObjectNameException JavaDoc
85     {
86         return getObjectName(databaseClusterId, new Properties JavaDoc());
87     }
88
89     /**
90      * Convenience method for constructing a standardized mbean ObjectName for this database.
91      * @param databaseClusterId a cluster identifier
92      * @param databaseId a database identifier
93      * @return an ObjectName for this cluster
94      * @throws MalformedObjectNameException if the ObjectName could not be constructed
95      */

96     public static ObjectName JavaDoc getObjectName(String JavaDoc databaseClusterId, String JavaDoc databaseId) throws MalformedObjectNameException JavaDoc
97     {
98         Properties JavaDoc properties = new Properties JavaDoc();
99         properties.setProperty(MBEAN_DATABASE_KEY, ObjectName.quote(databaseId));
100         
101         return getObjectName(databaseClusterId, properties);
102     }
103     
104     private static ObjectName JavaDoc getObjectName(String JavaDoc databaseClusterId, Properties JavaDoc properties) throws MalformedObjectNameException JavaDoc
105     {
106         properties.setProperty(MBEAN_CLUSTER_KEY, ObjectName.quote(databaseClusterId));
107         
108         return ObjectName.getInstance(MBEAN_DOMAIN, properties);
109     }
110     
111     /**
112      * Returns the current HA-JDBC version.
113      * @return a version label
114      */

115     public static String JavaDoc getVersion()
116     {
117         return resource.getString("version");
118     }
119     
120     /**
121      * Provides access to the singleton instance of this factory object.
122      * @return a factory for creating database clusters
123      */

124     public static synchronized DatabaseClusterFactory getInstance()
125     {
126         if (instance == null)
127         {
128             instance = createDatabaseClusterFactory();
129         }
130         
131         return instance;
132     }
133     
134     /**
135      * Returns the mbean server to which the database clusters will be registered.
136      * @return an mbean server instance
137      */

138     public static MBeanServer JavaDoc getMBeanServer()
139     {
140         String JavaDoc agent = System.getProperty(JMX_AGENT_PROPERTY);
141         
142         List JavaDoc serverList = MBeanServerFactory.findMBeanServer(agent);
143         
144         if (serverList.isEmpty())
145         {
146             throw new IllegalStateException JavaDoc(Messages.getMessage(Messages.MBEAN_SERVER_NOT_FOUND));
147         }
148         
149         return MBeanServer JavaDoc.class.cast(serverList.get(0));
150     }
151     
152     /**
153      * Creates a new DatabaseClusterFactory from a configuration file.
154      * @return a factory for creating database clusters
155      */

156     private static DatabaseClusterFactory createDatabaseClusterFactory()
157     {
158         String JavaDoc resource = System.getProperty(CONFIGURATION_PROPERTY, DEFAULT_RESOURCE);
159         
160         URL JavaDoc url = getResourceURL(resource);
161         
162         logger.info(Messages.getMessage(Messages.HA_JDBC_INIT, getVersion(), url));
163         
164         InputStream JavaDoc inputStream = null;
165         
166         try
167         {
168             inputStream = url.openStream();
169             
170             IUnmarshallingContext context = BindingDirectory.getFactory(DatabaseClusterFactory.class).createUnmarshallingContext();
171             
172             DatabaseClusterFactory factory = DatabaseClusterFactory.class.cast(context.unmarshalDocument(inputStream, null));
173
174             factory.url = url;
175             
176             return factory;
177         }
178         catch (IOException JavaDoc e)
179         {
180             String JavaDoc message = Messages.getMessage(Messages.CONFIG_NOT_FOUND, url);
181             
182             logger.error(message, e);
183             
184             throw new RuntimeException JavaDoc(message, e);
185         }
186         catch (JiBXException e)
187         {
188             String JavaDoc message = Messages.getMessage(Messages.CONFIG_LOAD_FAILED, url);
189             
190             logger.error(message, e);
191             
192             throw new RuntimeException JavaDoc(message, e);
193         }
194         catch (RuntimeException JavaDoc e)
195         {
196             logger.error(e.getMessage(), e);
197             
198             throw e;
199         }
200         catch (Error JavaDoc e)
201         {
202             logger.error(e.getMessage(), e);
203             
204             throw e;
205         }
206         finally
207         {
208             if (inputStream != null)
209             {
210                 try
211                 {
212                     inputStream.close();
213                 }
214                 catch (IOException JavaDoc e)
215                 {
216                     logger.warn(e.toString(), e);
217                 }
218             }
219         }
220     }
221     
222     /**
223      * Algorithm for searching class loaders for HA-JDBC url.
224      * @param resource a resource name
225      * @return a URL for the HA-JDBC configuration resource
226      */

227     private static URL JavaDoc getResourceURL(String JavaDoc resource)
228     {
229         try
230         {
231             return new URL JavaDoc(resource);
232         }
233         catch (MalformedURLException JavaDoc e)
234         {
235             URL JavaDoc url = Thread.currentThread().getContextClassLoader().getResource(resource);
236             
237             if (url == null)
238             {
239                 url = DatabaseClusterFactory.class.getClassLoader().getResource(resource);
240             }
241
242             if (url == null)
243             {
244                 url = ClassLoader.getSystemResource(resource);
245             }
246             
247             if (url == null)
248             {
249                 throw new RuntimeException JavaDoc(Messages.getMessage(Messages.CONFIG_NOT_FOUND, resource));
250             }
251             
252             return url;
253         }
254     }
255     
256     static DatabaseCluster createDatabaseCluster(Object JavaDoc factory)
257     {
258         DatabaseClusterBuilder builder = DatabaseClusterFactory.class.cast(factory).builder;
259         
260         return (builder == null) ? new LocalDatabaseCluster() : builder.buildDatabaseCluster();
261     }
262     
263     private Map JavaDoc<String JavaDoc, DatabaseCluster> databaseClusterMap = new HashMap JavaDoc<String JavaDoc, DatabaseCluster>();
264     private Map JavaDoc<String JavaDoc, SynchronizationStrategy> synchronizationStrategyMap = new HashMap JavaDoc<String JavaDoc, SynchronizationStrategy>();
265     private DatabaseClusterBuilder builder;
266     private URL JavaDoc url;
267     
268     private DatabaseClusterFactory()
269     {
270         // Do nothing
271
}
272     
273     /**
274      * Returns the database cluster identified by the specified id
275      * @param id a database cluster identifier
276      * @return a database cluster
277      */

278     public DatabaseCluster getDatabaseCluster(String JavaDoc id)
279     {
280         DatabaseCluster databaseCluster = this.databaseClusterMap.get(id);
281         
282         if (databaseCluster == null)
283         {
284             throw new IllegalArgumentException JavaDoc(Messages.getMessage(Messages.INVALID_DATABASE_CLUSTER, id));
285         }
286         
287         return databaseCluster;
288     }
289     
290     /**
291      * Returns the synchronization strategy identified by the specified id
292      * @param id a synchronization strategy identifier
293      * @return a synchronization strategy
294      * @throws IllegalArgumentException if the specified identifier is not a valid sychronization strategy
295      */

296     public SynchronizationStrategy getSynchronizationStrategy(String JavaDoc id)
297     {
298         SynchronizationStrategy strategy = this.synchronizationStrategyMap.get(id);
299         
300         if (strategy == null)
301         {
302             throw new IllegalArgumentException JavaDoc(Messages.getMessage(Messages.INVALID_SYNC_STRATEGY, id));
303         }
304         
305         return strategy;
306     }
307     
308     /**
309      * Exports the current HA-JDBC configuration.
310      */

311     public synchronized void exportConfiguration()
312     {
313         File JavaDoc file = null;
314         WritableByteChannel JavaDoc outputChannel = null;
315         FileChannel JavaDoc fileChannel = null;
316         
317         try
318         {
319             file = this.exportToFile();
320             
321             fileChannel = new FileInputStream JavaDoc(file).getChannel();
322             
323             // We cannot use URLConnection for files becuase Sun's implementation does not support output.
324
if (this.url.getProtocol().equals("file"))
325             {
326                 outputChannel = new FileOutputStream JavaDoc(new File JavaDoc(this.url.getPath())).getChannel();
327             }
328             else
329             {
330                 URLConnection JavaDoc connection = this.url.openConnection();
331                 
332                 connection.connect();
333                 
334                 outputChannel = Channels.newChannel(connection.getOutputStream());
335             }
336             
337             fileChannel.transferTo(0, file.length(), outputChannel);
338         }
339         catch (Exception JavaDoc e)
340         {
341             logger.warn(Messages.getMessage(Messages.CONFIG_STORE_FAILED, this.url), e);
342         }
343         finally
344         {
345             if (outputChannel != null)
346             {
347                 try
348                 {
349                     outputChannel.close();
350                 }
351                 catch (IOException JavaDoc e)
352                 {
353                     logger.warn(e.toString(), e);
354                 }
355             }
356             
357             if (fileChannel != null)
358             {
359                 try
360                 {
361                     fileChannel.close();
362                 }
363                 catch (IOException JavaDoc e)
364                 {
365                     logger.warn(e.toString(), e);
366                 }
367             }
368             
369             if (file != null)
370             {
371                 file.delete();
372             }
373         }
374     }
375     
376     private File JavaDoc exportToFile() throws Exception JavaDoc
377     {
378         File JavaDoc file = File.createTempFile("ha-jdbc", ".xml");
379         
380         IMarshallingContext context = BindingDirectory.getFactory(DatabaseClusterFactory.class).createMarshallingContext();
381     
382         context.setIndent(1, System.getProperty("line.separator"), '\t');
383         
384         // This method closes the writer
385
context.marshalDocument(this, null, null, new FileWriter JavaDoc(file));
386         
387         return file;
388     }
389     
390     void addDatabaseCluster(DatabaseCluster databaseCluster) throws Exception JavaDoc
391     {
392         this.databaseClusterMap.put(databaseCluster.getId(), databaseCluster);
393         
394         try
395         {
396             databaseCluster.start();
397         }
398         catch (Exception JavaDoc e)
399         {
400             for (DatabaseCluster cluster: this.databaseClusterMap.values())
401             {
402                 cluster.stop();
403             }
404             
405             throw e;
406         }
407     }
408     
409     void addSynchronizationStrategyBuilder(SynchronizationStrategyBuilder builder) throws Exception JavaDoc
410     {
411         this.synchronizationStrategyMap.put(builder.getId(), builder.buildStrategy());
412     }
413     
414     Iterator JavaDoc<SynchronizationStrategyBuilder> getSynchronizationStrategyBuilders() throws Exception JavaDoc
415     {
416         List JavaDoc<SynchronizationStrategyBuilder> builderList = new ArrayList JavaDoc<SynchronizationStrategyBuilder>(this.synchronizationStrategyMap.size());
417         
418         for (Map.Entry JavaDoc<String JavaDoc, SynchronizationStrategy> mapEntry: this.synchronizationStrategyMap.entrySet())
419         {
420             builderList.add(SynchronizationStrategyBuilder.getBuilder(mapEntry.getKey(), mapEntry.getValue()));
421         }
422         
423         return builderList.iterator();
424     }
425     
426     Iterator JavaDoc<DatabaseCluster> getDatabaseClusters()
427     {
428         return this.databaseClusterMap.values().iterator();
429     }
430     
431     /**
432      * @see java.lang.Object#finalize()
433      */

434     @Override JavaDoc
435     protected void finalize() throws Throwable JavaDoc
436     {
437         logger.info(Messages.getMessage(Messages.SHUT_DOWN));
438         
439         for (DatabaseCluster cluster: this.databaseClusterMap.values())
440         {
441             try
442             {
443                 cluster.stop();
444             }
445             catch (Throwable JavaDoc e)
446             {
447                 logger.warn(e.getMessage(), e);
448             }
449         }
450     }
451 }
452
Popular Tags