package org.jboss.seam.security.management.picketlink; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.enterprise.event.Event; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.Id; import javax.persistence.NoResultException; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.jboss.seam.security.annotations.management.IdentityProperty; import org.jboss.seam.security.annotations.management.PropertyType; import org.jboss.seam.security.management.IdentityObjectRelationshipImpl; import org.jboss.seam.security.management.IdentityObjectRelationshipTypeImpl; import org.jboss.seam.security.management.IdentityObjectTypeImpl; import org.jboss.solder.properties.Property; import org.jboss.solder.properties.query.AnnotatedPropertyCriteria; import org.jboss.solder.properties.query.NamedPropertyCriteria; import org.jboss.solder.properties.query.PropertyCriteria; import org.jboss.solder.properties.query.PropertyQueries; import org.jboss.solder.properties.query.TypedPropertyCriteria; import org.jboss.solder.reflection.Reflections; import org.picketlink.idm.common.exception.IdentityException; import org.picketlink.idm.impl.api.SimpleAttribute; import org.picketlink.idm.impl.store.FeaturesMetaDataImpl; import org.picketlink.idm.impl.types.SimpleIdentityObject; import org.picketlink.idm.spi.configuration.IdentityStoreConfigurationContext; import org.picketlink.idm.spi.configuration.metadata.IdentityObjectAttributeMetaData; import org.picketlink.idm.spi.exception.OperationNotSupportedException; import org.picketlink.idm.spi.model.IdentityObject; import org.picketlink.idm.spi.model.IdentityObjectAttribute; import org.picketlink.idm.spi.model.IdentityObjectCredential; import org.picketlink.idm.spi.model.IdentityObjectRelationship; import org.picketlink.idm.spi.model.IdentityObjectRelationshipType; import org.picketlink.idm.spi.model.IdentityObjectType; import org.picketlink.idm.spi.search.IdentityObjectSearchCriteria; import org.picketlink.idm.spi.store.FeaturesMetaData; import org.picketlink.idm.spi.store.IdentityObjectSearchCriteriaType; import org.picketlink.idm.spi.store.IdentityStoreInvocationContext; import org.picketlink.idm.spi.store.IdentityStoreSession; /** * IdentityStore implementation that allows identity related data to be * persisted in a database via JPA * * @author Shane Bryzak */ public class JpaIdentityStore implements org.picketlink.idm.spi.store.IdentityStore, Serializable { private static final long serialVersionUID = 7729139146633529501L; public static final String OPTION_IDENTITY_CLASS_NAME = "identityEntityClassName"; public static final String OPTION_CREDENTIAL_CLASS_NAME = "credentialEntityClassName"; public static final String OPTION_RELATIONSHIP_CLASS_NAME = "relationshipEntityClassName"; public static final String OPTION_ROLE_TYPE_CLASS_NAME = "roleTypeEntityClassName"; public static final String OPTION_ATTRIBUTE_CLASS_NAME = "attributeEntityClassName"; private static final String DEFAULT_USER_IDENTITY_TYPE = "USER"; private static final String DEFAULT_ROLE_IDENTITY_TYPE = "ROLE"; private static final String DEFAULT_GROUP_IDENTITY_TYPE = "GROUP"; private static final String DEFAULT_RELATIONSHIP_TYPE_MEMBERSHIP = "MEMBERSHIP"; private static final String DEFAULT_RELATIONSHIP_TYPE_ROLE = "ROLE"; // Property keys private static final String PROPERTY_IDENTITY_ID = "IDENTITY_ID"; private static final String PROPERTY_IDENTITY_NAME = "IDENTITY_NAME"; private static final String PROPERTY_IDENTITY_TYPE = "IDENTITY_TYPE"; private static final String PROPERTY_IDENTITY_TYPE_NAME = "IDENTITY_TYPE_NAME"; private static final String PROPERTY_CREDENTIAL_VALUE = "CREDENTIAL_VALUE"; private static final String PROPERTY_CREDENTIAL_TYPE = "CREDENTIAL_TYPE"; private static final String PROPERTY_CREDENTIAL_TYPE_NAME = "CREDENTIAL_TYPE_NAME"; private static final String PROPERTY_CREDENTIAL_IDENTITY = "CREDENTIAL_IDENTITY"; private static final String PROPERTY_RELATIONSHIP_FROM = "RELATIONSHIP_FROM"; private static final String PROPERTY_RELATIONSHIP_TO = "RELATIONSHIP_TO"; private static final String PROPERTY_RELATIONSHIP_TYPE = "RELATIONSHIP_TYPE"; private static final String PROPERTY_RELATIONSHIP_TYPE_NAME = "RELATIONSHIP_TYPE_NAME"; private static final String PROPERTY_RELATIONSHIP_NAME = "RELATIONSHIP_NAME"; private static final String PROPERTY_ROLE_TYPE_NAME = "RELATIONSHIP_NAME_NAME"; private static final String PROPERTY_ATTRIBUTE_NAME = "ATTRIBUTE_NAME"; private static final String PROPERTY_ATTRIBUTE_VALUE = "ATTRIBUTE_VALUE"; private static final String PROPERTY_ATTRIBUTE_IDENTITY = "ATTRIBUTE_IDENTITY"; private static final String PROPERTY_ATTRIBUTE_TYPE = "ATTRIBUTE_TYPE"; private static final String ATTRIBUTE_TYPE_TEXT = "text"; private static final String ATTRIBUTE_TYPE_BOOLEAN = "boolean"; private static final String ATTRIBUTE_TYPE_DATE = "date"; private static final String ATTRIBUTE_TYPE_INT = "int"; private static final String ATTRIBUTE_TYPE_LONG = "long"; private static final String ATTRIBUTE_TYPE_FLOAT = "float"; private static final String ATTRIBUTE_TYPE_DOUBLE = "double"; private class EntityToSpiConverter { private static final String IDENTITY_TYPE_CACHE_PREFIX = "identity_type:"; private static final String RELATIONSHIP_TYPE_CACHE_PREFIX = "relationship_type:"; private Map<Object, Object> cache = new HashMap<Object, Object>(); private Property<?> identityIdProperty = modelProperties.get(PROPERTY_IDENTITY_ID); private Property<?> identityNameProperty = modelProperties.get(PROPERTY_IDENTITY_NAME); private Property<?> identityTypeProperty = modelProperties.get(PROPERTY_IDENTITY_TYPE); private Property<?> identityTypeNameProperty = modelProperties.get(PROPERTY_IDENTITY_TYPE_NAME); private Property<?> relationshipTypeNameProperty = modelProperties.get(PROPERTY_RELATIONSHIP_TYPE_NAME); public IdentityObject convertToIdentityObject(Object entity) { if (!identityClass.isAssignableFrom(entity.getClass())) { throw new IllegalArgumentException("Invalid identity entity"); } if (cache.containsKey(entity)) { return (IdentityObject) cache.get(entity); } else { IdentityObject obj = new SimpleIdentityObject( identityNameProperty.getValue(entity).toString(), identityIdProperty.getValue(entity).toString(), convertToIdentityObjectType(identityTypeProperty.getValue(entity))); cache.put(entity, obj); return obj; } } public IdentityObjectType convertToIdentityObjectType(Object value) { if (value instanceof String) { String key = IDENTITY_TYPE_CACHE_PREFIX + (String) value; if (cache.containsKey(key)) return (IdentityObjectType) cache.get(key); IdentityObjectType type = new IdentityObjectTypeImpl((String) value); cache.put(key, type); return type; } else { if (cache.containsKey(value)) return (IdentityObjectType) cache.get(value); IdentityObjectType type = new IdentityObjectTypeImpl( (String) identityTypeNameProperty.getValue(value)); cache.put(value, type); return type; } } public IdentityObjectRelationshipType convertToRelationshipType(Object value) { if (value instanceof String) { String key = RELATIONSHIP_TYPE_CACHE_PREFIX + (String) value; if (cache.containsKey(key)) return (IdentityObjectRelationshipType) cache.get(key); IdentityObjectRelationshipType type = new IdentityObjectRelationshipTypeImpl((String) value); cache.put(key, type); return type; } else { if (cache.containsKey(value)) return (IdentityObjectRelationshipType) cache.get(value); IdentityObjectRelationshipType type = new IdentityObjectRelationshipTypeImpl( (String) relationshipTypeNameProperty.getValue(value)); cache.put(value, type); return type; } } } private String id; // Entity classes private Class<?> identityClass; private Class<?> credentialClass; private Class<?> relationshipClass; private Class<?> attributeClass; private Class<?> roleTypeClass; private String userIdentityType = DEFAULT_USER_IDENTITY_TYPE; private String roleIdentityType = DEFAULT_ROLE_IDENTITY_TYPE; private String groupIdentityType = DEFAULT_GROUP_IDENTITY_TYPE; private String relationshipTypeMembership = DEFAULT_RELATIONSHIP_TYPE_MEMBERSHIP; private String relationshipTypeRole = DEFAULT_RELATIONSHIP_TYPE_ROLE; /** * Model properties */ private Map<String, Property<Object>> modelProperties = new HashMap<String, Property<Object>>(); /** * Used to map attributes to properties spread across the object model * */ private class MappedAttribute { /** * The property of the IdentityObject class that references the object that * contains the attribute property */ private Property<Object> identityProperty; /** * The property of the mapped object that contains the attribute value */ private Property<Object> attributeProperty; public MappedAttribute(Property<Object> identityProperty, Property<Object> attributeProperty) { this.identityProperty = identityProperty; this.attributeProperty = attributeProperty; } public Property<Object> getIdentityProperty() { return identityProperty; } public Property<Object> getAttributeProperty() { return attributeProperty; } } /** * Attribute properties */ private Map<String, MappedAttribute> attributeProperties = new HashMap<String, MappedAttribute>(); boolean namedRelationshipsSupported = false; private FeaturesMetaData featuresMetaData; private class PropertyTypeCriteria implements PropertyCriteria { private PropertyType pt; public PropertyTypeCriteria(PropertyType pt) { this.pt = pt; } public boolean fieldMatches(Field f) { return f.isAnnotationPresent(IdentityProperty.class) && f.getAnnotation(IdentityProperty.class).value().equals(pt); } public boolean methodMatches(Method m) { return m.isAnnotationPresent(IdentityProperty.class) && m.getAnnotation(IdentityProperty.class).value().equals(pt); } } public JpaIdentityStore(String id) { this.id = id; } public void bootstrap(IdentityStoreConfigurationContext configurationContext) throws IdentityException { String clsName = configurationContext.getStoreConfigurationMetaData() .getOptionSingleValue(OPTION_IDENTITY_CLASS_NAME); if (clsName == null) { throw new IdentityException("Error bootstrapping JpaIdentityStore - identity entity class cannot be null"); } try { identityClass = Reflections.classForName(clsName); } catch (ClassNotFoundException e) { throw new IdentityException("Error bootstrapping JpaIdentityStore - invalid identity entity class: " + clsName); } if (identityClass == null) { throw new IdentityException( "Error initializing JpaIdentityStore - identityClass not set"); } clsName = configurationContext.getStoreConfigurationMetaData() .getOptionSingleValue(OPTION_CREDENTIAL_CLASS_NAME); if (clsName != null) { try { credentialClass = Class.forName(clsName); } catch (ClassNotFoundException e) { throw new IdentityException("Error bootstrapping JpaIdentityStore - invalid credential entity class: " + clsName); } } clsName = configurationContext.getStoreConfigurationMetaData() .getOptionSingleValue(OPTION_RELATIONSHIP_CLASS_NAME); try { relationshipClass = Class.forName(clsName); } catch (ClassNotFoundException e) { throw new IdentityException("Error bootstrapping JpaIdentityStore - invalid relationship entity class: " + clsName); } clsName = configurationContext.getStoreConfigurationMetaData() .getOptionSingleValue(OPTION_ROLE_TYPE_CLASS_NAME); if (clsName != null) { try { roleTypeClass = Class.forName(clsName); namedRelationshipsSupported = true; } catch (ClassNotFoundException e) { throw new IdentityException("Error bootstrapping JpaIdentityStore - invalid role type entity class: " + clsName); } } clsName = configurationContext.getStoreConfigurationMetaData() .getOptionSingleValue(OPTION_ATTRIBUTE_CLASS_NAME); if (clsName != null) { try { attributeClass = Class.forName(clsName); } catch (ClassNotFoundException e) { throw new IdentityException("Error bootstrapping JpaIdentityStore - invalid attribute entity class: " + clsName); } } configureIdentityId(); configureIdentityName(); configureIdentityType(); configureCredentials(); configureRelationships(); configureAttributes(); if (namedRelationshipsSupported) { configureRoleTypeName(); } featuresMetaData = new FeaturesMetaDataImpl( configurationContext.getStoreConfigurationMetaData(), new HashSet<IdentityObjectSearchCriteriaType>(), false, namedRelationshipsSupported, new HashSet<String>() ); } protected void configureIdentityId() throws IdentityException { List<Property<Object>> props = PropertyQueries.createQuery(identityClass) .addCriteria(new AnnotatedPropertyCriteria(Id.class)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_IDENTITY_ID, props.get(0)); } else { throw new IdentityException("Error initializing JpaIdentityStore - no Identity ID found."); } } protected void configureIdentityName() throws IdentityException { List<Property<Object>> props = PropertyQueries.createQuery(identityClass) .addCriteria(new PropertyTypeCriteria(PropertyType.NAME)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_IDENTITY_NAME, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous identity name property in identity class " + identityClass.getName()); } else { Property<Object> p = findNamedProperty(identityClass, "username", "userName", "name"); if (p != null) { modelProperties.put(PROPERTY_IDENTITY_NAME, p); } else { // Last resort - check whether the entity class exposes a single String property // if so, let's assume it's the identity name props = PropertyQueries.createQuery(identityClass) .addCriteria(new TypedPropertyCriteria(String.class)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_IDENTITY_NAME, props.get(0)); } } } if (!modelProperties.containsKey(PROPERTY_IDENTITY_NAME)) { throw new IdentityException("Error initializing JpaIdentityStore - no valid identity name property found."); } } protected void configureIdentityType() throws IdentityException { List<Property<Object>> props = PropertyQueries.createQuery(identityClass) .addCriteria(new PropertyTypeCriteria(PropertyType.TYPE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_IDENTITY_TYPE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous identity type property in identity class " + identityClass.getName()); } else { Property<Object> p = findNamedProperty(identityClass, "identityObjectType", "identityType", "identityObjectTypeName", "identityTypeName", "typeName", "discriminator", "accountType", "userType", "type"); if (p != null) { modelProperties.put(PROPERTY_IDENTITY_TYPE, props.get(0)); } else { // Last resort - let's check all properties, and try to find one // with an entity type that has "type" in its name props = PropertyQueries.createQuery(identityClass).getResultList(); search: for (Property<Object> typeProp : props) { if (typeProp.getJavaClass().isAnnotationPresent(Entity.class) && (typeProp.getJavaClass().getSimpleName().contains("type") || typeProp.getJavaClass().getSimpleName().contains("Type"))) { // we have a potential match, let's check if this entity has a name property Property<Object> nameProp = findNamedProperty(typeProp.getJavaClass(), "identityObjectTypeName", "identityTypeName", "typeName", "name"); if (nameProp != null) { modelProperties.put(PROPERTY_IDENTITY_TYPE, typeProp); modelProperties.put(PROPERTY_IDENTITY_TYPE_NAME, nameProp); break search; } } } } } Property<?> typeProp = modelProperties.get(PROPERTY_IDENTITY_TYPE); if (typeProp == null) { throw new IdentityException("Error initializing JpaIdentityStore - no valid identity type property found."); } if (!String.class.equals(typeProp.getJavaClass()) && !modelProperties.containsKey(PROPERTY_IDENTITY_TYPE_NAME)) { // We're not dealing with a simple type name - validate the lookup type Property<Object> nameProp = findNamedProperty(typeProp.getJavaClass(), "identityObjectTypeName", "identityTypeName", "typeName", "name"); if (nameProp != null) { modelProperties.put(PROPERTY_IDENTITY_TYPE_NAME, nameProp); } else { throw new IdentityException("Error initializing JpaIdentityStore - no valid identity type name property found."); } } } protected Property<Object> findNamedProperty(Class<?> targetClass, String... allowedNames) { List<Property<Object>> props = PropertyQueries.createQuery(targetClass) .addCriteria(new TypedPropertyCriteria(String.class)) .addCriteria(new PropertyTypeCriteria(PropertyType.NAME)) .getResultList(); if (props.size() == 1) { return props.get(0); } else { props = PropertyQueries.createQuery(targetClass) .addCriteria(new TypedPropertyCriteria(String.class)) .addCriteria(new NamedPropertyCriteria(allowedNames)) .getResultList(); for (String name : allowedNames) { for (Property<Object> prop : props) { if (name.equals(prop.getName())) return prop; } } } return null; } protected void configureCredentials() throws IdentityException { // If a credential entity has been explicitly configured, scan it if (credentialClass != null) { List<Property<Object>> props = PropertyQueries.createQuery(credentialClass) .addCriteria(new PropertyTypeCriteria(PropertyType.VALUE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_CREDENTIAL_VALUE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous credential value property in credential class " + credentialClass.getName()); } else { // Try scanning for a credential property also props = PropertyQueries.createQuery(credentialClass) .addCriteria(new PropertyTypeCriteria(PropertyType.CREDENTIAL)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_CREDENTIAL_VALUE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous credential value property in credential class " + credentialClass.getName()); } else { Property<Object> p = findNamedProperty(credentialClass, "credentialValue", "password", "passwordHash", "credential", "value"); if (p != null) modelProperties.put(PROPERTY_CREDENTIAL_VALUE, p); } } // Scan for the credential identity property props = PropertyQueries.createQuery(credentialClass) .addCriteria(new TypedPropertyCriteria(identityClass)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_CREDENTIAL_IDENTITY, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous identity property in credential class " + credentialClass.getName()); } else { // Scan for a named identity property props = PropertyQueries.createQuery(credentialClass) .addCriteria(new NamedPropertyCriteria("identity", "identityObject")) .getResultList(); if (!props.isEmpty()) { modelProperties.put(PROPERTY_CREDENTIAL_IDENTITY, props.get(0)); } else { throw new IdentityException("Error initializing JpaIdentityStore - no credential identity property found."); } } } else { // The credentials may be stored in the identity class List<Property<Object>> props = PropertyQueries.createQuery(identityClass) .addCriteria(new PropertyTypeCriteria(PropertyType.CREDENTIAL)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_CREDENTIAL_VALUE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous credential property in identity class " + identityClass.getName()); } else { Property<Object> p = findNamedProperty(identityClass, "credentialValue", "password", "passwordHash", "credential", "value"); if (p != null) modelProperties.put(PROPERTY_CREDENTIAL_VALUE, p); } // If Credential is on Identity, it's see if Credential Type is too props = PropertyQueries.createQuery(identityClass) .addCriteria(new PropertyTypeCriteria(PropertyType.CREDENTIAL_TYPE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_CREDENTIAL_TYPE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous credential type property in identity class " + identityClass.getName()); } else { Property<Object> p = findNamedProperty(identityClass, "credentialType", "identityObjectCredentialType", "type"); if (p != null) modelProperties.put(PROPERTY_CREDENTIAL_TYPE, p); } } if (!modelProperties.containsKey(PROPERTY_CREDENTIAL_VALUE)) { throw new IdentityException("Error initializing JpaIdentityStore - no credential value property found."); } // Scan for a credential type property if (modelProperties.get(PROPERTY_CREDENTIAL_TYPE) == null) { // We may have found it on identity List<Property<Object>> props = PropertyQueries.createQuery(credentialClass) .addCriteria(new PropertyTypeCriteria(PropertyType.TYPE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_CREDENTIAL_TYPE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous credential type property in credential class " + credentialClass.getName()); } else { props = PropertyQueries.createQuery(credentialClass) .addCriteria(new PropertyTypeCriteria(PropertyType.CREDENTIAL_TYPE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_CREDENTIAL_TYPE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous credential type property in credential class " + credentialClass.getName()); } else { Property<Object> p = findNamedProperty(credentialClass, "credentialType", "identityObjectCredentialType", "type"); if (p != null) modelProperties.put(PROPERTY_CREDENTIAL_TYPE, p); } } } Property<?> typeProp = modelProperties.get(PROPERTY_CREDENTIAL_TYPE); // If the credential type property isn't a String, then validate the lookup type if (!String.class.equals(typeProp.getJavaClass())) { Property<Object> nameProp = findNamedProperty(typeProp.getJavaClass(), "credentialObjectTypeName", "credentialTypeName", "typeName", "name"); if (nameProp != null) { modelProperties.put(PROPERTY_CREDENTIAL_TYPE_NAME, nameProp); } else { throw new IdentityException("Error initializing JpaIdentityStore - no valid credential type name property found."); } } } protected void configureRelationships() throws IdentityException { if (relationshipClass == null) { throw new IdentityException("Error initializing JpaIdentityStore - relationshipClass not set."); } List<Property<Object>> props = PropertyQueries.createQuery(relationshipClass) .addCriteria(new TypedPropertyCriteria(identityClass)) .addCriteria(new PropertyTypeCriteria(PropertyType.RELATIONSHIP_FROM)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_RELATIONSHIP_FROM, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous relationshipFrom property in relationship class " + relationshipClass.getName()); } else { Property<Object> p = findNamedProperty(relationshipClass, "relationshipFrom", "fromIdentityObject", "fromIdentity"); if (p != null) { modelProperties.put(PROPERTY_RELATIONSHIP_FROM, p); } else { // Last resort - search for a property with a type of identityClass // and a "from" in its name props = PropertyQueries.createQuery(relationshipClass) .addCriteria(new TypedPropertyCriteria(identityClass)) .getResultList(); for (Property<Object> prop : props) { if (prop.getName().contains("from")) { modelProperties.put(PROPERTY_RELATIONSHIP_FROM, prop); break; } } } } props = PropertyQueries.createQuery(relationshipClass) .addCriteria(new TypedPropertyCriteria(identityClass)) .addCriteria(new PropertyTypeCriteria(PropertyType.RELATIONSHIP_TO)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_RELATIONSHIP_TO, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous relationshipTo property in relationship class " + relationshipClass.getName()); } else { Property<Object> p = findNamedProperty(relationshipClass, "relationshipTo", "toIdentityObject", "toIdentity"); if (p != null) { modelProperties.put(PROPERTY_RELATIONSHIP_TO, p); } else { // Last resort - search for a property with a type of identityClass // and a "to" in its name props = PropertyQueries.createQuery(relationshipClass) .addCriteria(new TypedPropertyCriteria(identityClass)) .getResultList(); for (Property<Object> prop : props) { if (prop.getName().contains("to")) { modelProperties.put(PROPERTY_RELATIONSHIP_TO, prop); break; } } } } props = PropertyQueries.createQuery(relationshipClass) .addCriteria(new PropertyTypeCriteria(PropertyType.TYPE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_RELATIONSHIP_TYPE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous relationshipType property in relationship class " + relationshipClass.getName()); } else { Property<Object> p = findNamedProperty(relationshipClass, "identityRelationshipType", "relationshipType", "type"); if (p != null) { modelProperties.put(PROPERTY_RELATIONSHIP_TYPE, p); } else { props = PropertyQueries.createQuery(relationshipClass) .getResultList(); for (Property<Object> prop : props) { if (prop.getName().contains("type")) { modelProperties.put(PROPERTY_RELATIONSHIP_TYPE, prop); break; } } } } props = PropertyQueries.createQuery(relationshipClass) .addCriteria(new PropertyTypeCriteria(PropertyType.NAME)) .addCriteria(new TypedPropertyCriteria(String.class)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_RELATIONSHIP_NAME, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous relationship name property in relationship class " + relationshipClass.getName()); } else { Property<Object> p = findNamedProperty(relationshipClass, "relationshipName", "name"); if (p != null) { modelProperties.put(PROPERTY_RELATIONSHIP_NAME, p); } } if (modelProperties.containsKey(PROPERTY_RELATIONSHIP_NAME)) { namedRelationshipsSupported = true; } if (!modelProperties.containsKey(PROPERTY_RELATIONSHIP_FROM)) { throw new IdentityException( "Error initializing JpaIdentityStore - no valid relationship from property found."); } if (!modelProperties.containsKey(PROPERTY_RELATIONSHIP_TO)) { throw new IdentityException( "Error initializing JpaIdentityStore - no valid relationship to property found."); } if (!modelProperties.containsKey(PROPERTY_RELATIONSHIP_TYPE)) { throw new IdentityException( "Error initializing JpaIdentityStore - no valid relationship type property found."); } if (!modelProperties.containsKey(PROPERTY_RELATIONSHIP_NAME)) { throw new IdentityException( "Error initializing JpaIdentityStore - no valid relationship name property found."); } Class<?> typeClass = modelProperties.get(PROPERTY_RELATIONSHIP_TYPE).getJavaClass(); if (!String.class.equals(typeClass)) { props = PropertyQueries.createQuery(typeClass) .addCriteria(new PropertyTypeCriteria(PropertyType.NAME)) .addCriteria(new TypedPropertyCriteria(String.class)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_RELATIONSHIP_TYPE_NAME, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous relationship type name property in class " + typeClass.getName()); } else { Property<Object> p = findNamedProperty(typeClass, "relationshipTypeName", "typeName", "name"); if (p != null) { modelProperties.put(PROPERTY_RELATIONSHIP_TYPE_NAME, p); } } if (!modelProperties.containsKey(PROPERTY_RELATIONSHIP_TYPE_NAME)) { throw new IdentityException( "Error initializing JpaIdentityStore - no valid relationship type name property found"); } } } protected void configureAttributes() throws IdentityException { // If an attribute class has been configured, scan it for attributes if (attributeClass != null) { List<Property<Object>> props = PropertyQueries.createQuery(attributeClass) .addCriteria(new PropertyTypeCriteria(PropertyType.NAME)) .addCriteria(new TypedPropertyCriteria(String.class)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_ATTRIBUTE_NAME, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous attribute name property in class " + attributeClass.getName()); } else { Property<Object> prop = findNamedProperty(attributeClass, "attributeName", "name"); if (prop != null) modelProperties.put(PROPERTY_ATTRIBUTE_NAME, prop); } props = PropertyQueries.createQuery(attributeClass) .addCriteria(new PropertyTypeCriteria(PropertyType.VALUE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_ATTRIBUTE_VALUE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous attribute value property in class " + attributeClass.getName()); } else { Property<Object> prop = findNamedProperty(attributeClass, "attributeValue", "value"); if (prop != null) modelProperties.put(PROPERTY_ATTRIBUTE_VALUE, prop); } props = PropertyQueries.createQuery(attributeClass) .addCriteria(new TypedPropertyCriteria(identityClass)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_ATTRIBUTE_IDENTITY, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous identity property in attribute class " + attributeClass.getName()); } else { throw new IdentityException("Error initializing JpaIdentityStore - " + "no attribute identity property found."); } props = PropertyQueries.createQuery(attributeClass) .addCriteria(new PropertyTypeCriteria(PropertyType.TYPE)) .getResultList(); if (props.size() == 1) { modelProperties.put(PROPERTY_ATTRIBUTE_TYPE, props.get(0)); } else if (props.size() > 1) { throw new IdentityException( "Ambiguous attribute type property in class " + attributeClass.getName()); } } // Scan for additional attributes in the identity class also List<Property<Object>> props = PropertyQueries.createQuery(identityClass) .addCriteria(new PropertyTypeCriteria(PropertyType.ATTRIBUTE)) .getResultList(); for (Property<Object> p : props) { String attribName = p.getAnnotatedElement().getAnnotation(IdentityProperty.class).attributeName(); if (attributeProperties.containsKey(attribName)) { Property<Object> other = attributeProperties.get(attribName).getAttributeProperty(); throw new IdentityException("Multiple properties defined for attribute [" + attribName + "] - " + "Property: " + other.getDeclaringClass().getName() + "." + other.getAnnotatedElement().toString() + ", Property: " + p.getDeclaringClass().getName() + "." + p.getAnnotatedElement().toString()); } attributeProperties.put(attribName, new MappedAttribute(null, p)); } // scan any entity classes referenced by the identity class also props = PropertyQueries.createQuery(identityClass).getResultList(); for (Property<Object> p : props) { if (!p.isReadOnly() && p.getJavaClass().isAnnotationPresent(Entity.class)) { List<Property<Object>> pp = PropertyQueries.createQuery(p.getJavaClass()) .addCriteria(new PropertyTypeCriteria(PropertyType.ATTRIBUTE)) .getResultList(); for (Property<Object> attributeProperty : pp) { String attribName = attributeProperty.getAnnotatedElement().getAnnotation(IdentityProperty.class).attributeName(); if (attributeProperties.containsKey(attribName)) { Property<Object> other = attributeProperties.get(attribName).getAttributeProperty(); throw new IdentityException("Multiple properties defined for attribute [" + attribName + "] - " + "Property: " + other.getDeclaringClass().getName() + "." + other.getAnnotatedElement().toString() + ", Property: " + attributeProperty.getDeclaringClass().getName() + "." + attributeProperty.getAnnotatedElement().toString()); } attributeProperties.put(attribName, new MappedAttribute(p, attributeProperty)); } } } } protected void configureRoleTypeName() { Property<Object> relationshipNameProp = findNamedProperty(roleTypeClass, "name"); if (relationshipNameProp != null) { modelProperties.put(PROPERTY_ROLE_TYPE_NAME, relationshipNameProp); } } protected class AttributeValue { private String encoded; private String type; public AttributeValue(String encoded, String type) { this.encoded = encoded; this.type = type; } public String getEncoded() { return encoded; } public String getType() { return type; } } public String getUserIdentityType() { return userIdentityType; } public void setUserIdentityType(String userIdentityType) { this.userIdentityType = userIdentityType; } public String getRoleIdentityType() { return roleIdentityType; } public void setRoleIdentityType(String roleIdentityType) { this.roleIdentityType = roleIdentityType; } public String getGroupIdentityType() { return groupIdentityType; } public void setGroupIdentityType(String groupIdentityType) { this.groupIdentityType = groupIdentityType; } public String getRelationshipTypeMembership() { return relationshipTypeMembership; } public void setRelationshipTypeMembership(String relationshipTypeMembership) { this.relationshipTypeMembership = relationshipTypeMembership; } public String getRelationshipTypeRole() { return relationshipTypeRole; } public void setRelationshipTypeRole(String relationshipTypeRole) { this.relationshipTypeRole = relationshipTypeRole; } @SuppressWarnings("unchecked") public IdentityStoreSession createIdentityStoreSession( Map<String, Object> sessionOptions) throws IdentityException { EntityManager em = (EntityManager) sessionOptions.get(IdentitySessionProducer.SESSION_OPTION_ENTITY_MANAGER); Event<IdentityObjectCreatedEvent> event = (Event<IdentityObjectCreatedEvent>) sessionOptions.get(IdentitySessionProducer.SESSION_OPTION_IDENTITY_OBJECT_CREATED_EVENT); return new JpaIdentityStoreSessionImpl(em, event); } public IdentityObject createIdentityObject( IdentityStoreInvocationContext invocationCtx, String name, IdentityObjectType identityObjectType) throws IdentityException { return createIdentityObject(invocationCtx, name, identityObjectType, null); } protected Object lookupIdentityType(String identityType, EntityManager em) { Property<Object> typeNameProp = modelProperties.get(PROPERTY_IDENTITY_TYPE_NAME); try { // If there is no identity type table, just return the name if (typeNameProp == null) return identityType; final String identTypeEntityAnnotationValue = typeNameProp.getDeclaringClass().getAnnotation(Entity.class).name(); final String identTypeEntityName = ("".equals(identTypeEntityAnnotationValue) ? typeNameProp.getDeclaringClass().getSimpleName() : identTypeEntityAnnotationValue); Object val = em.createQuery( "select t from " + identTypeEntityName + " t where t." + typeNameProp.getName() + " = :identityType") .setParameter("identityType", identityType) .getSingleResult(); return val; } catch (NoResultException ex) { try { // The identity type wasn't found, so create it Object instance = typeNameProp.getDeclaringClass().newInstance(); typeNameProp.setValue(instance, identityType); em.persist(instance); return instance; } catch (Exception ex2) { throw new RuntimeException("Error creating identity type", ex2); } } } public IdentityObject createIdentityObject( IdentityStoreInvocationContext ctx, String name, IdentityObjectType identityObjectType, Map<String, String[]> attributes) throws IdentityException { try { Object identityInstance = identityClass.newInstance(); modelProperties.get(PROPERTY_IDENTITY_NAME).setValue(identityInstance, name); Property<Object> typeProp = modelProperties.get(PROPERTY_IDENTITY_TYPE); if (String.class.equals(typeProp.getJavaClass())) { typeProp.setValue(identityInstance, identityObjectType.getName()); } else { typeProp.setValue(identityInstance, lookupIdentityType(identityObjectType.getName(), getEntityManager(ctx))); } EntityManager em = getEntityManager(ctx); for (String attribName : attributeProperties.keySet()) { MappedAttribute attrib = attributeProperties.get(attribName); if (attrib.getIdentityProperty() != null && attrib.getIdentityProperty().getValue(identityInstance) == null) { Object instance = attrib.getIdentityProperty().getJavaClass().newInstance(); attrib.getIdentityProperty().setValue(identityInstance, instance); em.persist(instance); } } em.persist(identityInstance); // Fire an event that contains the new identity object Event<IdentityObjectCreatedEvent> event = ((JpaIdentityStoreSessionImpl) ctx.getIdentityStoreSession()).getIdentityObjectCreatedEvent(); if (event != null) { event.fire(new IdentityObjectCreatedEvent(identityInstance)); } Object id = modelProperties.get(PROPERTY_IDENTITY_ID).getValue(identityInstance); IdentityObject obj = new SimpleIdentityObject(name, (id != null ? id.toString() : null), identityObjectType); if (attributes != null) { List<IdentityObjectAttribute> attribs = new ArrayList<IdentityObjectAttribute>(); for (String key : attributes.keySet()) { for (String value : attributes.get(key)) { attribs.add(new SimpleAttribute(key, value)); } } updateAttributes(ctx, obj, attribs.toArray(new IdentityObjectAttribute[attribs.size()])); } em.flush(); return obj; } catch (Exception ex) { throw new IdentityException("Error creating identity object", ex); } } public IdentityObjectRelationship createRelationship( IdentityStoreInvocationContext invocationCtx, IdentityObject fromIdentity, IdentityObject toIdentity, IdentityObjectRelationshipType relationshipType, String relationshipName, boolean createNames) throws IdentityException { try { EntityManager em = getEntityManager(invocationCtx); Object relationship = relationshipClass.newInstance(); modelProperties.get(PROPERTY_RELATIONSHIP_FROM).setValue(relationship, lookupIdentity(fromIdentity, em)); modelProperties.get(PROPERTY_RELATIONSHIP_TO).setValue(relationship, lookupIdentity(toIdentity, em)); Property<Object> type = modelProperties.get(PROPERTY_RELATIONSHIP_TYPE); if (String.class.equals(modelProperties.get(PROPERTY_RELATIONSHIP_TYPE).getJavaClass())) { type.setValue(relationship, relationshipType.getName()); } else { type.setValue(relationship, lookupRelationshipType(relationshipType, em)); } modelProperties.get(PROPERTY_RELATIONSHIP_NAME).setValue(relationship, relationshipName); em.persist(relationship); em.flush(); return new IdentityObjectRelationshipImpl(fromIdentity, toIdentity, relationshipName, relationshipType); } catch (Exception ex) { throw new IdentityException("Exception creating relationship", ex); } } protected Object lookupIdentity(IdentityObject obj, EntityManager em) { Property<?> identityNameProp = modelProperties.get(PROPERTY_IDENTITY_NAME); Property<?> identityTypeProp = modelProperties.get(PROPERTY_IDENTITY_TYPE); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(identityClass); Root<?> root = criteria.from(identityClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(identityNameProp.getName()), obj.getName())); predicates.add(builder.equal(root.get(identityTypeProp.getName()), lookupIdentityType(obj.getIdentityType().getName(), em))); // TODO add criteria for identity type criteria.where(predicates.toArray(new Predicate[predicates.size()])); return em.createQuery(criteria).getSingleResult(); } protected Object lookupCredentialTypeEntity(String name, EntityManager em) { Property<?> credentialTypeNameProp = modelProperties.get(PROPERTY_CREDENTIAL_TYPE_NAME); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(credentialTypeNameProp.getDeclaringClass()); Root<?> root = criteria.from(credentialTypeNameProp.getDeclaringClass()); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(credentialTypeNameProp.getName()), name)); criteria.where(predicates.toArray(new Predicate[predicates.size()])); return em.createQuery(criteria).getSingleResult(); } protected Object lookupRelationshipType(IdentityObjectRelationshipType relationshipType, EntityManager em) { Property<?> relationshipTypeNameProp = modelProperties.get(PROPERTY_RELATIONSHIP_TYPE_NAME); if (relationshipTypeNameProp != null) { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(relationshipTypeNameProp.getDeclaringClass()); Root<?> root = criteria.from(relationshipTypeNameProp.getDeclaringClass()); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(relationshipTypeNameProp.getName()), relationshipType.getName())); criteria.where(predicates.toArray(new Predicate[predicates.size()])); return em.createQuery(criteria).getSingleResult(); } else { return relationshipType.getName(); } } public String createRelationshipName(IdentityStoreInvocationContext ctx, String name) throws IdentityException, OperationNotSupportedException { try { Property<Object> roleTypeNameProp = modelProperties.get(PROPERTY_ROLE_TYPE_NAME); Object roleTypeInstance = roleTypeClass.newInstance(); roleTypeNameProp.setValue(roleTypeInstance, name); EntityManager em = getEntityManager(ctx); em.persist(roleTypeInstance); em.flush(); return name; } catch (Exception ex) { throw new IdentityException("Error creating relationship name", ex); } } public EntityManager getEntityManager(IdentityStoreInvocationContext invocationContext) { return ((JpaIdentityStoreSessionImpl) invocationContext.getIdentityStoreSession()).getEntityManager(); } public IdentityObject findIdentityObject(IdentityStoreInvocationContext invocationContext, String id) throws IdentityException { try { final String identEntityAnnotationValue = identityClass.getAnnotation(Entity.class).name(); final String identEntityName = ("".equals(identEntityAnnotationValue) ? identityClass.getSimpleName() : identEntityAnnotationValue); Object identity = getEntityManager(invocationContext).createQuery("select i from " + identEntityName + " i where i." + modelProperties.get(PROPERTY_IDENTITY_ID).getName() + " = :id") .setParameter("id", id) .getSingleResult(); IdentityObjectType type = modelProperties.containsKey(PROPERTY_IDENTITY_TYPE_NAME) ? new IdentityObjectTypeImpl( modelProperties.get(PROPERTY_IDENTITY_TYPE_NAME).getValue( modelProperties.get(PROPERTY_IDENTITY_TYPE).getValue(identity)).toString()) : new IdentityObjectTypeImpl(modelProperties.get(PROPERTY_IDENTITY_TYPE).getValue(identity).toString()); return new SimpleIdentityObject( modelProperties.get(PROPERTY_IDENTITY_NAME).getValue(identity).toString(), modelProperties.get(PROPERTY_IDENTITY_ID).getValue(identity).toString(), type); } catch (NoResultException ex) { return null; } } public IdentityObject findIdentityObject( IdentityStoreInvocationContext invocationContext, String name, IdentityObjectType identityObjectType) throws IdentityException { try { Object identityType = modelProperties.containsKey(PROPERTY_IDENTITY_TYPE_NAME) ? lookupIdentityType(identityObjectType.getName(), getEntityManager(invocationContext)) : identityObjectType.getName(); final String identEntityAnnotationValue = identityClass.getAnnotation(Entity.class).name(); final String identEntityName = ("".equals(identEntityAnnotationValue) ? identityClass.getSimpleName() : identEntityAnnotationValue); Object identity = getEntityManager(invocationContext).createQuery("select i from " + identEntityName + " i where i." + modelProperties.get(PROPERTY_IDENTITY_NAME).getName() + " = :name and i." + modelProperties.get(PROPERTY_IDENTITY_TYPE).getName() + " = :type") .setParameter("name", name) .setParameter("type", identityType) .getSingleResult(); return new SimpleIdentityObject( modelProperties.get(PROPERTY_IDENTITY_NAME).getValue(identity).toString(), modelProperties.get(PROPERTY_IDENTITY_ID).getValue(identity).toString(), identityObjectType); } catch (NoResultException ex) { return null; } } public Collection<IdentityObject> findIdentityObject( IdentityStoreInvocationContext ctx, IdentityObjectType identityType, IdentityObjectSearchCriteria searchCriteria) throws IdentityException { List<IdentityObject> objs = new ArrayList<IdentityObject>(); EntityManager em = getEntityManager(ctx); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(identityClass); Root<?> root = criteria.from(identityClass); Property<?> identityTypeProp = modelProperties.get(PROPERTY_IDENTITY_TYPE); List<Predicate> predicates = new ArrayList<Predicate>(); if (identityType != null) { predicates.add(builder.equal(root.get(identityTypeProp.getName()), lookupIdentityType(identityType.getName(), em))); } criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); EntityToSpiConverter converter = new EntityToSpiConverter(); for (Object result : results) { objs.add(converter.convertToIdentityObject(result)); } return objs; } public String getId() { return id; } public Set<String> getRelationshipNames(IdentityStoreInvocationContext ctx, IdentityObjectSearchCriteria searchCriteria) throws IdentityException, OperationNotSupportedException { Set<String> names = new HashSet<String>(); if (!featuresMetaData.isNamedRelationshipsSupported()) return names; Property<Object> roleTypeNameProp = modelProperties.get(PROPERTY_ROLE_TYPE_NAME); if (roleTypeClass != null) { EntityManager em = getEntityManager(ctx); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(roleTypeClass); criteria.from(roleTypeClass); List<?> results = em.createQuery(criteria).getResultList(); for (Object result : results) { names.add(roleTypeNameProp.getValue(result).toString()); } } return names; } public Set<String> getRelationshipNames(IdentityStoreInvocationContext ctx, IdentityObject identity, IdentityObjectSearchCriteria searchCriteria) throws IdentityException, OperationNotSupportedException { Set<String> names = new HashSet<String>(); if (!featuresMetaData.isNamedRelationshipsSupported()) return names; EntityManager em = getEntityManager(ctx); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(relationshipClass); Root<?> root = criteria.from(relationshipClass); Property<?> identityToProperty = modelProperties.get(PROPERTY_RELATIONSHIP_TO); Property<?> relationshipNameProperty = modelProperties.get(PROPERTY_RELATIONSHIP_NAME); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(identityToProperty.getName()), lookupIdentity(identity, em))); Path<String> rolesOnly = root.get(relationshipNameProperty.getName()); predicates.add(builder.like(rolesOnly, "%")); criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); for (Object result : results) { names.add((String) relationshipNameProperty.getValue(result)); } return names; } public Map<String, String> getRelationshipProperties( IdentityStoreInvocationContext ctx, IdentityObjectRelationship relationship) throws IdentityException, OperationNotSupportedException { throw new OperationNotSupportedException("getRelationshipProperties() not supported"); } public FeaturesMetaData getSupportedFeatures() { return featuresMetaData; } public void removeIdentityObject( IdentityStoreInvocationContext ctx, IdentityObject identity) throws IdentityException { removeRelationships(ctx, identity, null, false); EntityManager em = getEntityManager(ctx); Property<?> nameProperty = modelProperties.get(PROPERTY_IDENTITY_NAME); Property<?> typeProperty = modelProperties.get(PROPERTY_IDENTITY_TYPE); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(identityClass); Root<?> root = criteria.from(identityClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(nameProperty.getName()), identity.getName())); predicates.add(builder.equal(root.get(typeProperty.getName()), lookupIdentityType(identity.getIdentityType().getName(), em))); criteria.where(predicates.toArray(new Predicate[predicates.size()])); try { Object instance = em.createQuery(criteria).getSingleResult(); // If there is a credential class, delete any credentials if (credentialClass != null) { Property<?> credentialIdentityProp = modelProperties.get(PROPERTY_CREDENTIAL_IDENTITY); criteria = builder.createQuery(credentialClass); root = criteria.from(credentialClass); predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(credentialIdentityProp.getName()), instance)); criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); for (Object result : results) { em.remove(result); } } // If there is an attribute class, delete any attributes if (attributeClass != null) { Property<?> attributeIdentityProperty = modelProperties.get(PROPERTY_ATTRIBUTE_IDENTITY); criteria = builder.createQuery(attributeClass); root = criteria.from(attributeClass); predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(attributeIdentityProperty.getName()), instance)); criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); for (Object result : results) { em.remove(result); } } em.remove(instance); } catch (NoResultException ex) { throw new IdentityException(String.format( "Exception removing identity object - [%s] not found.", identity), ex); } } public void removeRelationship(IdentityStoreInvocationContext ctx, IdentityObject fromIdentity, IdentityObject toIdentity, IdentityObjectRelationshipType relationshipType, String relationshipName) throws IdentityException { Property<?> fromProperty = modelProperties.get(PROPERTY_RELATIONSHIP_FROM); Property<?> toProperty = modelProperties.get(PROPERTY_RELATIONSHIP_TO); Property<?> relationshipTypeProp = modelProperties.get(PROPERTY_RELATIONSHIP_TYPE); EntityManager em = getEntityManager(ctx); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(relationshipClass); Root<?> root = criteria.from(relationshipClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(fromProperty.getName()), lookupIdentity(fromIdentity, em))); predicates.add(builder.equal(root.get(toProperty.getName()), lookupIdentity(toIdentity, em))); predicates.add(builder.equal(root.get(relationshipTypeProp.getName()), lookupRelationshipType(relationshipType, em))); criteria.where(predicates.toArray(new Predicate[predicates.size()])); Object relationship = em.createQuery(criteria).getSingleResult(); em.remove(relationship); } public String removeRelationshipName(IdentityStoreInvocationContext ctx, String name) throws IdentityException, OperationNotSupportedException { Property<?> nameProp = modelProperties.get(PROPERTY_ROLE_TYPE_NAME); EntityManager em = getEntityManager(ctx); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(roleTypeClass); Root<?> root = criteria.from(roleTypeClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(nameProp.getName()), name)); criteria.where(predicates.toArray((new Predicate[0]))); Object roleType = em.createQuery(criteria).getSingleResult(); em.remove(roleType); return null; } public void removeRelationships( IdentityStoreInvocationContext ctx, IdentityObject identity1, IdentityObject identity2, boolean named) throws IdentityException { EntityManager em = getEntityManager(ctx); Object loadedIdentity1 = null; if(identity1 != null) { loadedIdentity1 = lookupIdentity(identity1, em); } Object loadedIdentity2 = null; if(identity2 != null) { loadedIdentity2 = lookupIdentity(identity2, em); } CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(relationshipClass); Root<?> root = criteria.from(relationshipClass); Property<?> relationshipFromProp = modelProperties.get(PROPERTY_RELATIONSHIP_FROM); Property<?> relationshipToProp = modelProperties.get(PROPERTY_RELATIONSHIP_TO); List<Predicate> predicates = new ArrayList<Predicate>(); if (identity1 != null) { predicates.add(builder.equal(root.get(relationshipFromProp.getName()), loadedIdentity1)); } if (identity2 != null) { predicates.add(builder.equal(root.get(relationshipToProp.getName()), loadedIdentity2)); } criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); for (Object result : results) { em.remove(result); } criteria = builder.createQuery(relationshipClass); criteria.from(relationshipClass); predicates = new ArrayList<Predicate>(); if (identity2 != null) { predicates.add(builder.equal(root.get(relationshipFromProp.getName()), loadedIdentity2)); } if (identity1 != null) { predicates.add(builder.equal(root.get(relationshipToProp.getName()), loadedIdentity1)); } criteria.where(predicates.toArray(new Predicate[predicates.size()])); results = em.createQuery(criteria).getResultList(); for (Object result : results) { em.remove(result); } } public Set<IdentityObjectRelationship> resolveRelationships( IdentityStoreInvocationContext ctx, IdentityObject fromIdentity, IdentityObject toIdentity, IdentityObjectRelationshipType relationshipType) throws IdentityException { Set<IdentityObjectRelationship> relationships = new HashSet<IdentityObjectRelationship>(); EntityManager em = getEntityManager(ctx); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(relationshipClass); Root<?> root = criteria.from(relationshipClass); Property<?> relationshipFromProp = modelProperties.get(PROPERTY_RELATIONSHIP_FROM); Property<?> relationshipToProp = modelProperties.get(PROPERTY_RELATIONSHIP_TO); Property<?> relationshipTypeProp = modelProperties.get(PROPERTY_RELATIONSHIP_TYPE); Property<?> relationshipNameProp = modelProperties.get(PROPERTY_RELATIONSHIP_NAME); List<Predicate> predicates = new ArrayList<Predicate>(); if (fromIdentity != null) { predicates.add(builder.equal(root.get(relationshipFromProp.getName()), lookupIdentity(fromIdentity, em))); } if (toIdentity != null) { predicates.add(builder.equal(root.get(relationshipToProp.getName()), lookupIdentity(toIdentity, em))); } if (relationshipType != null) { predicates.add(builder.equal(root.get(relationshipTypeProp.getName()), lookupRelationshipType(relationshipType, em))); } criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); EntityToSpiConverter converter = new EntityToSpiConverter(); for (Object result : results) { IdentityObjectRelationship relationship = new IdentityObjectRelationshipImpl( converter.convertToIdentityObject(relationshipFromProp.getValue(result)), converter.convertToIdentityObject(relationshipToProp.getValue(result)), (String) relationshipNameProp.getValue(result), converter.convertToRelationshipType(relationshipTypeProp.getValue(result)) ); relationships.add(relationship); } return relationships; } public Set<IdentityObjectRelationship> resolveRelationships( IdentityStoreInvocationContext ctx, IdentityObject identity, IdentityObjectRelationshipType relationshipType, boolean parent, boolean named, String name) throws IdentityException { Set<IdentityObjectRelationship> relationships = new HashSet<IdentityObjectRelationship>(); EntityManager em = getEntityManager(ctx); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(relationshipClass); Root<?> root = criteria.from(relationshipClass); Property<?> relationshipFromProp = modelProperties.get(PROPERTY_RELATIONSHIP_FROM); Property<?> relationshipToProp = modelProperties.get(PROPERTY_RELATIONSHIP_TO); Property<?> relationshipTypeProp = modelProperties.get(PROPERTY_RELATIONSHIP_TYPE); Property<?> relationshipNameProp = modelProperties.get(PROPERTY_RELATIONSHIP_NAME); List<Predicate> predicates = new ArrayList<Predicate>(); if (parent) { predicates.add(builder.equal(root.get(relationshipFromProp.getName()), lookupIdentity(identity, em))); } else { predicates.add(builder.equal(root.get(relationshipToProp.getName()), lookupIdentity(identity, em))); } if (relationshipType != null) { predicates.add(builder.equal(root.get(relationshipTypeProp.getName()), lookupRelationshipType(relationshipType, em))); } if (named) { if (name != null) { predicates.add(builder.equal(root.get(relationshipNameProp.getName()), name)); } else { predicates.add(builder.isNotNull(root.get(relationshipNameProp.getName()))); } } criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); EntityToSpiConverter converter = new EntityToSpiConverter(); for (Object result : results) { IdentityObjectRelationship relationship = new IdentityObjectRelationshipImpl( converter.convertToIdentityObject(relationshipFromProp.getValue(result)), converter.convertToIdentityObject(relationshipToProp.getValue(result)), (String) relationshipNameProp.getValue(result), converter.convertToRelationshipType(relationshipTypeProp.getValue(result)) ); relationships.add(relationship); } return relationships; } public void updateCredential(IdentityStoreInvocationContext ctx, IdentityObject identityObject, IdentityObjectCredential credential) throws IdentityException { EntityManager em = getEntityManager(ctx); Property<Object> credentialValue = modelProperties.get(PROPERTY_CREDENTIAL_VALUE); if (credentialClass != null) { Property<Object> credentialIdentity = modelProperties.get(PROPERTY_CREDENTIAL_IDENTITY); Property<Object> credentialType = modelProperties.get(PROPERTY_CREDENTIAL_TYPE); Object identity = lookupIdentity(identityObject, em); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(credentialClass); Root<?> root = criteria.from(credentialClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(credentialIdentity.getName()), identity)); if (credentialType != null) { if (String.class.equals(credentialType.getJavaClass())) { predicates.add(builder.equal(root.get(credentialType.getName()), credential.getType().getName())); } else { predicates.add(builder.equal(root.get(credentialType.getName()), lookupCredentialTypeEntity(credential.getType().getName(), em))); } } criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); if (results.isEmpty()) { // The credential doesn't exist, let's create it try { Object newCredential = credentialClass.newInstance(); credentialIdentity.setValue(newCredential, identity); credentialValue.setValue(newCredential, credential.getValue()); credentialType.setValue(newCredential, lookupCredentialTypeEntity(credential.getType().getName(), em)); em.persist(newCredential); } catch (IllegalAccessException ex) { throw new IdentityException("Error updating credential - could " + "not create credential instance", ex); } catch (InstantiationException ex) { throw new IdentityException("Error updating credential - could " + "not create credential instance", ex); } } else { // TODO there shouldn't be multiple credentials with the same type, // but if there are, we need to deal with it somehow.. for now just use the first one Object result = results.get(0); credentialValue.setValue(result, credential.getValue()); em.merge(result); } } else { // The credential is stored in the identity class, update it there Property<Object> credentialProp = modelProperties.get(PROPERTY_CREDENTIAL_VALUE); Object identity = lookupIdentity(identityObject, em); credentialProp.setValue(identity, credential.getValue()); em.merge(identity); } } public boolean validateCredential(IdentityStoreInvocationContext ctx, IdentityObject identityObject, IdentityObjectCredential credential) throws IdentityException { EntityManager em = getEntityManager(ctx); Property<?> credentialValue = modelProperties.get(PROPERTY_CREDENTIAL_VALUE); // Either credentials are stored in their own class... if (credentialClass != null) { Property<?> credentialIdentity = modelProperties.get(PROPERTY_CREDENTIAL_IDENTITY); Property<?> credentialType = modelProperties.get(PROPERTY_CREDENTIAL_TYPE); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(credentialClass); Root<?> root = criteria.from(credentialClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(credentialIdentity.getName()), lookupIdentity(identityObject, em))); if (credentialType != null) { if (String.class.equals(credentialType.getJavaClass())) { predicates.add(builder.equal(root.get(credentialType.getName()), credential.getType().getName())); } else { predicates.add(builder.equal(root.get(credentialType.getName()), lookupCredentialTypeEntity(credential.getType().getName(), em))); } } criteria.where(predicates.toArray(new Predicate[0])); List<?> results = em.createQuery(criteria).getResultList(); if (results.isEmpty()) return false; // TODO this only supports plain text passwords for (Object result : results) { Object val = credentialValue.getValue(result); if (val.equals(credential.getValue())) return true; } } // or they're stored in the identity class else { Property<?> identityNameProp = modelProperties.get(PROPERTY_IDENTITY_NAME); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(credentialValue.getDeclaringClass()); Root<?> root = criteria.from(credentialValue.getDeclaringClass()); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(identityNameProp.getName()), identityObject.getName())); criteria.where(predicates.toArray(new Predicate[predicates.size()])); Object result = em.createQuery(criteria).getSingleResult(); Object val = credentialValue.getValue(result); if (val.equals(credential.getValue())) return true; } return false; } public void addAttributes(IdentityStoreInvocationContext ctx, IdentityObject identityObject, IdentityObjectAttribute[] attributes) throws IdentityException { try { EntityManager em = getEntityManager(ctx); Object identity = lookupIdentity(identityObject, em); Set<IdentityObjectAttribute> filteredAttribs = new HashSet<IdentityObjectAttribute>(); // Filter out the mapped attributes, and update their values for (IdentityObjectAttribute attrib : attributes) { if (attributeProperties.containsKey(attrib.getName())) { MappedAttribute mappedAttribute = attributeProperties.get(attrib.getName()); if (mappedAttribute.getIdentityProperty() == null) { mappedAttribute.getAttributeProperty().setValue(identity, attrib.getValue()); } else { mappedAttribute.getAttributeProperty().setValue(mappedAttribute.getIdentityProperty().getValue(identity), attrib.getValue()); } } else { filteredAttribs.add(attrib); } } if (!filteredAttribs.isEmpty() && attributeClass != null) { Property<Object> attributeIdentityProp = modelProperties.get(PROPERTY_ATTRIBUTE_IDENTITY); Property<Object> attributeNameProp = modelProperties.get(PROPERTY_ATTRIBUTE_NAME); Property<Object> attributeValueProp = modelProperties.get(PROPERTY_ATTRIBUTE_VALUE); for (IdentityObjectAttribute attrib : filteredAttribs) { if (attrib.getSize() == 1) { Object attribute = attributeClass.newInstance(); attributeIdentityProp.setValue(attribute, identity); attributeNameProp.setValue(attribute, attrib.getName()); attributeValueProp.setValue(attribute, attrib.getValue()); em.persist(attribute); } else { for (Object value : attrib.getValues()) { Object attribute = attributeClass.newInstance(); attributeIdentityProp.setValue(attribute, identity); attributeNameProp.setValue(attribute, attrib.getName()); attributeValueProp.setValue(attribute, value); em.persist(attribute); } } } } } catch (Exception e) { throw new IdentityException("Error while adding attributes.", e); } } public IdentityObjectAttribute getAttribute(IdentityStoreInvocationContext ctx, IdentityObject identity, String name) throws IdentityException { EntityManager em = getEntityManager(ctx); if (attributeProperties.containsKey(name)) { return getMappedAttribute(ctx, identity, name); } else { // If there is no attributeClass set, we have nowhere else to look - return an empty attribute if (attributeClass == null) return new SimpleAttribute(name); Property<?> attributeIdentityProp = modelProperties.get(PROPERTY_ATTRIBUTE_IDENTITY); Property<?> attributeNameProp = modelProperties.get(PROPERTY_ATTRIBUTE_NAME); Property<?> attributeValueProp = modelProperties.get(PROPERTY_ATTRIBUTE_VALUE); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(attributeClass); Root<?> root = criteria.from(attributeClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(attributeIdentityProp.getName()), lookupIdentity(identity, em))); predicates.add(builder.equal(root.get(attributeNameProp.getName()), name)); criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); if (results.size() == 0) { // No results found, return an empty attribute value return new SimpleAttribute(name); } else if (results.size() == 1) { return new SimpleAttribute(name, attributeValueProp.getValue(results.get(0))); } else { Collection<Object> values = new ArrayList<Object>(); for (Object result : results) { values.add(attributeValueProp.getValue(result)); } return new SimpleAttribute(name, values.toArray()); } } } /** * Returns an attribute value stored elsewhere than the IDENTITY_ATTRIBUTES table * * @param ctx * @param identity * @param name * @return * @throws IdentityException */ private IdentityObjectAttribute getMappedAttribute(IdentityStoreInvocationContext ctx, IdentityObject identity, String name) throws IdentityException { MappedAttribute mappedAttribute = attributeProperties.get(name); EntityManager em = getEntityManager(ctx); if (mappedAttribute.getIdentityProperty() == null) { // The attribute value is stored in the identity object itself return new SimpleAttribute(name, mappedAttribute.getAttributeProperty().getValue(lookupIdentity(identity, em))); } else { // The attribute value is stored in an object referenced by the identity object return new SimpleAttribute(name, mappedAttribute.getAttributeProperty().getValue( mappedAttribute.getIdentityProperty().getValue(lookupIdentity(identity, em)))); } } public Map<String, IdentityObjectAttribute> getAttributes( IdentityStoreInvocationContext ctx, IdentityObject identityObject) throws IdentityException { Map<String, IdentityObjectAttribute> attributes = new HashMap<String, IdentityObjectAttribute>(); EntityManager em = getEntityManager(ctx); Object identity = lookupIdentity(identityObject, em); for (String name : attributeProperties.keySet()) { attributes.put(name, getMappedAttribute(ctx, identityObject, name)); } if (attributeClass != null) { Property<?> attributeIdentityProp = modelProperties.get(PROPERTY_ATTRIBUTE_IDENTITY); Property<?> attributeNameProp = modelProperties.get(PROPERTY_ATTRIBUTE_NAME); Property<?> attributeValueProp = modelProperties.get(PROPERTY_ATTRIBUTE_VALUE); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(attributeClass); Root<?> root = criteria.from(attributeClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(attributeIdentityProp.getName()), identity)); criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); for (Object result : results) { String name = attributeNameProp.getValue(result).toString(); Object value = attributeValueProp.getValue(result); if (attributes.containsKey(name)) { IdentityObjectAttribute attr = attributes.get(name); attr.addValue(value); } else { attributes.put(name, new SimpleAttribute(name, value)); } } } return attributes; } /** * Removes the attributes specified by the attributeNames property. Mapped attributes cannot be * removed via this method, instead their values must be overwritten using updateAttributes() */ public void removeAttributes(IdentityStoreInvocationContext ctx, IdentityObject identityObject, String[] attributeNames) throws IdentityException { EntityManager em = getEntityManager(ctx); Object identity = lookupIdentity(identityObject, em); if (attributeClass != null) { Property<?> attributeIdentityProp = modelProperties.get(PROPERTY_ATTRIBUTE_IDENTITY); Property<?> attributeNameProp = modelProperties.get(PROPERTY_ATTRIBUTE_NAME); CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(attributeClass); Root<?> root = criteria.from(attributeClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(attributeIdentityProp.getName()), identity)); criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); for (Object result : results) { String name = attributeNameProp.getValue(result).toString(); for (String n : attributeNames) { if (name != null && name.equals(n)) { em.remove(result); break; } } } } } public void updateAttributes(IdentityStoreInvocationContext ctx, IdentityObject identityObject, IdentityObjectAttribute[] attributes) throws IdentityException { try { EntityManager em = getEntityManager(ctx); Object identity = lookupIdentity(identityObject, em); Set<IdentityObjectAttribute> filteredAttribs = new HashSet<IdentityObjectAttribute>(); // First we need to filter out the mapped attributes, and while we're at it we'll update their values for (IdentityObjectAttribute attrib : attributes) { if (attributeProperties.containsKey(attrib.getName())) { MappedAttribute mappedAttribute = attributeProperties.get(attrib.getName()); if (mappedAttribute.getIdentityProperty() == null) { mappedAttribute.getAttributeProperty().setValue(identity, attrib.getValue()); } else { mappedAttribute.getAttributeProperty().setValue(mappedAttribute.getIdentityProperty().getValue(identity), attrib.getValue()); } } else { filteredAttribs.add(attrib); } } // Now we'll update the remaining, non-mapped attribute values if (attributeClass != null) { Property<Object> attributeIdentityProp = modelProperties.get(PROPERTY_ATTRIBUTE_IDENTITY); Property<Object> attributeNameProp = modelProperties.get(PROPERTY_ATTRIBUTE_NAME); Property<Object> attributeValueProp = modelProperties.get(PROPERTY_ATTRIBUTE_VALUE); Property<Object> attributeTypeProp = modelProperties.get(PROPERTY_ATTRIBUTE_TYPE); for (IdentityObjectAttribute attrib : filteredAttribs) { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<?> criteria = builder.createQuery(attributeClass); Root<?> root = criteria.from(attributeClass); List<Predicate> predicates = new ArrayList<Predicate>(); predicates.add(builder.equal(root.get(attributeIdentityProp.getName()), identity)); predicates.add(builder.equal(root.get(attributeNameProp.getName()), attrib.getName())); criteria.where(predicates.toArray(new Predicate[predicates.size()])); List<?> results = em.createQuery(criteria).getResultList(); // All existing attribute values should be overwritten, so we // will first remove them, then add the new values if (!results.isEmpty()) { for (Object result : results) { em.remove(result); } } for (Object value : attrib.getValues()) { Object attribute = attributeClass.newInstance(); attributeIdentityProp.setValue(attribute, identity); attributeNameProp.setValue(attribute, attrib.getName()); // If there is an attribute type property, then determine the value type // TODO this is messy, refactor it by abstracting into a utility class if (attributeTypeProp != null) { if (String.class.equals(value.getClass())) { attributeValueProp.setValue(attribute, value.toString()); attributeTypeProp.setValue(attribute, ATTRIBUTE_TYPE_TEXT); } else if (Boolean.class.equals(value.getClass()) || Boolean.TYPE.equals(value.getClass())) { attributeValueProp.setValue(attribute, Boolean.toString((Boolean) value)); attributeTypeProp.setValue(attribute, ATTRIBUTE_TYPE_BOOLEAN); } else if (Date.class.isAssignableFrom(value.getClass())) { attributeValueProp.setValue(attribute, "" + ((Date) value).getTime()); attributeTypeProp.setValue(attribute, ATTRIBUTE_TYPE_DATE); } else if (Integer.class.equals(value.getClass()) || Integer.TYPE.equals(value.getClass())) { attributeValueProp.setValue(attribute, ((Integer) value).toString()); attributeTypeProp.setValue(attribute, ATTRIBUTE_TYPE_INT); } else if (Long.class.equals(value.getClass()) || Long.TYPE.equals(value.getClass())) { attributeValueProp.setValue(attribute, ((Long) value).toString()); attributeTypeProp.setValue(attribute, ATTRIBUTE_TYPE_LONG); } else if (Float.class.equals(value.getClass()) || Float.TYPE.equals(value.getClass())) { attributeValueProp.setValue(attribute, ((Float) value).toString()); attributeTypeProp.setValue(attribute, ATTRIBUTE_TYPE_FLOAT); } else if (Double.class.equals(value.getClass()) || Double.TYPE.equals(value.getClass())) { attributeValueProp.setValue(attribute, ((Double) value).toString()); attributeTypeProp.setValue(attribute, ATTRIBUTE_TYPE_DOUBLE); } else { throw new IdentityException("Could not persist attribute value - unsupported attribute value type " + value.getClass()); } } else { attributeValueProp.setValue(attribute, value.toString()); } em.persist(attribute); } } } } catch (Exception e) { throw new IdentityException("Error while updating attributes.", e); } } public IdentityStoreSession createIdentityStoreSession() throws IdentityException { return createIdentityStoreSession(null); } public Collection<IdentityObject> findIdentityObject(IdentityStoreInvocationContext invocationCxt, IdentityObject identity, IdentityObjectRelationshipType relationshipType, boolean parent, IdentityObjectSearchCriteria criteria) throws IdentityException { List<IdentityObject> objs = new ArrayList<IdentityObject>(); EntityManager em = getEntityManager(invocationCxt); javax.persistence.Query q = null; boolean orderByName = false; boolean ascending = true; if (criteria != null && criteria.isSorted()) { orderByName = true; ascending = criteria.isAscending(); } StringBuilder queryString = new StringBuilder(); IdentityObjectType identityType = identity.getIdentityType(); Object identType = modelProperties.containsKey(PROPERTY_IDENTITY_TYPE_NAME) ? lookupIdentityType( identityType.getName(), getEntityManager(invocationCxt)) : identityType.getName(); final String identEntityAnnotationValue = identityClass.getAnnotation(Entity.class).name(); final String identEntityName = ("".equals(identEntityAnnotationValue) ? identityClass.getSimpleName() : identEntityAnnotationValue); Object ident = getEntityManager(invocationCxt).createQuery( "select i from " + identEntityName + " i where i." + modelProperties.get(PROPERTY_IDENTITY_NAME).getName() + " = :name and i." + modelProperties.get(PROPERTY_IDENTITY_TYPE).getName() + " = :type") .setParameter("name", identity.getName()).setParameter("type", identType).getSingleResult(); String relEntityName = ""; if (modelProperties.get(PROPERTY_RELATIONSHIP_NAME) != null) { final Class<?> relationshipClass = modelProperties.get(PROPERTY_RELATIONSHIP_NAME).getDeclaringClass(); final String relEntityAnnotationValue = relationshipClass.getAnnotation(Entity.class).name(); relEntityName = ("".equals(identEntityAnnotationValue) ? relationshipClass.getSimpleName() : relEntityAnnotationValue); } if (parent) { if (relationshipType != null) { queryString.append("select distinct ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + " from " + relEntityName + " ior where ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + "." + modelProperties.get(PROPERTY_RELATIONSHIP_NAME).getName() + " like :nameFilter and ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TYPE).getName() + "." + modelProperties.get(PROPERTY_RELATIONSHIP_TYPE_NAME).getName() + " = :relType and ior." + modelProperties.get(PROPERTY_RELATIONSHIP_FROM).getName() + " = :identity"); } else { queryString.append("select distinct ior. " + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + "from " + relEntityName + " ior where ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + "." + modelProperties.get(PROPERTY_IDENTITY_NAME).getName() + " like :nameFilter and ior." + modelProperties.get(PROPERTY_RELATIONSHIP_FROM).getName() + " = :identity"); } if (orderByName) { queryString.append(" order by ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + "." + modelProperties.get(PROPERTY_IDENTITY_NAME).getName() + (ascending ? " asc" : "")); } } else { if (relationshipType != null) { queryString.append("select distinct ior." + modelProperties.get(PROPERTY_RELATIONSHIP_FROM).getName() + " from " + relEntityName + " ior where ior." + modelProperties.get(PROPERTY_RELATIONSHIP_FROM).getName() + "." + modelProperties.get(PROPERTY_IDENTITY_NAME).getName() + " like :nameFilter and ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TYPE).getName() + "." + modelProperties.get(PROPERTY_RELATIONSHIP_TYPE_NAME).getName() + " = :relType and ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + " = :identity"); } else { queryString.append("select distinct ior." + modelProperties.get(PROPERTY_RELATIONSHIP_FROM).getName() + " from " + relEntityName + " ior where ior." + modelProperties.get(PROPERTY_RELATIONSHIP_FROM).getName() + "." + modelProperties.get(PROPERTY_IDENTITY_NAME).getName() + " like :nameFilter and ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + " = :identity"); } if (orderByName) { queryString.append(" order by ior." + modelProperties.get(PROPERTY_RELATIONSHIP_TO).getName() + "." + modelProperties.get(PROPERTY_IDENTITY_NAME).getName() + (ascending ? " asc" : "")); } } q = em.createQuery(queryString.toString()).setParameter("identity", ident); if (relationshipType != null) { q.setParameter("relType", relationshipType.getName()); } if (criteria != null && criteria.getFilter() != null) { q.setParameter("nameFilter", criteria.getFilter().replaceAll("\\*", "%")); } else { q.setParameter("nameFilter", "%"); } if (criteria != null && criteria.isPaged() && !criteria.isFiltered()) { q.setFirstResult(criteria.getFirstResult()); if (criteria.getMaxResults() > 0) { q.setMaxResults(criteria.getMaxResults()); } } List<?> results = q.getResultList(); EntityToSpiConverter converter = new EntityToSpiConverter(); for (Object result : results) { objs.add(converter.convertToIdentityObject(result)); } return objs; } public IdentityObject findIdentityObjectByUniqueAttribute( IdentityStoreInvocationContext invocationCtx, IdentityObjectType identityObjectType, IdentityObjectAttribute attribute) throws IdentityException { // TODO Auto-generated method stub return null; } public Map<String, IdentityObjectAttributeMetaData> getAttributesMetaData( IdentityStoreInvocationContext invocationContext, IdentityObjectType identityType) { // TODO Auto-generated method stub return null; } public Set<String> getSupportedAttributeNames( IdentityStoreInvocationContext invocationContext, IdentityObjectType identityType) throws IdentityException { // TODO Auto-generated method stub return null; } public int getIdentityObjectsCount( IdentityStoreInvocationContext invocationCtx, IdentityObjectType identityType) throws IdentityException { System.out.println("*** Invoked unimplemented method getIdentityObjectsCount()"); // TODO Auto-generated method stub return 0; } public Map<String, String> getRelationshipNameProperties( IdentityStoreInvocationContext ctx, String name) throws IdentityException, OperationNotSupportedException { throw new OperationNotSupportedException("getRelationshipNameProperties() not supported"); } public void setRelationshipNameProperties( IdentityStoreInvocationContext ctx, String name, Map<String, String> properties) throws IdentityException, OperationNotSupportedException { throw new OperationNotSupportedException("setRelationshipNameProperties() not supported"); } public void setRelationshipProperties(IdentityStoreInvocationContext ctx, IdentityObjectRelationship relationship, Map<String, String> properties) throws IdentityException, OperationNotSupportedException { throw new OperationNotSupportedException("setRelationshipProperties() not supported"); } public void removeRelationshipNameProperties( IdentityStoreInvocationContext ctx, String name, Set<String> properties) throws IdentityException, OperationNotSupportedException { throw new OperationNotSupportedException("removeRelationshipNameProperties() not supported"); } public void removeRelationshipProperties(IdentityStoreInvocationContext ctx, IdentityObjectRelationship relationship, Set<String> properties) throws IdentityException, OperationNotSupportedException { throw new OperationNotSupportedException("removeRelationshipProperties() not supported"); } }