Added ServletContextListener for start of embedded MongoDB at Keycloak deploy. Added PropertiesManager

This commit is contained in:
mposolda 2013-10-10 09:31:16 +02:00
parent 71cd9cffa4
commit 453e1c5cf7
9 changed files with 166 additions and 27 deletions

View file

@ -123,6 +123,10 @@
<groupId>org.mongodb</groupId> <groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId> <artifactId>mongo-java-driver</artifactId>
</dependency> </dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View file

@ -21,6 +21,10 @@
<async-supported>true</async-supported> <async-supported>true</async-supported>
</servlet> </servlet>
<listener>
<listener-class>org.keycloak.services.listeners.MongoRunnerListener</listener-class>
</listener>
<filter> <filter>
<filter-name>Keycloak Session Management</filter-name> <filter-name>Keycloak Session Management</filter-name>
<filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class> <filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>

View file

@ -163,7 +163,7 @@
<dependency> <dependency>
<groupId>de.flapdoodle.embed</groupId> <groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId> <artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>

View file

@ -0,0 +1,53 @@
package org.keycloak.services.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network;
import org.jboss.resteasy.logging.Logger;
import org.keycloak.services.utils.PropertiesManager;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class MongoRunnerListener implements ServletContextListener {
protected static final Logger logger = Logger.getLogger(MongoRunnerListener.class);
private MongodExecutable mongodExe;
private MongodProcess mongod;
@Override
public void contextInitialized(ServletContextEvent sce) {
if (PropertiesManager.bootstrapEmbeddedMongoAtContextInit()) {
int port = PropertiesManager.getMongoPort();
logger.info("Going to start embedded MongoDB on port=" + port);
try {
mongodExe = MongodStarter.getDefaultInstance().prepare(new MongodConfig(Version.V2_0_5, port, Network.localhostIsIPv6()));
mongod = mongodExe.start();
} catch (Exception e) {
logger.warn("Couldn't start Embedded Mongo on port " + port + ". Maybe it's already started? Cause: " + e.getClass() + " " + e.getMessage());
if (logger.isDebugEnabled()) {
logger.debug("Failed to start MongoDB", e);
}
}
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (mongodExe != null) {
if (mongod != null) {
logger.info("Going to stop embedded MongoDB.");
mongod.stop();
}
mongodExe.stop();
}
}
}

View file

@ -8,6 +8,7 @@ import org.keycloak.models.picketlink.PicketlinkKeycloakSession;
import org.keycloak.models.picketlink.PicketlinkKeycloakSessionFactory; import org.keycloak.models.picketlink.PicketlinkKeycloakSessionFactory;
import org.keycloak.models.picketlink.mappings.ApplicationEntity; import org.keycloak.models.picketlink.mappings.ApplicationEntity;
import org.keycloak.models.picketlink.mappings.RealmEntity; import org.keycloak.models.picketlink.mappings.RealmEntity;
import org.keycloak.services.utils.PropertiesManager;
import org.keycloak.social.SocialRequestManager; import org.keycloak.social.SocialRequestManager;
import org.picketlink.idm.PartitionManager; import org.picketlink.idm.PartitionManager;
import org.picketlink.idm.config.IdentityConfigurationBuilder; import org.picketlink.idm.config.IdentityConfigurationBuilder;
@ -31,15 +32,6 @@ import java.util.Set;
*/ */
public class KeycloakApplication extends Application { public class KeycloakApplication extends Application {
public static final String SESSION_FACTORY = "keycloak.sessionFactory";
public static final String SESSION_FACTORY_PICKETLINK = "picketlink";
public static final String SESSION_FACTORY_MONGO = "mongo";
public static final String MONGO_HOST = "keycloak.mongodb.host";
public static final String MONGO_PORT = "keycloak.mongodb.port";
public static final String MONGO_DB_NAME = "keycloak.mongodb.databaseName";
public static final String MONGO_DROP_DB_ON_STARTUP = "keycloak.mongodb.dropDatabaseOnStartup";
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<?>>();
@ -65,11 +57,12 @@ public class KeycloakApplication extends Application {
} }
public static KeycloakSessionFactory buildSessionFactory() { public static KeycloakSessionFactory buildSessionFactory() {
String sessionFactoryType = System.getProperty(SESSION_FACTORY, SESSION_FACTORY_PICKETLINK); if (PropertiesManager.isMongoSessionFactory()) {
if (SESSION_FACTORY_MONGO.equals(sessionFactoryType)) {
return buildMongoDBSessionFactory(); return buildMongoDBSessionFactory();
} else { } else if (PropertiesManager.isPicketlinkSessionFactory()) {
return buildPicketlinkSessionFactory(); return buildPicketlinkSessionFactory();
} else {
throw new IllegalStateException("Unknown session factory type: " + PropertiesManager.getSessionFactoryType());
} }
} }
@ -79,10 +72,10 @@ public class KeycloakApplication extends Application {
} }
private static KeycloakSessionFactory buildMongoDBSessionFactory() { private static KeycloakSessionFactory buildMongoDBSessionFactory() {
String host = System.getProperty(MONGO_HOST, "localhost"); String host = PropertiesManager.getMongoHost();
int port = Integer.parseInt(System.getProperty(MONGO_PORT, "27017")); int port = PropertiesManager.getMongoPort();
String dbName = System.getProperty(MONGO_DB_NAME, "keycloak"); String dbName = PropertiesManager.getMongoDbName();
boolean dropDatabaseOnStartup = Boolean.parseBoolean(System.getProperty(MONGO_DROP_DB_ON_STARTUP, "true")); boolean dropDatabaseOnStartup = PropertiesManager.dropDatabaseOnStartup();
return new MongoDBSessionFactory(host, port, dbName, dropDatabaseOnStartup); return new MongoDBSessionFactory(host, port, dbName, dropDatabaseOnStartup);
} }

View file

@ -0,0 +1,82 @@
package org.keycloak.services.utils;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class PropertiesManager {
private static final String SESSION_FACTORY = "keycloak.sessionFactory";
public static final String SESSION_FACTORY_PICKETLINK = "picketlink";
public static final String SESSION_FACTORY_MONGO = "mongo";
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 getSessionFactoryType() {
return System.getProperty(SESSION_FACTORY, SESSION_FACTORY_PICKETLINK);
}
public static void setSessionFactoryType(String sessionFactoryType) {
System.setProperty(SESSION_FACTORY, sessionFactoryType);
}
public static void setDefaultSessionFactoryType() {
System.setProperty(SESSION_FACTORY, SESSION_FACTORY_PICKETLINK);
}
public static boolean isMongoSessionFactory() {
return getSessionFactoryType().equals(SESSION_FACTORY_MONGO);
}
public static boolean isPicketlinkSessionFactory() {
return getSessionFactoryType().equals(SESSION_FACTORY_PICKETLINK);
}
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

@ -8,6 +8,7 @@ import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.runtime.Network; import de.flapdoodle.embed.process.runtime.Network;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.utils.PropertiesManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -15,7 +16,7 @@ import org.keycloak.services.resources.KeycloakApplication;
public class MongoDBSessionFactoryTestContext implements SessionFactoryTestContext { public class MongoDBSessionFactoryTestContext implements SessionFactoryTestContext {
protected static final Logger logger = Logger.getLogger(MongoDBSessionFactoryTestContext.class); protected static final Logger logger = Logger.getLogger(MongoDBSessionFactoryTestContext.class);
private static final int PORT = 27777; private static final int PORT = PropertiesManager.MONGO_DEFAULT_PORT_UNIT_TESTS;
private MongodExecutable mongodExe; private MongodExecutable mongodExe;
private MongodProcess mongod; private MongodProcess mongod;
@ -42,16 +43,16 @@ public class MongoDBSessionFactoryTestContext implements SessionFactoryTestConte
} }
logger.info("MongoDB stopped successfully"); logger.info("MongoDB stopped successfully");
// Null this, so other tests are not affected // Reset this, so other tests are not affected
System.setProperty(KeycloakApplication.SESSION_FACTORY, ""); PropertiesManager.setDefaultSessionFactoryType();
} }
@Override @Override
public void initEnvironment() { public void initEnvironment() {
System.setProperty(KeycloakApplication.SESSION_FACTORY, KeycloakApplication.SESSION_FACTORY_MONGO); PropertiesManager.setSessionFactoryType(PropertiesManager.SESSION_FACTORY_MONGO);
System.setProperty(KeycloakApplication.MONGO_HOST, "localhost"); PropertiesManager.setMongoHost("localhost");
System.setProperty(KeycloakApplication.MONGO_PORT, String.valueOf(PORT)); PropertiesManager.setMongoPort(PORT);
System.setProperty(KeycloakApplication.MONGO_DB_NAME, "keycloakTest"); PropertiesManager.setMongoDbName("keycloakTest");
System.setProperty(KeycloakApplication.MONGO_DROP_DB_ON_STARTUP, "true"); PropertiesManager.setDropDatabaseOnStartup(true);
} }
} }

