diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/AbstractAttributedNoSQLObject.java b/services/src/main/java/org/keycloak/services/models/nosql/api/AbstractAttributedNoSQLObject.java
index efdddee67c..a3a6ddb1bf 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/AbstractAttributedNoSQLObject.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/AbstractAttributedNoSQLObject.java
@@ -7,7 +7,7 @@ import java.util.Map;
/**
* @author Marek Posolda
*/
-public abstract class AbstractAttributedNoSQLObject implements AttributedNoSQLObject {
+public abstract class AbstractAttributedNoSQLObject extends AbstractNoSQLObject implements AttributedNoSQLObject {
// Simple hashMap for now (no thread-safe)
private Map attributes = new HashMap();
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/AbstractNoSQLObject.java b/services/src/main/java/org/keycloak/services/models/nosql/api/AbstractNoSQLObject.java
new file mode 100644
index 0000000000..692839bc00
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/AbstractNoSQLObject.java
@@ -0,0 +1,12 @@
+package org.keycloak.services.models.nosql.api;
+
+/**
+ * @author Marek Posolda
+ */
+public abstract class AbstractNoSQLObject implements NoSQLObject {
+
+ @Override
+ public void afterRemove(NoSQL noSQL) {
+ // Empty by default
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java
index c3081b05a9..1b28fd1e33 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQL.java
@@ -3,6 +3,7 @@ package org.keycloak.services.models.nosql.api;
import java.util.List;
import org.keycloak.services.models.nosql.api.query.NoSQLQuery;
+import org.keycloak.services.models.nosql.api.query.NoSQLQueryBuilder;
/**
* @author Marek Posolda
@@ -26,4 +27,6 @@ public interface NoSQL {
void removeObject(Class extends NoSQLObject> type, String oid);
void removeObjects(Class extends NoSQLObject> type, NoSQLQuery query);
+
+ NoSQLQueryBuilder createQueryBuilder();
}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLField.java b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLField.java
index c3e0586d2f..8c5d2a2940 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLField.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLField.java
@@ -16,7 +16,5 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Retention(RUNTIME)
public @interface NoSQLField {
- String fieldName() default "";
-
- // TODO: add lazy loading?
+ // TODO: fieldName add lazy loading?
}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLObject.java b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLObject.java
index 1f430b6f5a..7d31b68700 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLObject.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/NoSQLObject.java
@@ -1,9 +1,16 @@
package org.keycloak.services.models.nosql.api;
/**
- * Just marker interface
+ * Base interface for object, which is persisted in NoSQL database
*
* @author Marek Posolda
*/
public interface NoSQLObject {
+
+ /**
+ * Lifecycle callback, which is called after removal of this object from NoSQL database.
+ * It may be useful for triggering removal of wired objects.
+ */
+ void afterRemove(NoSQL noSQL);
+
}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/query/NoSQLQueryBuilder.java b/services/src/main/java/org/keycloak/services/models/nosql/api/query/NoSQLQueryBuilder.java
index aa4eb48e52..341a115120 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/query/NoSQLQueryBuilder.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/query/NoSQLQueryBuilder.java
@@ -12,14 +12,6 @@ public abstract class NoSQLQueryBuilder {
protected NoSQLQueryBuilder() {};
- public static NoSQLQueryBuilder create(Class extends NoSQLQueryBuilder> builderClass) {
- try {
- return builderClass.newInstance();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
public NoSQLQuery build() {
return new NoSQLQuery(queryAttributes);
}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/types/ConverterKey.java b/services/src/main/java/org/keycloak/services/models/nosql/api/types/ConverterKey.java
index f4b6fe0cdf..68fc3cb950 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/types/ConverterKey.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/types/ConverterKey.java
@@ -27,4 +27,5 @@ class ConverterKey {
ConverterKey tc = (ConverterKey)obj;
return tc.applicationObjectType.equals(this.applicationObjectType) && tc.dbObjectType.equals(this.dbObjectType);
}
+
}
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/api/types/TypeConverter.java b/services/src/main/java/org/keycloak/services/models/nosql/api/types/TypeConverter.java
index 7bdb384625..3368e4f390 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/api/types/TypeConverter.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/api/types/TypeConverter.java
@@ -11,6 +11,7 @@ import java.util.Map;
*/
public class TypeConverter {
+ // TODO: Thread-safety support (maybe...)
private Map> converterRegistry = new HashMap>();
public void addConverter(Converter converter) {
@@ -18,14 +19,19 @@ public class TypeConverter {
converterRegistry.put(converterKey, converter);
}
- public T convertDBObjectToApplicationObject(S dbObject, Class expectedApplicationObjectType, Class expectedDBObjectType) {
+ public T convertDBObjectToApplicationObject(S dbObject, Class expectedApplicationObjectType) {
+ // TODO: Not type safe as it expects that S type of converter must exactly match type of dbObject. Converter lookup should be more flexible
+ Class expectedDBObjectType = (Class)dbObject.getClass();
Converter converter = getConverter(expectedApplicationObjectType, expectedDBObjectType);
return converter.convertDBObjectToApplicationObject(dbObject);
}
- public S convertApplicationObjectToDBObject(T applicationobject, Class expectedApplicationObjectType, Class expectedDBObjectType) {
+ public S convertApplicationObjectToDBObject(T applicationObject, Class expectedDBObjectType) {
+ // TODO: Not type safe as it expects that T type of converter must exactly match type of applicationObject. Converter lookup should be more flexible
+ Class expectedApplicationObjectType = (Class)applicationObject.getClass();
Converter converter = getConverter(expectedApplicationObjectType, expectedDBObjectType);
- return converter.convertApplicationObjectToDBObject(applicationobject);
+
+ return converter.convertApplicationObjectToDBObject(applicationObject);
}
private Converter getConverter( Class expectedApplicationObjectType, Class expectedDBObjectType) {
diff --git a/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java b/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java
index fd6efa7627..0385aeef0c 100644
--- a/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java
+++ b/services/src/main/java/org/keycloak/services/models/nosql/impl/MongoDBImpl.java
@@ -12,20 +12,21 @@ import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import org.bson.types.ObjectId;
-import org.keycloak.services.models.nosql.api.AttributedNoSQLObject;
+import org.jboss.resteasy.logging.Logger;
import org.keycloak.services.models.nosql.api.NoSQL;
import org.keycloak.services.models.nosql.api.NoSQLCollection;
import org.keycloak.services.models.nosql.api.NoSQLField;
import org.keycloak.services.models.nosql.api.NoSQLId;
import org.keycloak.services.models.nosql.api.NoSQLObject;
import org.keycloak.services.models.nosql.api.query.NoSQLQuery;
+import org.keycloak.services.models.nosql.api.query.NoSQLQueryBuilder;
import org.keycloak.services.models.nosql.api.types.Converter;
import org.keycloak.services.models.nosql.api.types.TypeConverter;
import org.keycloak.services.models.nosql.impl.types.BasicDBListToStringArrayConverter;
+import org.keycloak.services.models.nosql.impl.types.NoSQLObjectConverter;
import org.picketlink.common.properties.Property;
import org.picketlink.common.properties.query.AnnotatedPropertyCriteria;
import org.picketlink.common.properties.query.PropertyQueries;
-import org.picketlink.common.reflection.Types;
/**
* @author Marek Posolda
@@ -33,59 +34,61 @@ import org.picketlink.common.reflection.Types;
public class MongoDBImpl implements NoSQL {
private final DB database;
- // private static final Logger logger = Logger.getLogger(MongoDBImpl.class);
+ private static final Logger logger = Logger.getLogger(MongoDBImpl.class);
private final TypeConverter typeConverter;
+ private ConcurrentMap, ObjectInfo> objectInfoCache =
+ new ConcurrentHashMap, ObjectInfo>();
- public MongoDBImpl(DB database) {
+ public MongoDBImpl(DB database, boolean removeAllObjectsAtStartup, Class extends NoSQLObject>[] managedDataTypes) {
this.database = database;
typeConverter = new TypeConverter();
typeConverter.addConverter(new BasicDBListToStringArrayConverter());
+ for (Class extends NoSQLObject> type : managedDataTypes) {
+ typeConverter.addConverter(new NoSQLObjectConverter(this, typeConverter, type));
+ getObjectInfo(type);
+ }
+
+ if (removeAllObjectsAtStartup) {
+ for (Class extends NoSQLObject> type : managedDataTypes) {
+ ObjectInfo objectInfo = getObjectInfo(type);
+ String collectionName = objectInfo.getDbCollectionName();
+ if (collectionName != null) {
+ logger.debug("Removing all objects of type " + type);
+
+ DBCollection dbCollection = this.database.getCollection(collectionName);
+ dbCollection.remove(new BasicDBObject());
+ } else {
+ logger.debug("Skip removing objects of type " + type + " as it doesn't have it's own collection");
+ }
+ }
+ logger.info("All objects successfully removed from MongoDB");
+ }
}
- private ConcurrentMap, ObjectInfo extends NoSQLObject>> objectInfoCache =
- new ConcurrentHashMap, ObjectInfo extends NoSQLObject>>();
-
-
-
@Override
public void saveObject(NoSQLObject object) {
- Class> clazz = object.getClass();
+ Class extends NoSQLObject> clazz = object.getClass();
// Find annotations for ID, for all the properties and for the name of the collection.
ObjectInfo objectInfo = getObjectInfo(clazz);
// Create instance of BasicDBObject and add all declared properties to it (properties with null value probably should be skipped)
- BasicDBObject dbObject = new BasicDBObject();
- List> props = objectInfo.getProperties();
- for (Property