package org.picketlink.idm.permission.acl.spi; import org.picketlink.common.properties.Property; import org.picketlink.common.properties.query.AnnotatedPropertyCriteria; import org.picketlink.common.properties.query.PropertyQueries; import org.picketlink.idm.IdentityManagementException; import java.io.Serializable; import java.lang.annotation.Annotation; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import static org.picketlink.common.reflection.Reflections.classForName; /** * * @author Shane Bryzak * */ public class EntityPermissionHandler extends BaseAbstractPermissionHandler { private static final String SEPARATOR = ":"; private Class<? extends Annotation> entityAnnotationClass = null; private Class<? extends Annotation> idAnnotationClass = null; private Map<Class<?>, List<Property<Serializable>>> idProperties = new ConcurrentHashMap<Class<?>, List<Property<Serializable>>>(); public EntityPermissionHandler() { try { entityAnnotationClass = classForName("javax.persistence.Entity"); idAnnotationClass = classForName("javax.persistence.Id"); } catch (ClassNotFoundException ex) { // Entity permissions not supported } } @Override public boolean canHandle(Class<?> resourceClass) { return entityAnnotationClass != null && resourceClass.isAnnotationPresent(entityAnnotationClass); } private List<Property<Serializable>> getIdProperties(Object resource) { Class<?> resourceClass = unwrapResourceClass(resource); if (!idProperties.containsKey(resourceClass)) { queryIdProperties(resourceClass); } return idProperties.get(resourceClass); } private synchronized void queryIdProperties(Class<?> resourceClass) { if (!idProperties.containsKey(resourceClass)) { List<Property<Serializable>> props = PropertyQueries.<Serializable>createQuery(resourceClass) .addCriteria(new AnnotatedPropertyCriteria(idAnnotationClass)) .getResultList(); // If there is more than one property sort them in ascending alphabetical order if (props.size() > 1) { Collections.sort(props, new Comparator<Property<Serializable>>() { @Override public int compare(Property<Serializable> a, Property<Serializable> b) { return a.getName().compareTo(b.getName()); } }); } idProperties.put(resourceClass, props); } } /** * TODO we only support @Id identifiers at the moment, still need to add support for @EmbeddedId etc * * @param resource * @return */ @Override public Serializable getIdentifier(Object resource) { List<Property<Serializable>> props = getIdProperties(resource); // If the entity has a single @Id property, return it if (props.size() == 1) { return props.get(0).getValue(resource); // Otherwise return a colon-separated list } else if (props.size() > 1) { StringBuilder sb = new StringBuilder(); for (Property<Serializable> p : props) { if (sb.length() > 0) { sb.append(SEPARATOR); } sb.append(p.getValue(resource).toString()); } return sb.toString(); } else { throw new IdentityManagementException( String.format("Could not locate @Id property for specified resource [%s]", resource)); } } @Override public Class<?> unwrapResourceClass(Object resource) { return resource.getClass(); } }