Use service loader to load model provider

This commit is contained in:
Stian Thorgersen 2013-11-12 11:49:03 +00:00
parent 70f3ffa40c
commit 2e9a474eac
17 changed files with 142 additions and 62 deletions

View file

@ -5,5 +5,7 @@ package org.keycloak.models;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface ModelProvider { public interface ModelProvider {
String getId();
KeycloakSessionFactory createFactory(); KeycloakSessionFactory createFactory();
} }

View file

@ -11,6 +11,12 @@ import javax.persistence.Persistence;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class JpaModelProvider implements ModelProvider { public class JpaModelProvider implements ModelProvider {
@Override
public String getId() {
return "jpa";
}
@Override @Override
public KeycloakSessionFactory createFactory() { public KeycloakSessionFactory createFactory() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store"); EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-keycloak-identity-store");

View file

@ -0,0 +1 @@
org.keycloak.models.jpa.JpaModelProvider

View file

@ -0,0 +1,58 @@
package org.keycloak.models.mongo;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PropertiesManager {
private static final String MONGO_HOST = "keycloak.mongodb.host";
private static final String MONGO_PORT = "keycloak.mongodb.port";
private static final String MONGO_DB_NAME = "keycloak.mongodb.databaseName";
private static final String MONGO_DROP_DB_ON_STARTUP = "keycloak.mongodb.dropDatabaseOnStartup";
private static final String BOOTSTRAP_EMBEDDED_MONGO_AT_CONTEXT_INIT = "keycloak.mongodb.bootstrapEmbeddedMongoAtContextInit";
// Port where embedded MongoDB will be started during keycloak bootstrap. Same port will be used by KeycloakApplication then
private static final int MONGO_DEFAULT_PORT_KEYCLOAK_WAR_EMBEDDED = 37017;
// Port where MongoDB instance is normally started on linux. This port should be used if we're not starting embedded instance (keycloak.mongodb.bootstrapEmbeddedMongoAtContextInit is false)
private static final int MONGO_DEFAULT_PORT_KEYCLOAK_WAR = 27017;
// Port where unit tests will start embedded MongoDB instance
public static final int MONGO_DEFAULT_PORT_UNIT_TESTS = 27777;
public static String getMongoHost() {
return System.getProperty(MONGO_HOST, "localhost");
}
public static void setMongoHost(String mongoHost) {
System.setProperty(MONGO_HOST, mongoHost);
}
public static int getMongoPort() {
return Integer.parseInt(System.getProperty(MONGO_PORT, String.valueOf(MONGO_DEFAULT_PORT_KEYCLOAK_WAR_EMBEDDED)));
}
public static void setMongoPort(int mongoPort) {
System.setProperty(MONGO_PORT, String.valueOf(mongoPort));
}
public static String getMongoDbName() {
return System.getProperty(MONGO_DB_NAME, "keycloak");
}
public static void setMongoDbName(String mongoMongoDbName) {
System.setProperty(MONGO_DB_NAME, mongoMongoDbName);
}
public static boolean dropDatabaseOnStartup() {
return Boolean.parseBoolean(System.getProperty(MONGO_DROP_DB_ON_STARTUP, "true"));
}
public static void setDropDatabaseOnStartup(boolean dropDatabaseOnStartup) {
System.setProperty(MONGO_DROP_DB_ON_STARTUP, String.valueOf(dropDatabaseOnStartup));
}
public static boolean bootstrapEmbeddedMongoAtContextInit() {
return isMongoSessionFactory() && Boolean.parseBoolean(System.getProperty(BOOTSTRAP_EMBEDDED_MONGO_AT_CONTEXT_INIT, "true"));
}
}

View file

@ -3,13 +3,31 @@ package org.keycloak.models.mongo.keycloak;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.ModelProvider; import org.keycloak.models.ModelProvider;
import java.lang.Override;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class MongoModelProvider implements ModelProvider { public class MongoModelProvider implements ModelProvider {
@Override
public String getId() {
return "mongo";
}
@Override @Override
public KeycloakSessionFactory createFactory() { public KeycloakSessionFactory createFactory() {
return null; //To change body of implemented methods use File | Settings | File Templates. String host = PropertiesManager.getMongoHost();
int port = PropertiesManager.getMongoPort();
String dbName = PropertiesManager.getMongoDbName();
boolean dropDatabaseOnStartup = PropertiesManager.dropDatabaseOnStartup();
// Create MongoDBSessionFactory via reflection now
try {
return new MongoDBSessionFactory(host, port, dbName, dropDatabaseOnStartup);
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
} }

View file

@ -0,0 +1 @@
org.keycloak.models.mongo.keycloak.MongoModelProvider

View file

@ -37,6 +37,11 @@ public class PicketlinkModelProvider implements ModelProvider {
return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager()); return new PicketlinkKeycloakSessionFactory(emf, buildPartitionManager());
} }
@Override
public String getId() {
return "picketlink";
}
public static PartitionManager buildPartitionManager() { public static PartitionManager buildPartitionManager() {
IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder(); IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();

View file

@ -0,0 +1 @@
org.keycloak.models.picketlink.PicketlinkModelProvider

View file

@ -31,14 +31,15 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-model-picketlink</artifactId> <artifactId>keycloak-model-jpa</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>provided</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId> <artifactId>keycloak-model-picketlink</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope>
</dependency> </dependency>
<!--<dependency> <!--<dependency>

View file

@ -1,18 +1,19 @@
package org.keycloak.services.resources; package org.keycloak.services.resources;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.SkeletonKeyContextResolver; import org.keycloak.SkeletonKeyContextResolver;
import org.keycloak.models.KeycloakSessionFactory; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.ModelProvider; import org.keycloak.models.ModelProvider;
import org.keycloak.services.managers.SocialRequestManager; import org.keycloak.services.managers.SocialRequestManager;
import org.keycloak.services.managers.TokenManager; import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.utils.PropertiesManager;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.ws.rs.core.Application; import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import java.lang.reflect.Constructor;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.Set; import java.util.Set;
/** /**
@ -21,14 +22,19 @@ import java.util.Set;
*/ */
public class KeycloakApplication extends Application { public class KeycloakApplication extends Application {
private static final Logger log = Logger.getLogger(KeycloakApplication.class);
private static final String MODEL_PROVIDER = "keycloak.model";
private static final String DEFAULT_MODEL_PROVIDER = "jpa";
protected Set<Object> singletons = new HashSet<Object>(); protected Set<Object> singletons = new HashSet<Object>();
protected Set<Class<?>> classes = new HashSet<Class<?>>(); protected Set<Class<?>> classes = new HashSet<Class<?>>();
protected KeycloakSessionFactory factory; protected KeycloakSessionFactory factory;
public KeycloakApplication(@Context ServletContext context) { public KeycloakApplication(@Context ServletContext context) {
KeycloakSessionFactory f = createSessionFactory(); this.factory = createSessionFactory();
this.factory = f;
context.setAttribute(KeycloakSessionFactory.class.getName(), factory); context.setAttribute(KeycloakSessionFactory.class.getName(), factory);
//classes.add(KeycloakSessionCleanupFilter.class); //classes.add(KeycloakSessionCleanupFilter.class);
@ -41,57 +47,36 @@ public class KeycloakApplication extends Application {
classes.add(QRCodeResource.class); classes.add(QRCodeResource.class);
} }
protected KeycloakSessionFactory createSessionFactory() { public static KeycloakSessionFactory createSessionFactory() {
return buildSessionFactory(); ServiceLoader<ModelProvider> providers = ServiceLoader.load(ModelProvider.class);
} String configuredProvider = System.getProperty(MODEL_PROVIDER);
ModelProvider provider = null;
public static KeycloakSessionFactory buildSessionFactory() { if (configuredProvider != null) {
if (PropertiesManager.isMongoSessionFactory()) { for (ModelProvider p : providers) {
return buildMongoDBSessionFactory(); if (p.getId().equals(configuredProvider)) {
} else if (PropertiesManager.isPicketlinkSessionFactory()) { provider = p;
return buildPicketlinkSessionFactory(); }
} else if (PropertiesManager.isJpaSessionFactory()) { }
return buildJpaSessionFactory();
} else { } else {
throw new IllegalStateException("Unknown session factory type: " + PropertiesManager.getSessionFactoryType()); for (ModelProvider p : providers) {
if (provider == null) {
provider = p;
}
if (p.getId().equals(DEFAULT_MODEL_PROVIDER)) {
provider = p;
break;
}
} }
} }
private static KeycloakSessionFactory buildJpaSessionFactory() { if (provider != null) {
ModelProvider provider = null; log.debug("Model provider: " + provider.getId());
try {
provider = (ModelProvider)Class.forName("org.keycloak.models.jpa.JpaModelProvider").newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return provider.createFactory(); return provider.createFactory();
} }
throw new RuntimeException("Model provider not found");
private static KeycloakSessionFactory buildPicketlinkSessionFactory() {
ModelProvider provider = null;
try {
provider = (ModelProvider)Class.forName("org.keycloak.models.picketlink.PicketlinkModelProvider").newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return provider.createFactory();
}
private static KeycloakSessionFactory buildMongoDBSessionFactory() {
String host = PropertiesManager.getMongoHost();
int port = PropertiesManager.getMongoPort();
String dbName = PropertiesManager.getMongoDbName();
boolean dropDatabaseOnStartup = PropertiesManager.dropDatabaseOnStartup();
// Create MongoDBSessionFactory via reflection now
try {
Class<? extends KeycloakSessionFactory> mongoDBSessionFactoryClass = (Class<? extends KeycloakSessionFactory>)Class.forName("org.keycloak.models.mongo.keycloak.adapters.MongoDBSessionFactory");
Constructor<? extends KeycloakSessionFactory> constr = mongoDBSessionFactoryClass.getConstructor(String.class, int.class, String.class, boolean.class);
return constr.newInstance(host, port, dbName, dropDatabaseOnStartup);
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
public KeycloakSessionFactory getFactory() { public KeycloakSessionFactory getFactory() {
@ -103,9 +88,6 @@ public class KeycloakApplication extends Application {
factory.close(); factory.close();
} }
@Override @Override
public Set<Class<?>> getClasses() { public Set<Class<?>> getClasses() {
return classes; return classes;

View file

@ -31,7 +31,7 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest {
@Before @Before
public void before() throws Exception { public void before() throws Exception {
factory = KeycloakApplication.buildSessionFactory(); factory = KeycloakApplication.createSessionFactory();
identitySession = factory.createSession(); identitySession = factory.createSession();
identitySession.getTransaction().begin(); identitySession.getTransaction().begin();
manager = new RealmManager(identitySession); manager = new RealmManager(identitySession);

View file

@ -23,7 +23,7 @@ public class ModelTest extends AbstractKeycloakServerTest {
@Before @Before
public void before() throws Exception { public void before() throws Exception {
factory = KeycloakApplication.buildSessionFactory(); factory = KeycloakApplication.createSessionFactory();
identitySession = factory.createSession(); identitySession = factory.createSession();
identitySession.getTransaction().begin(); identitySession.getTransaction().begin();
manager = new RealmManager(identitySession); manager = new RealmManager(identitySession);

View file

@ -26,7 +26,7 @@ public class UserModelTest extends AbstractKeycloakServerTest {
@Before @Before
public void before() throws Exception { public void before() throws Exception {
factory = KeycloakApplication.buildSessionFactory(); factory = KeycloakApplication.createSessionFactory();
identitySession = factory.createSession(); identitySession = factory.createSession();
identitySession.getTransaction().begin(); identitySession.getTransaction().begin();
manager = new RealmManager(identitySession); manager = new RealmManager(identitySession);

View file

@ -72,7 +72,7 @@ public abstract class AbstractKeycloakTest {
@Before @Before
public void before() throws Exception { public void before() throws Exception {
testContext.initEnvironment(); testContext.initEnvironment();
factory = KeycloakApplication.buildSessionFactory(); factory = KeycloakApplication.createSessionFactory();
identitySession = factory.createSession(); identitySession = factory.createSession();
identitySession.getTransaction().begin(); identitySession.getTransaction().begin();
realmManager = new RealmManager(identitySession); realmManager = new RealmManager(identitySession);

View file

@ -51,6 +51,11 @@
<artifactId>keycloak-services</artifactId> <artifactId>keycloak-services</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-model-jpa</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-social-core</artifactId> <artifactId>keycloak-social-core</artifactId>

View file

@ -271,7 +271,7 @@ public class KeycloakServer {
server.deploy(di); server.deploy(di);
factory = KeycloakApplication.buildSessionFactory(); factory = KeycloakApplication.createSessionFactory();
setupDefaultRealm(); setupDefaultRealm();

View file

@ -22,7 +22,7 @@ public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
@Override @Override
public KeycloakSessionFactory call() throws Exception { public KeycloakSessionFactory call() throws Exception {
return KeycloakApplication.buildSessionFactory(); return KeycloakApplication.createSessionFactory();
} }
}); });