View file

@ -1,6 +1,7 @@
package org.keycloak.test.common; package org.keycloak.test.common;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.utils.PropertiesManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -19,6 +20,6 @@ public class PicketlinkSessionFactoryTestContext implements SessionFactoryTestCo
@Override @Override
public void initEnvironment() { public void initEnvironment() {
System.setProperty(KeycloakApplication.SESSION_FACTORY, KeycloakApplication.SESSION_FACTORY_PICKETLINK); PropertiesManager.setSessionFactoryType(PropertiesManager.SESSION_FACTORY_PICKETLINK);
} }
} }

View file

@ -9,6 +9,7 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.mongo.keycloak.adapters.RealmAdapter; import org.keycloak.models.mongo.keycloak.adapters.RealmAdapter;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.utils.PropertiesManager;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@ -51,7 +52,7 @@ public class RemoveUsersWorker implements Worker {
// TODO: Not supported in model actually. We support operation just in MongoDB // TODO: Not supported in model actually. We support operation just in MongoDB
// UserModel user = realm.removeUser(username); // UserModel user = realm.removeUser(username);
if (KeycloakApplication.SESSION_FACTORY_MONGO.equals(System.getProperty(KeycloakApplication.SESSION_FACTORY))) { if (PropertiesManager.isMongoSessionFactory()) {
RealmAdapter mongoRealm = (RealmAdapter)realm; RealmAdapter mongoRealm = (RealmAdapter)realm;
mongoRealm.removeUser(username); mongoRealm.removeUser(username);
} else { } else {