001package com.avaje.ebean; 002 003import com.avaje.ebean.common.SpiContainer; 004import com.avaje.ebean.config.ContainerConfig; 005import com.avaje.ebean.config.ServerConfig; 006import com.avaje.ebeaninternal.server.lib.ShutdownManager; 007 008import javax.persistence.PersistenceException; 009import java.lang.reflect.Constructor; 010import java.util.Properties; 011 012/** 013 * Creates EbeanServer instances. 014 * <p> 015 * This uses either a ServerConfig or properties in the ebean.properties file to 016 * configure and create a EbeanServer instance. 017 * </p> 018 * <p> 019 * The EbeanServer instance can either be registered with the Ebean singleton or 020 * not. The Ebean singleton effectively holds a map of EbeanServers by a name. 021 * If the EbeanServer is registered with the Ebean singleton you can retrieve it 022 * later via {@link Ebean#getServer(String)}. 023 * </p> 024 * <p> 025 * One EbeanServer can be nominated as the 'default/primary' EbeanServer. Many 026 * methods on the Ebean singleton such as {@link Ebean#find(Class)} are just a 027 * convenient way of using the 'default/primary' EbeanServer. 028 * </p> 029 */ 030public class EbeanServerFactory { 031 032 033 private static final String DEFAULT_CONTAINER = "com.avaje.ebeaninternal.server.core.DefaultContainer"; 034 035 private static SpiContainer container; 036 037 /** 038 * Initialise the container with clustering configuration. 039 * 040 * Call this prior to creating any EbeanServer instances or alternatively set the 041 * ContainerConfig on the ServerConfig when creating the first EbeanServer instance. 042 */ 043 public static synchronized void initialiseContainer(ContainerConfig containerConfig) { 044 getContainer(containerConfig); 045 } 046 047 /** 048 * Create using ebean.properties to configure the server. 049 */ 050 public static synchronized EbeanServer create(String name) { 051 052 // construct based on loading properties files 053 // and if invoked by Ebean then it handles registration 054 SpiContainer serverFactory = getContainer(null); 055 return serverFactory.createServer(name); 056 } 057 058 /** 059 * Create using the ServerConfig object to configure the server. 060 */ 061 public static synchronized EbeanServer create(ServerConfig config) { 062 063 if (config.getName() == null) { 064 throw new PersistenceException("The name is null (it is required)"); 065 } 066 067 EbeanServer server = createInternal(config); 068 069 if (config.isDefaultServer()) { 070 PrimaryServer.setSkip(true); 071 } 072 if (config.isRegister()) { 073 Ebean.register(server, config.isDefaultServer()); 074 } 075 076 return server; 077 } 078 079 /** 080 * Create using the ServerConfig additionally specifying a classLoader to use as the context class loader. 081 */ 082 public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) { 083 084 ClassLoader currentContextLoader = Thread.currentThread().getContextClassLoader(); 085 Thread.currentThread().setContextClassLoader(classLoader); 086 try { 087 return EbeanServerFactory.create(config); 088 089 } finally { 090 // set the currentContextLoader back 091 Thread.currentThread().setContextClassLoader(currentContextLoader); 092 } 093 } 094 095 /** 096 * Shutdown gracefully all EbeanServers cleaning up any resources as required. 097 * <p> 098 * This is typically invoked via JVM shutdown hook and not explicitly called. 099 * </p> 100 */ 101 public static synchronized void shutdown() { 102 ShutdownManager.shutdown(); 103 } 104 105 106 private static EbeanServer createInternal(ServerConfig config) { 107 108 return getContainer(config.getContainerConfig()).createServer(config); 109 } 110 111 /** 112 * Get the EbeanContainer initialising it if necessary. 113 * 114 * @param containerConfig the configuration controlling clustering communication 115 */ 116 private static SpiContainer getContainer(ContainerConfig containerConfig) { 117 118 // thread safe in that all calling methods are synchronized 119 if (container != null) { 120 return container; 121 } 122 123 if (containerConfig == null) { 124 // effectively load configuration from ebean.properties 125 Properties properties = PrimaryServer.getProperties(); 126 containerConfig = new ContainerConfig(); 127 containerConfig.loadFromProperties(properties); 128 } 129 container = createContainer(containerConfig); 130 return container; 131 } 132 133 /** 134 * Create the container instance using the configuration. 135 */ 136 protected static SpiContainer createContainer(ContainerConfig containerConfig) { 137 138 String implClassName = System.getProperty("ebean.container", DEFAULT_CONTAINER); 139 140 try { 141 Class<?> cls = Class.forName(implClassName); 142 Constructor<?> constructor = cls.getConstructor(ContainerConfig.class); 143 return (SpiContainer) constructor.newInstance(containerConfig); 144 } catch (Exception ex) { 145 throw new RuntimeException(ex); 146 } 147 } 148}