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