/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <hr> * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * This file has been modified by the OpenOLAT community. Changes are licensed * under the Apache 2.0 license as the original file. */ package org.olat.properties; import java.io.File; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import javax.persistence.Query; import javax.persistence.TypedQuery; import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.AssertException; import org.olat.core.manager.BasicManager; import org.olat.core.util.StringHelper; import org.olat.group.BusinessGroup; import org.olat.group.BusinessGroupRef; import org.olat.user.UserDataDeletable; /** * Initial Date: Mar 10, 2004 * * @author Mike Stock * * Comment: * */ public class PropertyManager extends BasicManager implements UserDataDeletable { private static PropertyManager INSTANCE; /** * [used by spring] */ private PropertyManager() { INSTANCE = this; } /** * @return Singleton. */ public static PropertyManager getInstance() { return INSTANCE; } /** * Creates a new Property * @param identity * @param group * @param olatResourceable * @param category * @param name * @param floatValue * @param longValue * @param stringValue * @param textValue * @return property instance. */ public Property createPropertyInstance(Identity identity, BusinessGroup group, OLATResourceable olatResourceable, String category, String name, Float floatValue, Long longValue, String stringValue, String textValue) { Property p = new Property(); p.setIdentity(identity); p.setGrp(group); if (olatResourceable != null) { p.setResourceTypeName(olatResourceable.getResourceableTypeName()); p.setResourceTypeId(olatResourceable.getResourceableId()); } p.setCategory(category); p.setName(name); p.setFloatValue(floatValue); p.setLongValue(longValue); p.setStringValue(stringValue); p.setTextValue(textValue); return p; } /** * Create a user proprety. Grp, course and node a re set to null. * * @param identity * @param category * @param name * @param floatValue * @param longValue * @param stringValue * @param textValue * @return property instance limited to a specific user. */ public Property createUserPropertyInstance(Identity identity, String category, String name, Float floatValue, Long longValue, String stringValue, String textValue) { return createPropertyInstance(identity, null, null, category, name, floatValue, longValue, stringValue, textValue); } /** * Deletes a property on the database * @param p the property */ public void deleteProperty(Property p) { DBFactory.getInstance().deleteObject(p); } /** * Save a property * @param p */ public void saveProperty(Property p) { p.setLastModified(new Date()); DBFactory.getInstance().saveObject(p); } /** * Update a property * @param p */ public void updateProperty(Property p) { p.setLastModified(new Date()); DBFactory.getInstance().updateObject(p); } /** * Find a user property. * * @param identity * @param category * @param name * @return Found property or null if no match. */ public Property findUserProperty(Identity identity, String category, String name) { StringBuilder sb = new StringBuilder(); sb.append("select v from ").append(Property.class.getName()).append(" as v ") .append(" inner join fetch v.identity identity ") .append(" where identity.key=:identityKey and v.category=:cat and v.name=:name and v.grp is null and v.resourceTypeName is null and v.resourceTypeId is null"); List<Property> props = DBFactory.getInstance().getCurrentEntityManager() .createQuery(sb.toString(), Property.class) .setParameter("identityKey", identity.getKey()) .setParameter("cat", category) .setParameter("name", name) .getResultList(); if (props == null || props.size() != 1) { if(isLogDebugEnabled()) logDebug("Could not find property: " + name); return null; } return props.get(0); } /** * Return all the properties with the specified name and category * * @param identity * @param category * @param name * @return */ public List<Property> findAllUserProperties(IdentityRef identity, String category, String name) { StringBuilder sb = new StringBuilder(); sb.append("select v from ").append(Property.class.getName()).append(" as v ") .append(" inner join v.identity identity ") .append(" where identity.key=:identityKey and v.category=:cat and v.name=:name"); return DBFactory.getInstance().getCurrentEntityManager() .createQuery(sb.toString(), Property.class) .setParameter("identityKey", identity.getKey()) .setParameter("cat", category) .setParameter("name", name) .getResultList(); } /** * Generic method. Returns a list of Property objects. This is an inexact match i.e. parameters with null values * will not be included in the query. * * @param identity * @param grp * @param resourceable * @param category * @param name * @return a list of Property objects */ public List<Property> listProperties(Identity identity, BusinessGroup grp, OLATResourceable resourceable, String category, String name) { if (resourceable == null) { return listProperties(identity, grp, null, null, category, name); } else { return listProperties(identity, grp, resourceable.getResourceableTypeName(), resourceable.getResourceableId(), category, name); } } public int countProperties(Identity identity, BusinessGroup grp, OLATResourceable resourceable, String category, String name) { if (resourceable == null) { return countProperties(identity, grp, null, null, category, name, null, null); } else { return countProperties(identity, grp, resourceable.getResourceableTypeName(), resourceable.getResourceableId(), category, name, null, null); } } /** * Only to use if no OLATResourceable Object is available. * @param identity * @param grp * @param resourceTypeName * @param resourceTypeId * @param category * @param name * @return a list of Property objects */ public List<Property> listProperties(Identity identity, BusinessGroup grp, String resourceTypeName, Long resourceTypeId, String category, String name) { return listProperties(identity, grp, resourceTypeName, resourceTypeId, category, name, null, null); } public int countProperties(Identity identity, BusinessGroup grp, String resourceTypeName, Long resourceTypeId, String category, String name, Long longValue, String stringValue) { TypedQuery<Number> query = createQueryListProperties(identity, grp, resourceTypeName, resourceTypeId, category, name, longValue, stringValue, Number.class); return query.getSingleResult().intValue(); } /** * Only to use if no OLATResourceable Object is available. * @param identity * @param grp * @param resourceTypeName * @param resourceTypeId * @param category * @param name * @param longValue * @param stringValue * @return a list of Property objects */ public List<Property> listProperties(Identity identity, BusinessGroup grp, String resourceTypeName, Long resourceTypeId, String category, String name, Long longValue, String stringValue) { TypedQuery<Property> query = createQueryListProperties(identity, grp, resourceTypeName, resourceTypeId, category, name, longValue, stringValue, Property.class); return query.getResultList(); } /** * * @param identity * @param grp * @param resourceTypeName * @param resourceTypeId * @param category * @param name * @param longValue * @param stringValue * @param resultClass Only Number and Property are acceptable * @return */ private <U> TypedQuery<U> createQueryListProperties(Identity identity, BusinessGroup grp, String resourceTypeName, Long resourceTypeId, String category, String name, Long longValue, String stringValue, Class<U> resultClass) { StringBuilder sb = new StringBuilder(); if(Number.class.equals(resultClass)) { sb.append("select count(v) from ").append(Property.class.getName()).append(" as v "); if (identity != null) { sb.append(" inner join v.identity identity "); } if (grp != null) { sb.append(" inner join v.grp grp "); } } else { sb.append("select v from ").append(Property.class.getName()).append(" as v "); if (identity != null) { sb.append(" inner join fetch v.identity identity "); } if (grp != null) { sb.append(" inner join fetch v.grp grp "); } } sb.append(" where "); boolean and = false; if (identity != null) { and = and(sb, and); sb.append("identity.key=:identityKey"); } if (grp != null) { and = and(sb, and); sb.append("grp.key=:groupKey"); } if (resourceTypeName != null) { and = and(sb, and); sb.append("v.resourceTypeName=:resName"); } if (resourceTypeId != null) { and = and(sb, and); sb.append(" v.resourceTypeId=:resId"); } if (category != null) { and = and(sb, and); sb.append("v.category=:cat"); } if (name != null) { and = and(sb, and); sb.append("v.name=:name"); } if (longValue != null) { and = and(sb, and); sb.append("v.longValue=:long"); } if (stringValue != null) { and = and(sb, and); sb.append("v.stringValue=:string"); } TypedQuery<U> queryProps = DBFactory.getInstance().getCurrentEntityManager().createQuery(sb.toString(), resultClass); if (identity != null) { queryProps.setParameter("identityKey", identity.getKey()); } if (grp != null) { queryProps.setParameter("groupKey", grp.getKey()); } if (resourceTypeName != null) { queryProps.setParameter("resName", resourceTypeName); } if (resourceTypeId != null) { queryProps.setParameter("resId", resourceTypeId); } if (category != null) { queryProps.setParameter("cat", category); } if (name != null) { queryProps.setParameter("name", name); } if (longValue != null) { queryProps.setParameter("long", longValue); } if (stringValue != null) { queryProps.setParameter("string", stringValue); } return queryProps; } /** * deletes properties. IMPORTANT: if an argument is null, then it will be not considered in the delete statement, which means not only the record having a "null" value will be deleted, but all. * @param identity * @param grp * @param resourceable * @param category * @param name */ public int deleteProperties(Identity identity, BusinessGroup grp, OLATResourceable resourceable, String category, String name) { StringBuilder sb = new StringBuilder(); sb.append("delete from ").append(Property.class.getName()).append(" as v where "); boolean and = false; if (identity != null) { and = and(sb, and); sb.append("identity.key=:identityKey"); } if (grp != null) { and = and(sb, and); sb.append("v.grp.key=:groupKey"); } if (resourceable != null) { and = and(sb, and); sb.append("v.resourceTypeName=:resName and v.resourceTypeId"); if (resourceable.getResourceableId() == null) { sb.append(" is null"); } else { sb.append(" =:resId"); } } if (category != null) { and = and(sb, and); sb.append("v.category=:cat"); } if (name != null) { and = and(sb, and); sb.append("v.name=:name"); } Query queryProps = DBFactory.getInstance().getCurrentEntityManager().createQuery(sb.toString()); if (identity != null) { queryProps.setParameter("identityKey", identity.getKey()); } if (grp != null) { queryProps.setParameter("groupKey", grp.getKey()); } if (resourceable != null) { queryProps.setParameter("resName", resourceable.getResourceableTypeName()); if (resourceable.getResourceableId() != null) { queryProps.setParameter("resId", resourceable.getResourceableId()); } } if (category != null) { queryProps.setParameter("cat", category); } if (name != null) { queryProps.setParameter("name", name); } return queryProps.executeUpdate(); } /** * Generic find method. Returns a list of Property objects. This is an exact match i.e. if you pass-on null values, * null values will be included in the query. * * @param identity * @param grp * @param resourceable * @param category * @param name * @return a list of Property objects. */ public List<Property> findProperties(Identity identity, BusinessGroup grp, OLATResourceable resourceable, String category, String name) { if (resourceable == null) return findProperties(identity, grp, null, null, category, name); else return findProperties(identity, grp, resourceable.getResourceableTypeName(), resourceable.getResourceableId(), category, name); } /** * Only to use if no OLATResourceable Object is available. * @param identity * @param grp * @param resourceTypeName * @param resourceTypeId * @param category * @param name * @return List of properties */ public List<Property> findProperties(Identity identity, BusinessGroup grp, String resourceTypeName, Long resourceTypeId, String category, String name) { StringBuilder sb = new StringBuilder(); sb.append("select v from ").append(Property.class.getName()).append(" as v "); if (identity != null) { sb.append(" inner join fetch v.identity identity where identity.key=:identityKey"); } else { sb.append(" where v.identity is null"); } sb.append(" and v.grp "); if (grp != null) sb.append(".key=:groupKey"); else sb.append(" is null"); sb.append(" and v.resourceTypeName "); if (resourceTypeName != null) sb.append("=:resName"); else sb.append(" is null"); sb.append(" and v.resourceTypeId"); if (resourceTypeId != null) sb.append("=:resId"); else sb.append(" is null"); sb.append(" and v.category"); if (category != null) sb.append("=:cat"); else sb.append(" is null"); sb.append(" and v.name"); if (name != null) sb.append("=:name"); else sb.append(" is null"); TypedQuery<Property> queryProps = DBFactory.getInstance().getCurrentEntityManager().createQuery(sb.toString(), Property.class); if (identity != null) { queryProps.setParameter("identityKey", identity.getKey()); } if (grp != null) { queryProps.setParameter("groupKey", grp.getKey()); } if (resourceTypeName != null) { queryProps.setParameter("resName", resourceTypeName); } if (resourceTypeId != null) { queryProps.setParameter("resId", resourceTypeId); } if (category != null) { queryProps.setParameter("cat", category); } if (name != null) { queryProps.setParameter("name", name); } return queryProps.getResultList(); } /** * Get a list of identities that have properties given the restricting values * @param resourceable Search restricted to this resourcable * @param category Search restricted to this property category * @param name Search restricted to this property name * @param matchNullValues true: null values in the above restricting values will be * added as null values to the query; false: null values in the restricting values will * be ignored in the query * @return List of identities */ public List<Identity> findIdentitiesWithProperty(OLATResourceable resourceable, String category, String name, boolean matchNullValues) { if (resourceable == null) return findIdentitiesWithProperty(null, null, category, name, matchNullValues); else return findIdentitiesWithProperty(resourceable.getResourceableTypeName(), resourceable.getResourceableId(), category, name, matchNullValues); } /** * Get a list of identities that have properties given the restricting values * @param resourceTypeName Search restricted to this resource type name * @param resourceTypeId Search restricted to this resource type id * @param category Search restricted to this property category * @param name Search restricted to this property name * @param matchNullValues true: null values in the above restricting values will be * added as null values to the query; false: null values in the restricting values will * be ignored in the query * @return List of identities */ public List<Identity> findIdentitiesWithProperty(String resourceTypeName, Long resourceTypeId, String category, String name, boolean matchNullValues) { StringBuilder sb = new StringBuilder(); sb.append("select distinct i from ").append(Property.class.getName()).append(" as p") .append(" inner join p.identity i"); boolean and = false; if (resourceTypeName != null) { and = appendAnd(sb, "p.resourceTypeName=:resName", and); } else if (matchNullValues) { and = appendAnd(sb, "p.resourceTypeName is null", and); } if (resourceTypeId != null) { and = appendAnd(sb, "p.resourceTypeId =:resId", and); } else if (matchNullValues) { and = appendAnd(sb, "p.resourceTypeId is null", and); } if (category != null) { and = appendAnd(sb, "p.category=:cat", and); } else if (matchNullValues) { and = appendAnd(sb, "p.category is null", and); } if (name != null) { and = appendAnd(sb, "p.name=:name", and); } else if (matchNullValues) { and = appendAnd(sb, "p.name is null", and); } TypedQuery<Identity> queryIdentities = DBFactory.getInstance().getCurrentEntityManager() .createQuery(sb.toString(), Identity.class); if (resourceTypeName != null) { queryIdentities.setParameter("resName", resourceTypeName); } if (resourceTypeId != null) { queryIdentities.setParameter("resId", resourceTypeId); } if (category != null) { queryIdentities.setParameter("cat", category); } if (name != null) { queryIdentities.setParameter("name", name); } return queryIdentities.getResultList(); } /** * Generic find method. * * @param identity * @param grp * @param resourceable * @param category * @param name * @return Property if found or null * @throws AssertException if more than one match found */ public Property findProperty(Identity identity, BusinessGroup grp, OLATResourceable resourceable, String category, String name) { List<Property> props = findProperties(identity, grp, resourceable, category, name); if (props == null || props.size() == 0) { if(isLogDebugEnabled()) logDebug("Could not find property: " + name); return null; } else if (props.size() > 1) { throw new AssertException("findProperty found more than one properties for identity::" + identity + ", group::" + grp + ", resourceable::" + resourceable + ", category::" + category + ", name::" + name); } return props.get(0); } /** * The query is an exact match where null value are NOT allowed. * @param businessGroup * @param resourceable * @param category * @param name * @return */ public Property findProperty(BusinessGroupRef businessGroup, OLATResourceable resourceable, String category, String name) { StringBuilder sb = new StringBuilder(128); sb.append("select p from ").append(Property.class.getName()).append(" as p") .append(" where p.category=:category and p.name=:name") .append(" and p.grp.key=:groupKey") .append(" and p.resourceTypeName=:resourceTypeName and p.resourceTypeId=:resourceableId"); List<Property> properties = DBFactory.getInstance().getCurrentEntityManager() .createQuery(sb.toString(), Property.class) .setParameter("groupKey", businessGroup.getKey()) .setParameter("resourceTypeName", resourceable.getResourceableTypeName()) .setParameter("resourceableId", resourceable.getResourceableId()) .setParameter("category", category) .setParameter("name", name) .getResultList(); return properties.isEmpty() ? null : properties.get(0); } /** * * @param identities * @param resourceable * @param category * @param name * @return */ public List<Property> findProperties(List<Identity> identities, OLATResourceable resourceable, String category, String name) { if(identities == null || identities.isEmpty()) { return Collections.emptyList(); } StringBuilder query = new StringBuilder(); query.append("select p from ").append(Property.class.getName()).append(" as p") .append(" inner join fetch p.identity identity ") .append(" where identity in (:identities)"); if (resourceable != null) { query.append(" and p.resourceTypeName=:resourceTypeName and p.resourceTypeId=:resourceableId"); } if (category != null) { query.append(" and p.category=:category"); } if (name != null) { query.append(" and p.name=:name"); } TypedQuery<Property> dbQuery = DBFactory.getInstance().getCurrentEntityManager() .createQuery(query.toString(), Property.class) .setParameter("identities", identities);; if (resourceable != null) { dbQuery.setParameter("resourceTypeName", resourceable.getResourceableTypeName()); dbQuery.setParameter("resourceableId", resourceable.getResourceableId()); } if (category != null) { dbQuery.setParameter("category", category); } if (name != null) { dbQuery.setParameter("name", name); } List<Property> props = dbQuery.getResultList(); return props; } /** * * @param resourceables * @param category * @param name * @return */ public List<Property> findProperties(String resourceableTypeName, List<Long> resourceableIds, String category, String name) { if(resourceableIds == null || resourceableIds.isEmpty() || !StringHelper.containsNonWhitespace(resourceableTypeName)) { return Collections.emptyList(); } StringBuilder query = new StringBuilder(); query.append("select p from ").append(Property.class.getName()).append(" as p") .append(" where p.resourceTypeName=:resourceTypeName and p.resourceTypeId in (:resourceableIds)"); if (category != null) { query.append(" and p.category=:category"); } if (name != null) { query.append(" and p.name=:name"); } TypedQuery<Property> dbQuery = DBFactory.getInstance().getCurrentEntityManager() .createQuery(query.toString(), Property.class) .setParameter("resourceTypeName", resourceableTypeName) .setParameter("resourceableIds", resourceableIds); if (category != null) { dbQuery.setParameter("category", category); } if (name != null) { dbQuery.setParameter("name", name); } List<Property> props = dbQuery.getResultList(); return props; } /** * Gets the property by long value. */ public Property getPropertyByLongValue (long longValue, String name) { StringBuilder query = new StringBuilder(); query.append("select p from ") .append(Property.class.getName()) .append(" as p") .append(" where p.longValue=:longValue"); if (name != null) { query.append(" and p.name=:name"); } TypedQuery<Property> dbQuery = DBFactory.getInstance().getCurrentEntityManager() .createQuery(query.toString(), Property.class) .setParameter("longValue", longValue); if (name != null) { dbQuery.setParameter("name", name); } List<Property> properties = dbQuery.setMaxResults(1).getResultList(); if (properties.size() > 0) { return properties.get(0); } else { return null; } } /** * @return a list of all available resource type names */ public List<String> getAllResourceTypeNames() { StringBuilder sb = new StringBuilder(); sb.append("select distinct v.resourceTypeName from ").append(Property.class.getName()).append(" as v where v.resourceTypeName is not null"); return DBFactory.getInstance().getCurrentEntityManager().createQuery(sb.toString(), String.class).getResultList(); } /** * Delete all properties of a certain identity. * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity) */ @Override public void deleteUserData(Identity identity, String newDeletedUserName, File archivePath) { List<Property> userProperterties = listProperties(identity, null, null, null, null, null); for (Iterator<Property> iter = userProperterties.iterator(); iter.hasNext(); ) { deleteProperty( iter.next()); } if(isLogDebugEnabled()) { logDebug("All properties deleted for identity=" + identity); } } public Property createProperty() { Property p = new Property(); return p; } private boolean and(StringBuilder sb, boolean and) { if(and) sb.append(" and "); return true; } private boolean appendAnd(StringBuilder sb, String content, boolean and) { if(and) sb.append(" and "); else sb.append(" where "); sb.append(content).append(" "); return true; } }