1 21 package net.sf.hajdbc; 22 23 import java.io.File ; 24 import java.io.FileInputStream ; 25 import java.io.FileOutputStream ; 26 import java.io.FileWriter ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.net.MalformedURLException ; 30 import java.net.URL ; 31 import java.net.URLConnection ; 32 import java.nio.channels.Channels ; 33 import java.nio.channels.FileChannel ; 34 import java.nio.channels.WritableByteChannel ; 35 import java.util.ArrayList ; 36 import java.util.HashMap ; 37 import java.util.Iterator ; 38 import java.util.List ; 39 import java.util.Map ; 40 import java.util.Properties ; 41 import java.util.ResourceBundle ; 42 43 import javax.management.MBeanServer ; 44 import javax.management.MBeanServerFactory ; 45 import javax.management.MalformedObjectNameException ; 46 import javax.management.ObjectName ; 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 62 public final class DatabaseClusterFactory 63 { 64 private static final String JMX_AGENT_PROPERTY = "ha-jdbc.jmx-agent"; 65 private static final String CONFIGURATION_PROPERTY = "ha-jdbc.configuration"; 66 67 private static final String DEFAULT_RESOURCE = "ha-jdbc.xml"; 68 69 private static final String MBEAN_DOMAIN = "net.sf.hajdbc"; 70 private static final String MBEAN_CLUSTER_KEY = "cluster"; 71 private static final String MBEAN_DATABASE_KEY = "database"; 72 73 static Logger logger = LoggerFactory.getLogger(DatabaseClusterFactory.class); 74 75 private static DatabaseClusterFactory instance = null; 76 private static ResourceBundle resource = ResourceBundle.getBundle(DatabaseClusterFactory.class.getName()); 77 78 84 public static ObjectName getObjectName(String databaseClusterId) throws MalformedObjectNameException 85 { 86 return getObjectName(databaseClusterId, new Properties ()); 87 } 88 89 96 public static ObjectName getObjectName(String databaseClusterId, String databaseId) throws MalformedObjectNameException 97 { 98 Properties properties = new Properties (); 99 properties.setProperty(MBEAN_DATABASE_KEY, ObjectName.quote(databaseId)); 100 101 return getObjectName(databaseClusterId, properties); 102 } 103 104 private static ObjectName getObjectName(String databaseClusterId, Properties properties) throws MalformedObjectNameException 105 { 106 properties.setProperty(MBEAN_CLUSTER_KEY, ObjectName.quote(databaseClusterId)); 107 108 return ObjectName.getInstance(MBEAN_DOMAIN, properties); 109 } 110 111 115 public static String getVersion() 116 { 117 return resource.getString("version"); 118 } 119 120 124 public static synchronized DatabaseClusterFactory getInstance() 125 { 126 if (instance == null) 127 { 128 instance = createDatabaseClusterFactory(); 129 } 130 131 return instance; 132 } 133 134 138 public static MBeanServer getMBeanServer() 139 { 140 String agent = System.getProperty(JMX_AGENT_PROPERTY); 141 142 List serverList = MBeanServerFactory.findMBeanServer(agent); 143 144 if (serverList.isEmpty()) 145 { 146 throw new IllegalStateException (Messages.getMessage(Messages.MBEAN_SERVER_NOT_FOUND)); 147 } 148 149 return MBeanServer .class.cast(serverList.get(0)); 150 } 151 152 156 private static DatabaseClusterFactory createDatabaseClusterFactory() 157 { 158 String resource = System.getProperty(CONFIGURATION_PROPERTY, DEFAULT_RESOURCE); 159 160 URL url = getResourceURL(resource); 161 162 logger.info(Messages.getMessage(Messages.HA_JDBC_INIT, getVersion(), url)); 163 164 InputStream 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 e) 179 { 180 String message = Messages.getMessage(Messages.CONFIG_NOT_FOUND, url); 181 182 logger.error(message, e); 183 184 throw new RuntimeException (message, e); 185 } 186 catch (JiBXException e) 187 { 188 String message = Messages.getMessage(Messages.CONFIG_LOAD_FAILED, url); 189 190 logger.error(message, e); 191 192 throw new RuntimeException (message, e); 193 } 194 catch (RuntimeException e) 195 { 196 logger.error(e.getMessage(), e); 197 198 throw e; 199 } 200 catch (Error 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 e) 215 { 216 logger.warn(e.toString(), e); 217 } 218 } 219 } 220 } 221 222 227 private static URL getResourceURL(String resource) 228 { 229 try 230 { 231 return new URL (resource); 232 } 233 catch (MalformedURLException e) 234 { 235 URL 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 (Messages.getMessage(Messages.CONFIG_NOT_FOUND, resource)); 250 } 251 252 return url; 253 } 254 } 255 256 static DatabaseCluster createDatabaseCluster(Object factory) 257 { 258 DatabaseClusterBuilder builder = DatabaseClusterFactory.class.cast(factory).builder; 259 260 return (builder == null) ? new LocalDatabaseCluster() : builder.buildDatabaseCluster(); 261 } 262 263 private Map <String , DatabaseCluster> databaseClusterMap = new HashMap <String , DatabaseCluster>(); 264 private Map <String , SynchronizationStrategy> synchronizationStrategyMap = new HashMap <String , SynchronizationStrategy>(); 265 private DatabaseClusterBuilder builder; 266 private URL url; 267 268 private DatabaseClusterFactory() 269 { 270 } 272 273 278 public DatabaseCluster getDatabaseCluster(String id) 279 { 280 DatabaseCluster databaseCluster = this.databaseClusterMap.get(id); 281 282 if (databaseCluster == null) 283 { 284 throw new IllegalArgumentException (Messages.getMessage(Messages.INVALID_DATABASE_CLUSTER, id)); 285 } 286 287 return databaseCluster; 288 } 289 290 296 public SynchronizationStrategy getSynchronizationStrategy(String id) 297 { 298 SynchronizationStrategy strategy = this.synchronizationStrategyMap.get(id); 299 300 if (strategy == null) 301 { 302 throw new IllegalArgumentException (Messages.getMessage(Messages.INVALID_SYNC_STRATEGY, id)); 303 } 304 305 return strategy; 306 } 307 308 311 public synchronized void exportConfiguration() 312 { 313 File file = null; 314 WritableByteChannel outputChannel = null; 315 FileChannel fileChannel = null; 316 317 try 318 { 319 file = this.exportToFile(); 320 321 fileChannel = new FileInputStream (file).getChannel(); 322 323 if (this.url.getProtocol().equals("file")) 325 { 326 outputChannel = new FileOutputStream (new File (this.url.getPath())).getChannel(); 327 } 328 else 329 { 330 URLConnection 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 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 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 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 exportToFile() throws Exception 377 { 378 File 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 context.marshalDocument(this, null, null, new FileWriter (file)); 386 387 return file; 388 } 389 390 void addDatabaseCluster(DatabaseCluster databaseCluster) throws Exception 391 { 392 this.databaseClusterMap.put(databaseCluster.getId(), databaseCluster); 393 394 try 395 { 396 databaseCluster.start(); 397 } 398 catch (Exception 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 410 { 411 this.synchronizationStrategyMap.put(builder.getId(), builder.buildStrategy()); 412 } 413 414 Iterator <SynchronizationStrategyBuilder> getSynchronizationStrategyBuilders() throws Exception 415 { 416 List <SynchronizationStrategyBuilder> builderList = new ArrayList <SynchronizationStrategyBuilder>(this.synchronizationStrategyMap.size()); 417 418 for (Map.Entry <String , 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 <DatabaseCluster> getDatabaseClusters() 427 { 428 return this.databaseClusterMap.values().iterator(); 429 } 430 431 434 @Override 435 protected void finalize() throws Throwable 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 e) 446 { 447 logger.warn(e.getMessage(), e); 448 } 449 } 450 } 451 } 452 | Popular Tags |