/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <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 the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <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>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.portfolio.manager;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.TypedQuery;
import org.hibernate.ObjectNotFoundException;
import org.olat.basesecurity.Group;
import org.olat.basesecurity.GroupRoles;
import org.olat.basesecurity.IdentityRef;
import org.olat.basesecurity.PolicyImpl;
import org.olat.basesecurity.SecurityGroupImpl;
import org.olat.basesecurity.SecurityGroupMembershipImpl;
import org.olat.basesecurity.manager.GroupDAO;
import org.olat.core.CoreSpringFactory;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.persistence.DBQuery;
import org.olat.core.commons.persistence.PersistentObject;
import org.olat.core.commons.services.commentAndRating.CommentAndRatingService;
import org.olat.core.commons.services.notifications.NotificationsManager;
import org.olat.core.commons.services.notifications.SubscriptionContext;
import org.olat.core.id.Identity;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.AssertException;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.StringHelper;
import org.olat.core.util.resource.OresHelper;
import org.olat.portfolio.model.artefacts.AbstractArtefact;
import org.olat.portfolio.model.restriction.CollectRestriction;
import org.olat.portfolio.model.restriction.RestrictionsConstants;
import org.olat.portfolio.model.structel.EPAbstractMap;
import org.olat.portfolio.model.structel.EPDefaultMap;
import org.olat.portfolio.model.structel.EPMapShort;
import org.olat.portfolio.model.structel.EPPage;
import org.olat.portfolio.model.structel.EPStructureElement;
import org.olat.portfolio.model.structel.EPStructureElementToGroupRelation;
import org.olat.portfolio.model.structel.EPStructureToArtefactLink;
import org.olat.portfolio.model.structel.EPStructureToStructureLink;
import org.olat.portfolio.model.structel.EPStructuredMap;
import org.olat.portfolio.model.structel.EPStructuredMapTemplate;
import org.olat.portfolio.model.structel.EPTargetResource;
import org.olat.portfolio.model.structel.ElementType;
import org.olat.portfolio.model.structel.PortfolioStructure;
import org.olat.portfolio.model.structel.PortfolioStructureMap;
import org.olat.portfolio.model.structel.PortfolioStructureRef;
import org.olat.portfolio.model.structel.StructureStatusEnum;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryManager;
import org.olat.repository.RepositoryService;
import org.olat.repository.manager.RepositoryEntryRelationDAO;
import org.olat.resource.OLATResource;
import org.olat.resource.OLATResourceManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
*
* Description:<br>
* Manager to operate ePortfolio maps, structure-elements, pages.
*
* <P>
* Initial Date: 11.06.2010 <br>
* @author Roman Haag, roman.haag@frentix.com, http://www.frentix.com
*/
@Service("epStructureManager")
public class EPStructureManager {
public static final String STRUCTURE_ELEMENT_TYPE_NAME = "EPStructureElement";
public static final OLATResourceable ORES_MAPOWNER = OresHelper.lookupType(EPStructureManager.class, "EPOwner");
public static final OLog log = Tracing.createLoggerFor(EPStructureManager.class);
@Autowired
private DB dbInstance;
@Autowired
private RepositoryManager repositoryManager;
@Autowired
private OLATResourceManager resourceManager;
@Autowired
private GroupDAO groupDao;
@Autowired
private RepositoryService repositoryService;
@Autowired
private RepositoryEntryRelationDAO repositoryEntyRelationDao;
/**
* Return the list of artefacts glued to this structure element
* @param structure
* @return A list of artefacts
*/
protected List<AbstractArtefact> getArtefacts(PortfolioStructure structure) {
return getArtefacts(structure, -1, -1);
}
/**
* recursively fetches all linked artefacts in the given map.<br />
* ( iterates over all pages in the map, all artefacts on these pages, all
* artefacts in structureElements on these pages)
*
* FXOLAT-431
*
* @param map
* @return
protected List<AbstractArtefact> getAllArtefactsInMap(EPAbstractMap map){
List<AbstractArtefact> results = new ArrayList<AbstractArtefact>();
List<PortfolioStructure> children = loadStructureChildren(map);
for (PortfolioStructure child : children) {
// maps have pages as children, this will be true..!
if(child instanceof EPPage){
results.addAll(getArtefacts(child));
}
}
return results;
}
*/
protected boolean hasMap(IdentityRef identity) {
StringBuilder sb = new StringBuilder();
sb.append("select stEl.key from ").append(EPStructureElement.class.getName()).append(" stEl ")
.append(" inner join stEl.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup")
.append(" inner join baseGroup.members as membership on (membership.identity.key=:identityKey and membership.role='").append(GroupRoles.owner.name()).append("')");
List<Long> count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Long.class)
.setParameter("identityKey", identity.getKey())
.setFirstResult(0)
.setMaxResults(1)
.getResultList();
return count != null && count.size() > 0 && count.get(0) != null && count.get(0) >= 0;
}
protected List<PortfolioStructureMap> getOpenStructuredMapAfterDeadline() {
StringBuilder sb = new StringBuilder();
sb.append("select map from ").append(EPStructuredMap.class.getName()).append(" as map");
sb.append(" where (map.status is null or not(map.status = 'closed'))")
.append(" and map.deadLine<:currentDate");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setDate("currentDate", new Date());
@SuppressWarnings("unchecked")
List<PortfolioStructureMap> maps = query.list();
return maps;
}
protected List<PortfolioStructure> getStructureElements(int firstResult, int maxResults, ElementType... types){
StringBuilder sb = new StringBuilder();
sb.append("select stEl from ").append(EPStructureElement.class.getName()).append(" stEl");
sb.append(" where stEl.class in (");
boolean first = true;
for(ElementType type:types) {
if(first) first = false;
else sb.append(",");
sb.append(getImplementation(type).getName());
}
sb.append(")");
DBQuery query = dbInstance.createQuery(sb.toString());
if(firstResult > 0) {
query.setFirstResult(firstResult);
}
if(maxResults > 0) {
query.setMaxResults(maxResults);
}
@SuppressWarnings("unchecked")
List<PortfolioStructure> pStructs = query.list();
return pStructs;
}
protected List<PortfolioStructure> getStructureElementsForUser(IdentityRef ident, ElementType... types){
StringBuilder sb = new StringBuilder();
sb.append("select stEl from ").append(EPStructureElement.class.getName()).append(" as stEl")
.append(" inner join stEl.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup")
.append(" where exists (select membership from bgroupmember as membership " )
.append(" where baseGroup=membership.group and membership.identity.key=:identityKey and membership.role='").append(GroupRoles.owner.name()).append("'")
.append(" )");
if(types != null && types.length > 0) {
sb.append(" and stEl.class in (");
boolean first = true;
for(ElementType type:types) {
if(first) first = false;
else sb.append(",");
sb.append(getImplementation(type).getName());
}
sb.append(")");
}
return dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), PortfolioStructure.class)
.setParameter("identityKey", ident.getKey())
.getResultList();
}
/**
* Check if the identity is owner of the map identified by the specified resource
* @param identity
* @param ores
* @return
*/
protected boolean isMapOwner(IdentityRef identity, OLATResourceable ores) {
StringBuilder sb = new StringBuilder();
sb.append("select count(stEl) from ").append(EPStructureElement.class.getName()).append(" stEl ")
.append(" inner join stEl.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup")
.append(" where stEl.olatResource.resId=:resourceableId")
.append(" and stEl.olatResource.resName=:resourceableTypeName")
.append(" and exists (select membership from bgroupmember as membership " )
.append(" where baseGroup=membership.group and membership.identity.key=:identityKey and membership.role='").append(GroupRoles.owner.name()).append("'")
.append(" )");
Number count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class)
.setParameter("identityKey", identity.getKey())
.setParameter("resourceableId", ores.getResourceableId())
.setParameter("resourceableTypeName", ores.getResourceableTypeName())
.getSingleResult();
return count == null ? false : count.intValue() > 0;
}
/**
* Check if the identity is owner of the map identified by the specified key
* @param identity
* @param mapKey The structure primary key
* @return
*/
protected boolean isMapOwner(IdentityRef identity, Long mapKey) {
StringBuilder sb = new StringBuilder();
sb.append("select count(stEl) from ").append(EPStructureElement.class.getName()).append(" stEl ")
.append(" inner join stEl.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup")
.append(" where stEl.key=:key")
.append(" and exists (select membership from bgroupmember as membership " )
.append(" where baseGroup=membership.group and membership.identity.key=:identityKey and membership.role='").append(GroupRoles.owner.name()).append("'")
.append(" )");
Number count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class)
.setParameter("identityKey", identity.getKey())
.setParameter("key", mapKey)
.getSingleResult();
return count == null ? false : count.intValue() > 0;
}
/**
* Check if the identity is owner or is in a valid policy
* @param identity
* @param ores
* @return
*/
protected boolean isMapVisible(IdentityRef identity, OLATResourceable ores) {
StringBuilder sb = new StringBuilder();
sb.append("select count(stEl) from ").append(EPStructureElement.class.getName()).append(" stEl")
.append(" inner join stEl.olatResource as oRes")
.append(" inner join stEl.groups as relGroup")
.append(" where oRes.resId=:resourceableId and oRes.resName=:resourceableTypeName")
.append(" and (relGroup.validFrom is null or relGroup.validFrom<=:date)")
.append(" and (relGroup.validTo is null or relGroup.validTo>=:date)")
.append(" and (relGroup.role='").append(EPMapPolicy.Type.allusers.name()).append("'")
.append(" or exists (select membership from bgroupmember as membership " )
.append(" where membership.group=relGroup.group and membership.identity.key=:identityKey")
.append(" )")
.append(" )");
Number count = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), Number.class)
.setParameter("identityKey", identity.getKey())
.setParameter("resourceableId", ores.getResourceableId())
.setParameter("resourceableTypeName", ores.getResourceableTypeName())
.setParameter("date", new Date())
.getSingleResult();
return count == null ? false : count.intValue() > 0;
}
/**
*
* @param select
* @param choosenOwner
* @param limitFrom
* @param limitTo
* @param types
* @return
*/
private <U> TypedQuery<U> buildStructureElementsFromOthersLimitedQuery(Identity choosenOwner, Class<U> cl, ElementType... types){
StringBuilder sb = new StringBuilder();
if(cl.equals(Number.class)) {
sb.append("select count(stEl) from ").append(EPStructureElement.class.getName()).append(" stEl ")
.append(" inner join stEl.olatResource as oRes ");
} else {
sb.append("select stEl from ").append(EPStructureElement.class.getName()).append(" stEl ")
.append(" inner join fetch stEl.olatResource as oRes ");
}
sb.append(" inner join stEl.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup");
sb.append(" where oRes in ( ").append(" select policy.olatResource from").append(" ").append(PolicyImpl.class.getName()).append(" as policy, ").append(" ")
.append(SecurityGroupImpl.class.getName()).append(" as sgi,").append(" ").append(SecurityGroupMembershipImpl.class.getName()).append(" as sgmsi ")
.append(" where sgi = policy.securityGroup")// implicit inner join
.append(" and (sgmsi.securityGroup = sgi and sgmsi.identity =:ident) ")// member of the security group
.append(" and (policy.from is null or policy.from<=:date)").append(" and (policy.to is null or policy.to>=:date)").append(" )");
// remove owner
sb.append(" and not exists ( ").append("select sgi2 from bgroup as sgi2, bgroupmember as sgmsi2 ")
.append(" where baseGroup=sgi2 and sgmsi2.group=sgi2 and sgmsi2.identity=:ident")
.append(" )");
if (choosenOwner != null) {
sb.append(" and exists (select sgi.key from bgroup as sgi, bgroupmember as sgmsi ")
.append(" where sgmsi.group=baseGroup and sgmsi.identity=:owner")
.append(" )");
}
if (types != null && types.length > 0) {
sb.append(" and stEl.class in (");
boolean first = true;
for (final ElementType type : types) {
if (first) {
first = false;
} else {
sb.append(",");
}
sb.append(getImplementation(type).getName());
}
sb.append(")");
}
return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), cl);
}
protected int countStructureElementsFromOthers(final Identity ident, final Identity choosenOwner ,final ElementType... types){
TypedQuery<Number> query = buildStructureElementsFromOthersLimitedQuery(choosenOwner, Number.class, types);
query.setParameter("ident", ident)
.setParameter("date", new Date());
if (choosenOwner != null) {
query.setParameter("owner", choosenOwner);
}
Number count = query.getSingleResult();
return count == null ? 0 : count.intValue();
}
protected List<PortfolioStructure> getStructureElementsFromOthersLimited(Identity ident, Identity choosenOwner,
int limitFrom, int limitTo, ElementType... types){
TypedQuery<PortfolioStructure> query = buildStructureElementsFromOthersLimitedQuery(choosenOwner, PortfolioStructure.class, types);
//limits
if(limitTo > 0 && (limitFrom < limitTo)){
query.setFirstResult(limitFrom);
query.setMaxResults(limitTo-limitFrom);
}
query.setParameter("ident", ident)
.setParameter("date", new Date());
if (choosenOwner != null) {
query.setParameter("owner", choosenOwner);
}
return query.getResultList();
}
protected List<PortfolioStructure> getStructureElementsFromOthersWithoutPublic(IdentityRef ident, IdentityRef choosenOwner, ElementType... types){
StringBuilder sb = new StringBuilder();
sb.append("select stEl from ").append(EPStructureElement.class.getName()).append(" stEl ")
.append(" inner join fetch stEl.olatResource as oRes ")
.append(" inner join stEl.groups as relGroup on relGroup.defaultGroup=false")
.append(" inner join relGroup.group as baseGroup")
.append(" inner join baseGroup.members as members")
.append(" where members.identity.key=:identityKey")
.append(" and (relGroup.validFrom is null or relGroup.validFrom<=:date)")
.append(" and (relGroup.validTo is null or relGroup.validTo>=:date)");
if(choosenOwner != null) {
sb.append(" and exists (select sgmsi from bgroupmember as sgmsi ")
.append(" where sgmsi.group=baseGroup and sgmsi.identity.key=:ownerKey")
.append(" )");
}
if(types != null && types.length > 0) {
sb.append(" and stEl.class in (");
boolean first = true;
for(ElementType type:types) {
if(first) first = false;
else sb.append(",");
sb.append(getImplementation(type).getName());
}
sb.append(")");
}
TypedQuery<PortfolioStructure> query =dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), PortfolioStructure.class)
.setParameter("identityKey", ident.getKey())
.setParameter("date", new Date());
if(choosenOwner != null) {
query.setParameter("ownerKey", choosenOwner.getKey());
}
return query.getResultList();
}
protected boolean hasStructureElementsFromOthersWithoutPublic(IdentityRef ident){
StringBuilder sb = new StringBuilder();
sb.append("select stEl.key from ").append(EPStructureElement.class.getName()).append(" stEl ")
.append(" inner join stEl.groups as relGroup on relGroup.defaultGroup=false")
.append(" inner join relGroup.group as baseGroup")
.append(" inner join baseGroup.members as members")
.append(" where members.identity.key=:identityKey")
.append(" and (relGroup.validFrom is null or relGroup.validFrom<=:date)")
.append(" and (relGroup.validTo is null or relGroup.validTo>=:date)");
List<Long> count = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Long.class)
.setParameter("identityKey", ident.getKey())
.setParameter("date", new Date())
.setFirstResult(0)
.setMaxResults(1)
.getResultList();
return count != null && count.size() > 0 && count.get(0) != null && count.get(0) >= 0;
}
private Class<?> getImplementation(ElementType type) {
switch(type) {
case DEFAULT_MAP: return EPDefaultMap.class;
case STRUCTURED_MAP: return EPStructuredMap.class;
case TEMPLATE_MAP: return EPStructuredMapTemplate.class;
default: return null;
}
}
protected List<PortfolioStructure> getReferencedMapsForArtefact(AbstractArtefact artefact){
List<PortfolioStructure> pfList = getAllReferencesForArtefact(artefact);
List<PortfolioStructure> mapList = new ArrayList<PortfolioStructure>();
for (Iterator<?> iterator = pfList.iterator(); iterator.hasNext();) {
EPStructureElement portfolioStructure = (EPStructureElement) iterator.next();
EPStructureElement actStruct = portfolioStructure;
while (actStruct.getRoot() != null){
EPStructureElement actRoot = actStruct.getRoot();
if (actRoot != null) {
actStruct = actRoot;
}
}
if (!mapList.contains(actStruct)) mapList.add(actStruct);
}
return mapList;
}
protected List<PortfolioStructure> getAllReferencesForArtefact(AbstractArtefact artefact){
StringBuilder sb = new StringBuilder();
sb.append("select link.structureElement from ").append(EPStructureToArtefactLink.class.getName()).append(" link")
.append(" where link.artefact=:artefactEl ");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setEntity("artefactEl", artefact);
@SuppressWarnings("unchecked")
List<PortfolioStructure> pfList = query.list();
return pfList;
}
/**
* Return the list of artefacts glued to this structure element
* @param structure
* @param firstResult
* @param maxResults
* @return
*/
public List<AbstractArtefact> getArtefacts(PortfolioStructure structure, int firstResult, int maxResults) {
StringBuilder sb = new StringBuilder();
sb.append("select link.artefact from ").append(EPStructureToArtefactLink.class.getName()).append(" link")
.append(" where link.structureElement.key=:structureElKey order by link.order");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setLong("structureElKey", structure.getKey());
if(firstResult > 0) {
query.setFirstResult(firstResult);
}
if(maxResults > 0) {
query.setMaxResults(maxResults);
}
@SuppressWarnings("unchecked")
List<AbstractArtefact> artefacts = query.list();
return artefacts;
}
/**
* Return the number of artefacts hold by a structure element
* @param structure
* @return
*/
public int countArtefacts(PortfolioStructure structure) {
StringBuilder sb = new StringBuilder();
sb.append("select count(link) from ").append(EPStructureToArtefactLink.class.getName()).append(" link")
.append(" where link.structureElement=:structureEl");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setEntity("structureEl", structure);
Number count = (Number)query.uniqueResult();
return count.intValue();
}
/**
* Count all artefacts (links) in a map
*/
protected int countArtefactsRecursively(PortfolioStructure structure) {
//return countArtefactsRecursively(structure, 0);
StringBuilder sb = new StringBuilder();
sb.append("select count(link) from ").append(EPStructureToArtefactLink.class.getName()).append(" link")
.append(" inner join link.structureElement structure ")
.append(" inner join structure.rootMap root")
.append(" where root=:structureEl");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setEntity("structureEl", structure);
Number count = (Number)query.uniqueResult();
return count.intValue();
}
protected int countArtefactsRecursively(PortfolioStructure structure, int res){
List<PortfolioStructure> childs = loadStructureChildren(structure);
res = res + countArtefacts(structure);
for (PortfolioStructure portfolioStructure : childs) {
res = countArtefactsRecursively(portfolioStructure, res);
}
return res;
}
protected boolean isArtefactInStructure(AbstractArtefact artefact, PortfolioStructure structure){
StringBuilder sb = new StringBuilder();
sb.append("select link.key from ").append(EPStructureToArtefactLink.class.getName()).append(" link")
.append(" where link.structureElement=:structureEl and link.artefact=:artefact");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setEntity("structureEl", structure);
query.setEntity("artefact", artefact);
@SuppressWarnings("unchecked")
List<Long> key = query.list();
return key.size() == 1 ? true : false;
}
/**
* Number of children
*/
public int countStructureChildren(PortfolioStructure structure) {
if (structure == null) throw new NullPointerException();
StringBuilder sb = new StringBuilder();
sb.append("select count(link) from ").append(EPStructureToStructureLink.class.getName()).append(" link")
.append(" where link.parent=:structureEl");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setEntity("structureEl", structure);
Number count = (Number)query.uniqueResult();
return count.intValue();
}
/**
* Retrieve the children structures
* @param structure
* @return
*/
protected List<PortfolioStructure> loadStructureChildren(PortfolioStructure structure) {
return loadStructureChildren(structure, -1, -1);
}
/**
*
* @param structure
* @param firstResult
* @param maxResults
* @return
*/
protected List<PortfolioStructure> loadStructureChildren(PortfolioStructure structure, int firstResult, int maxResults) {
if (structure == null) throw new NullPointerException();
StringBuilder sb = new StringBuilder();
sb.append("select link.child from ").append(EPStructureToStructureLink.class.getName()).append(" link")
.append(" where link.parent=:structureEl order by link.order");
DBQuery query = dbInstance.createQuery(sb.toString());
if(firstResult > 0) {
query.setFirstResult(firstResult);
}
if(maxResults > 0) {
query.setMaxResults(maxResults);
}
query.setEntity("structureEl", structure);
@SuppressWarnings("unchecked")
List<PortfolioStructure> resources = query.list();
return resources;
}
/**
* Retrieve the parent of the structure
* @param structure
* @return
*/
protected PortfolioStructure loadStructureParent(PortfolioStructureRef structure) {
if (structure == null) throw new NullPointerException();
StringBuilder sb = new StringBuilder();
sb.append("select link.parent from ").append(EPStructureToStructureLink.class.getName()).append(" link")
.append(" where link.child.key=:structureElKey");
List<PortfolioStructure> resources = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), PortfolioStructure.class)
.setParameter("structureElKey", structure.getKey())
.getResultList();
if(resources.isEmpty()) return null;
if(resources.size() == 1) return resources.get(0);
log.error("A structure child has more than one parent");
return null;
}
protected Integer[] getRestrictionStatistics(PortfolioStructure structure) {
if (structure instanceof EPStructureElement) {
EPStructureElement structEl = (EPStructureElement) structure;
structEl = (EPStructureElement) reloadPortfolioStructure(structEl);
final List<CollectRestriction> restrictions = structEl.getCollectRestrictions();
if (restrictions != null && !restrictions.isEmpty()) {
int todo = 0;
int done = 0;
List<AbstractArtefact> artefacts = getArtefacts(structEl);
for (CollectRestriction cR : restrictions) {
if (RestrictionsConstants.MIN.equals(cR.getRestriction()) || RestrictionsConstants.EQUAL.equals(cR.getRestriction())) {
todo += cR.getAmount();
int actualCRCount = countRestrictionType(artefacts, cR);
done += actualCRCount;
}
}
return new Integer[] { done, todo };
}
}
return null;
}
// count recursively
protected Integer[] getRestrictionStatisticsOfMap(PortfolioStructure structureMap, int done, int todo) {
final List<PortfolioStructure> children = loadStructureChildren(structureMap);
for (final PortfolioStructure child : children) {
Integer[] childStat = getRestrictionStatisticsOfMap(child, done, todo);
done = childStat[0];
todo = childStat[1];
}
// summarize
Integer[] statsArr = getRestrictionStatistics(structureMap);
if (statsArr != null){
done += statsArr[0];
todo += statsArr[1];
}
return new Integer[] {done, todo};
}
/**
* Add a link between a structure element and an artefact
* @param author
* @param artefact
* @param structure
* @return
*/
protected boolean addArtefactToStructure(Identity author, AbstractArtefact artefact, PortfolioStructure structure) {
if (author == null || artefact == null || structure == null) throw new NullPointerException();
if (structure instanceof EPStructureElement) {
EPStructureElement structureEl = (EPStructureElement)structure;
boolean canAdd = canAddArtefact(structureEl, artefact);
if(!canAdd) {
return false;
}
//save eventual changes
//TODO update the changes before dbInstance.updateObject(structureEl);
//reconnect to the session
structureEl = (EPStructureElement)dbInstance.loadObject(structureEl);
EPStructureToArtefactLink link = new EPStructureToArtefactLink();
link.setArtefact(artefact);
link.setStructureElement(structureEl);
link.setAuthor(author);
structureEl.getInternalArtefacts().add(link);
dbInstance.updateObject(structureEl);
return true;
}
return false;
}
protected boolean canAddArtefact(EPStructureElement structureEl, AbstractArtefact newArtefact) {
List<CollectRestriction> restrictions = structureEl.getCollectRestrictions();
if(restrictions == null || restrictions.isEmpty()) return true;
boolean allOk = true;
List<String> artefactTypeAllowed = new ArrayList<String>();
List<AbstractArtefact> artefacts = getArtefacts(structureEl);
artefacts.add(newArtefact);
for(CollectRestriction restriction:restrictions) {
String type = restriction.getArtefactType();
int count = countRestrictionType(artefacts, restriction);
artefactTypeAllowed.add(type);
if(type.equals(newArtefact.getResourceableTypeName())) {
if(RestrictionsConstants.MAX.equals(restriction.getRestriction())) {
allOk &= (restriction.getAmount() > 0 && count <= restriction.getAmount());
} else if(RestrictionsConstants.EQUAL.equals(restriction.getRestriction())) {
allOk &= (restriction.getAmount() > 0 && count <= restriction.getAmount());
}
}
}
allOk &= artefactTypeAllowed.contains(newArtefact.getResourceableTypeName());
return allOk;
}
protected boolean moveArtefactFromStructToStruct(AbstractArtefact artefact, PortfolioStructure oldParStruct, PortfolioStructure newParStruct) {
EPStructureElement oldEPSt = (EPStructureElement)dbInstance.loadObject((EPStructureElement)oldParStruct);
Identity author = oldEPSt.getInternalArtefacts().get(0).getAuthor();
if (author == null) return false; // old model without author, doesn't work!
String reflexion = getReflexionForArtefactToStructureLink(artefact, oldParStruct);
removeArtefactFromStructure(artefact, oldParStruct);
boolean allOk = false;
allOk = addArtefactToStructure(author, artefact, newParStruct);
if (allOk) return setReflexionForArtefactToStructureLink(artefact, newParStruct, reflexion);
return allOk;
}
protected boolean moveArtefactInStruct(AbstractArtefact artefact, PortfolioStructure parStruct, int position) {
EPStructureElement structureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)parStruct);
Identity author = structureEl.getInternalArtefacts().get(0).getAuthor();
if (author == null) return false; // old model without author, doesn't work!
List<EPStructureToArtefactLink> artefactLinks = structureEl.getInternalArtefacts();
int currentIndex = -1;
for(EPStructureToArtefactLink link:artefactLinks) {
currentIndex++;
if(link.getArtefact().equals(artefact)) {
break;
}
}
if(currentIndex > -1 && currentIndex < artefactLinks.size()) {
EPStructureToArtefactLink link = artefactLinks.remove(currentIndex);
if(position > currentIndex) {
position--;
}
artefactLinks.add(position, link);
}
return true;
}
/**
* Check the collect restriction against the structure element
* @param structure
* @return
*/
protected boolean checkCollectRestriction(PortfolioStructure structure) {
if (structure instanceof EPStructureElement) {
EPStructureElement structureEl = (EPStructureElement)structure;
List<CollectRestriction> restrictions = structureEl.getCollectRestrictions();
if(restrictions == null || restrictions.isEmpty()) return true;
boolean allOk = true;
List<String> artefactTypeAllowed = new ArrayList<String>();
List<AbstractArtefact> artefacts = getArtefacts(structureEl);
for(CollectRestriction restriction:restrictions) {
int count = countRestrictionType(artefacts, restriction);
artefactTypeAllowed.add(restriction.getArtefactType());
boolean ok = true;
if(RestrictionsConstants.MAX.equals(restriction.getRestriction())) {
ok &= (restriction.getAmount() > 0 && count <= restriction.getAmount());
} else if(RestrictionsConstants.MIN.equals(restriction.getRestriction())) {
ok &= (restriction.getAmount() > 0 && count >= restriction.getAmount());
} else if(RestrictionsConstants.EQUAL.equals(restriction.getRestriction())) {
ok &= (restriction.getAmount() > 0 && count == restriction.getAmount());
} else {
ok &= false;
}
allOk &= ok;
}
for(AbstractArtefact artefact:artefacts) {
allOk &= artefactTypeAllowed.contains(artefact.getResourceableTypeName());
}
return allOk;
}
return true;
}
private int countRestrictionType(List<AbstractArtefact> artefacts, CollectRestriction restriction) {
int count = 0;
if(StringHelper.containsNonWhitespace(restriction.getArtefactType())) {
for(AbstractArtefact artefact:artefacts) {
if(restriction.getArtefactType().equals(artefact.getResourceableTypeName())) {
count++;
}
}
}
return count;
}
/**
* Remove a link between a structure element and an artefact.
* @param author The author of the link
* @param artefact The artefact to link
* @param structure The structure element
* @return The link
*/
protected PortfolioStructure removeArtefactFromStructure(AbstractArtefact artefact, PortfolioStructure structure) {
return removeArtefactFromStructure(artefact, structure, false);
}
private PortfolioStructure removeArtefactFromStructure(AbstractArtefact artefact, PortfolioStructure structure, boolean updateFirst) {
if (artefact == null || structure == null) throw new NullPointerException();
if (artefact.getKey() == null) return null;//not persisted
if(structure instanceof EPStructureElement) {
//save eventual changes
if(updateFirst) {
dbInstance.updateObject(structure);
}
//reconnect to the session
EPStructureElement structureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)structure);
EPStructureToArtefactLink linkToDelete = null;
for(Iterator<EPStructureToArtefactLink> linkIt=structureEl.getInternalArtefacts().iterator(); linkIt.hasNext(); ) {
EPStructureToArtefactLink link = linkIt.next();
if(link.getArtefact().getKey().equals(artefact.getKey())) {
linkIt.remove();
linkToDelete = link;
break;
}
}
//I have not set the cascade all delete
if(linkToDelete != null) {
dbInstance.updateObject(structureEl);
dbInstance.deleteObject(linkToDelete);
}
return structureEl;
}
return null;
}
/**
* Move up an artefact in the list
* @param structure
* @param artefact
*/
public void moveUp(PortfolioStructure structure, AbstractArtefact artefact) {
move(structure, artefact, true);
}
/**
* Move down an artefact in the list
* @param structure
* @param artefact
*/
public void moveDown(PortfolioStructure structure, AbstractArtefact artefact) {
move(structure, artefact, false);
}
private void move(PortfolioStructure structure, AbstractArtefact artefact, boolean up) {
if (artefact == null || structure == null) throw new NullPointerException();
if (structure instanceof EPStructureElement) {
//save eventual changes
dbInstance.updateObject(structure);
//reconnect to the session
EPStructureElement structureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)structure);
List<EPStructureToArtefactLink> artefactLinks = structureEl.getInternalArtefacts();
int index = indexOf(artefactLinks, artefact);
if(up && index > 0) {
//swap the link with the previous link in the list
Collections.swap(artefactLinks, index, index-1);
dbInstance.updateObject(structureEl);
} else if(!up && (index >= 0 && index < (artefactLinks.size() - 1))) {
//swap the link with the next link in the list
Collections.swap(artefactLinks, index, index+1);
dbInstance.updateObject(structureEl);
}
}
}
private int indexOf(List<EPStructureToArtefactLink> artefactLinks, AbstractArtefact artefact) {
int count = 0;
for(EPStructureToArtefactLink link:artefactLinks) {
if(link.getArtefact().getKey().equals(artefact.getKey())) {
return count;
}
count++;
}
return -1;
}
/**
* Add a child structure to the parent structure.
* @param parentStructure
* @param childStructure
* @param destinationPos set to -1 to append at the end!
*/
public void addStructureToStructure(PortfolioStructure parentStructure, PortfolioStructure childStructure, int destinationPos) {
if (parentStructure == null || childStructure == null) throw new NullPointerException();
if(childStructure instanceof EPStructureElement) {
//save eventual changes
dbInstance.updateObject(parentStructure);
//reconnect to the session (why reconnect? you update it already)
//parentStructure = (EPStructureElement)dbInstance.loadObject((EPStructureElement)parentStructure);
EPStructureToStructureLink link = new EPStructureToStructureLink();
link.setParent(parentStructure);
link.setChild(childStructure);
//refresh internal link to its root element
((EPStructureElement)childStructure).setRoot((EPStructureElement) parentStructure);
List<EPStructureToStructureLink> internalChildren = ((EPStructureElement)parentStructure).getInternalChildren();
if (destinationPos == -1) {
internalChildren.add(link);
} else if(destinationPos <= internalChildren.size()) {
internalChildren.add(destinationPos, link);
} else {
internalChildren.add(link);
}
}
}
protected boolean moveStructureToNewParentStructure(PortfolioStructure structToBeMvd, PortfolioStructure oldParStruct, PortfolioStructure newParStruct, int destinationPos){
if (structToBeMvd == null || oldParStruct == null || newParStruct == null) throw new NullPointerException();
try { // try catch, as used in d&d TOC-tree, should still continue on error
removeStructure(oldParStruct, structToBeMvd);
addStructureToStructure(newParStruct, structToBeMvd, destinationPos);
} catch (Exception e) {
log.error("could not move structure " + structToBeMvd.getKey() + " from " + oldParStruct.getKey() + " to " + newParStruct.getKey(), e);
return false;
}
return true;
}
public void deleteRootStructure(PortfolioStructure rootStructure) {
if (rootStructure == null) throw new NullPointerException();
if (rootStructure.getKey() == null) return;
if(rootStructure instanceof EPStructureElement) {
dbInstance.deleteObject(rootStructure);
}
}
/**
* Remove a child structure from its parent structure.
* @param parentStructure
* @param childStructure
*
*
*/
// this has to be done recursively for pages, structs also!
// also remove the artefacts from each!
public void removeStructure(PortfolioStructure parentStructure, PortfolioStructure childStructure) {
if (childStructure == null) throw new NullPointerException();
if (childStructure.getKey() == null) return;//child not persisted
if (parentStructure == null) return; // cannot remove with no parent!
if(childStructure instanceof EPStructureElement) {
//save eventual changes
dbInstance.updateObject(parentStructure);
//reconnect to the session
EPStructureToStructureLink linkToDelete = null;
EPStructureElement parentStructureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)parentStructure);
for(Iterator<EPStructureToStructureLink> linkIt=parentStructureEl.getInternalChildren().iterator(); linkIt.hasNext(); ) {
EPStructureToStructureLink link = linkIt.next();
// List<AbstractArtefact> thisStructsArtefacts = getArtefacts(link.getChild());
// for (AbstractArtefact artefact : thisStructsArtefacts) {
// removeArtefactFromStructure(artefact, link.getChild());
// }
if(link.getChild().getKey().equals(childStructure.getKey())) {
linkIt.remove();
linkToDelete = link;
break;
}
}
//I have not set the cascade all delete
if(linkToDelete != null) {
dbInstance.updateObject(parentStructureEl);
dbInstance.deleteObject(linkToDelete);
}
}
if (parentStructure == childStructure) {
deleteRootStructure(childStructure);
return;
}
}
/**
* This method is only for templates.
* @param res
*/
public void deletePortfolioMapTemplate(OLATResourceable res) {
PortfolioStructure map = loadPortfolioStructure(res);
if(map == null) {
return;//nothing to delete
}
removeStructureRecursively(map);
dbInstance.commit();
}
public void removeStructureRecursively(PortfolioStructure struct) {
List<PortfolioStructure> children = loadStructureChildren(struct);
for (PortfolioStructure childstruct : children) {
removeStructureRecursively(childstruct);
}
// remove artefact-links
List<AbstractArtefact> thisStructsArtefacts = getArtefacts(struct);
for (AbstractArtefact artefact : thisStructsArtefacts) {
removeArtefactFromStructure(artefact, struct, false);
}
// remove from parent
PortfolioStructure parent = loadStructureParent(struct);
if (parent == null && struct.getRoot() != null) parent = struct.getRoot();
removeStructure(parent, struct);
// remove collect restriction
struct.getCollectRestrictions().clear();
// remove sharings
if (struct instanceof EPAbstractMap) {
((EPAbstractMap)struct).getGroups().clear();
}
// remove comments and ratings
CommentAndRatingService commentAndRatingService = CoreSpringFactory.getImpl(CommentAndRatingService.class);
commentAndRatingService.deleteAllIgnoringSubPath(struct.getOlatResource());
// FXOLAT-431 remove subscriptions if the current struct is a map
if(struct instanceof EPAbstractMap){
SubscriptionContext subsContext = new SubscriptionContext(EPNotificationsHandler.TYPENNAME, struct.getResourceableId(), EPNotificationsHandler.TYPENNAME);
NotificationsManager.getInstance().delete(subsContext);
}
// remove structure itself
struct = (EPStructureElement) dbInstance.loadObject((EPStructureElement)struct);
dbInstance.deleteObject(struct);
if (struct instanceof EPAbstractMap){
removeBaseGroup((EPAbstractMap)struct);
}
//EPStructuredMapTemplates are linked to a repository entry
//which need the resource
if(!(struct instanceof EPStructuredMapTemplate)) {
resourceManager.deleteOLATResourceable(struct);
}
}
private void removeBaseGroup(EPAbstractMap map) {
Set<EPStructureElementToGroupRelation> relations = map.getGroups();
if (relations != null) {
for(EPStructureElementToGroupRelation relation:relations) {
Group group = relation.getGroup();
if(relation.isDefaultGroup()) {
groupDao.removeMemberships(group);
groupDao.removeGroup(group);
}
}
}
}
/**
* Move a structure element up in the list
* @param parentStructure
* @param childStructure
*/
public void moveUp(PortfolioStructure parentStructure, PortfolioStructure childStructure) {
move(parentStructure, childStructure, true);
}
/**
* Move a structure element down in the list and save the parent and the list
* @param parentStructure
* @param childStructure
*/
public void moveDown(PortfolioStructure parentStructure, PortfolioStructure childStructure) {
move(parentStructure, childStructure, false);
}
private void move(PortfolioStructure parentStructure, PortfolioStructure childStructure, boolean up) {
if (childStructure == null || parentStructure == null) throw new NullPointerException();
if (parentStructure instanceof EPStructureElement) {
//save eventual changes
dbInstance.updateObject(parentStructure);
//reconnect to the session
EPStructureElement structureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)parentStructure);
List<EPStructureToStructureLink> structureLinks = structureEl.getInternalChildren();
int index = indexOf(structureLinks, childStructure);
if(up && index > 0) {
//swap the link with the previous link in the list
Collections.swap(structureLinks, index, index-1);
dbInstance.updateObject(structureEl);
} else if(!up && (index >= 0 && index < (structureLinks.size() - 1))) {
//swap the link with the next link in the list
Collections.swap(structureLinks, index, index+1);
dbInstance.updateObject(structureEl);
}
}
}
protected boolean reOrderStructures(PortfolioStructure parent, PortfolioStructure orderSubject, int orderDest){
EPStructureElement structureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)parent);
List<EPStructureToStructureLink> structureLinks = structureEl.getInternalChildren();
int oldPos = indexOf(structureLinks, orderSubject);
if (oldPos != orderDest && oldPos != -1) {
EPStructureToStructureLink link = structureLinks.remove(oldPos);
if(oldPos < orderDest) {
orderDest--;
}
if(orderDest < 0) {
orderDest = 0;
} else if(orderDest > structureLinks.size()) {
orderDest = structureLinks.size() -1; // place at end
}
structureLinks.add(orderDest, link);
dbInstance.updateObject(structureEl);
return true;
}
return false;
}
private int indexOf(List<EPStructureToStructureLink> structLinks, PortfolioStructure structure) {
int count = 0;
for(EPStructureToStructureLink link:structLinks) {
if(link.getChild().getKey().equals(structure.getKey())) {
return count;
}
count++;
}
return -1;
}
protected void copyStructureRecursively(PortfolioStructure source, PortfolioStructure target, boolean withArtefacts) {
//all changes are overwritten
EPStructureElement targetEl = (EPStructureElement)target;
if(targetEl instanceof EPStructuredMap) {
((EPStructuredMap)targetEl).setCopyDate(new Date());
}
//update the source
dbInstance.updateObject(source);
//reconnect to the session
EPStructureElement sourceEl = (EPStructureElement)source;
targetEl.setStyle(sourceEl.getStyle());
copyEPStructureElementRecursively(sourceEl, targetEl, withArtefacts, true);
}
private void copyEPStructureElementRecursively(EPStructureElement sourceEl, EPStructureElement targetEl, boolean withArtefacts, boolean cloneRestrictions) {
//needed if the sourceEl come from a link. Hibernate doesn't initialize the list properly
sourceEl = (EPStructureElement)dbInstance.loadObject(sourceEl);
if(withArtefacts) {
List<EPStructureToArtefactLink> artefactLinks = sourceEl.getInternalArtefacts();
for(EPStructureToArtefactLink artefactLink:artefactLinks) {
EPStructureToArtefactLink link = instantiateClone(artefactLink);
link.setStructureElement(targetEl);// make the pseudo
targetEl.getInternalArtefacts().add(link); // bidirectional relations
}
}
//clone the links
List<EPStructureToStructureLink> childLinks = sourceEl.getInternalChildren();
for(EPStructureToStructureLink childLink:childLinks) {
copy(childLink, targetEl, withArtefacts, false, cloneRestrictions);
}
savePortfolioStructure(targetEl);
}
/**
* Sync the tree structure recursively with or without artefacts
* @param sourceEl
* @param targetEl
* @param withArtefacts
*/
protected void syncStructureRecursively(PortfolioStructure source, PortfolioStructure target, boolean withArtefacts) {
//all changes are overwritten
EPStructureElement sourceEl = (EPStructureElement)source;
//update the source
dbInstance.updateObject(target);
//reconnect to the session
EPStructureElement targetEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)target);
syncEPStructureElementRecursively(sourceEl, targetEl, withArtefacts);
}
/**
* This sync method syncs the structure of the tree, collect restriction, title, description, representation-mode (table/miniview)
*
* @param sourceEl
* @param targetEl
* @param withArtefacts
*/
private void syncEPStructureElementRecursively(EPStructureElement sourceEl, EPStructureElement targetEl, boolean withArtefacts) {
List<EPStructureToStructureLink> sourceRefLinks = new ArrayList<EPStructureToStructureLink>(sourceEl.getInternalChildren());
List<EPStructureToStructureLink> targetRefLinks = new ArrayList<EPStructureToStructureLink>(targetEl.getInternalChildren());
Comparator<EPStructureToStructureLink> COMPARATOR = new KeyStructureToStructureLinkComparator();
//remove deleted elements
for(Iterator<EPStructureToStructureLink> targetIt=targetEl.getInternalChildren().iterator(); targetIt.hasNext(); ) {
EPStructureToStructureLink targetLink = targetIt.next();
int index = indexOf(sourceRefLinks, targetLink, COMPARATOR);
if(index < 0) {
targetIt.remove();
removeStructureRecursively(targetLink.getChild());
}
}
//add new element
for(EPStructureToStructureLink sourceRefLink:sourceRefLinks) {
int index = indexOf(targetRefLinks, sourceRefLink, COMPARATOR);
if(index < 0) {
//create a new structure element, dont clone restriction!
copy(sourceRefLink, targetEl, withArtefacts, false, false);
}
}
//sync attributes, representation and collect restrictions
copyOrUpdateCollectRestriction(sourceEl, targetEl, true);
targetEl.setArtefactRepresentationMode(sourceEl.getArtefactRepresentationMode());
targetEl.setStyle(sourceEl.getStyle());
targetEl.setTitle(sourceEl.getTitle());
targetEl.setDescription(sourceEl.getDescription());
//at this point, we must have the same content in the two list
//but with perhaps other ordering: reorder
List<EPStructureToStructureLink> targetLinks = targetEl.getInternalChildren();
for(int i=0; i<sourceRefLinks.size(); i++) {
EPStructureToStructureLink sourceRefLink = sourceRefLinks.get(i);
int index = indexOf(targetLinks, sourceRefLink, COMPARATOR);
if(index == i) {
//great, right at its position
} else if (index > i) {
Collections.swap(targetLinks, i, index);
} else {
//not possible
}
//sync recursively
if(index >= 0) {
EPStructureElement subSourceEl = (EPStructureElement)sourceRefLink.getChild();
EPStructureElement subTargetEl = (EPStructureElement)targetLinks.get(i).getChild();
syncEPStructureElementRecursively(subSourceEl, subTargetEl, withArtefacts);
}
}
targetEl = dbInstance.getCurrentEntityManager().merge(targetEl);
}
private int indexOf(List<EPStructureToStructureLink> refLinks, EPStructureToStructureLink link, Comparator<EPStructureToStructureLink> comparator) {
int count=0;
for(EPStructureToStructureLink refLink:refLinks) {
if(comparator.compare(refLink, link) == 0) {
return count;
}
count++;
}
return -1;
}
/**
* Copy/Import structure elements recursively
* @param refLink
* @param targetEl
* @param withArtefacts Copy the artefacts
* @param importEl Don't load elements from the DB
* @param cloneRestrictions should the collect-restrictions be applied? you could also do this manually by copyCollectRestriction()
*/
private void copy(EPStructureToStructureLink refLink, EPStructureElement targetEl, boolean withArtefacts, boolean importEl, boolean cloneRestrictions) {
EPStructureElement childSourceEl = (EPStructureElement)refLink.getChild();
EPStructureElement clonedChildEl = instantiateClone(refLink.getChild());
if(clonedChildEl == null) {
log.warn("Attempt to clone an unsupported structure type: " + refLink.getChild(), null);
} else {
OLATResource resource = resourceManager.createOLATResourceInstance(clonedChildEl.getClass());
clonedChildEl.setOlatResource(resource);
//set root
if(targetEl.getRoot() == null) {
//it's the root element
clonedChildEl.setRoot(targetEl);
} else {
clonedChildEl.setRoot(targetEl.getRoot());
}
if(targetEl.getRootMap() == null && targetEl instanceof PortfolioStructureMap) {
clonedChildEl.setRootMap((PortfolioStructureMap)targetEl);
} else {
clonedChildEl.setRootMap(targetEl.getRootMap());
}
if (!importEl) clonedChildEl.setStructureElSource(childSourceEl.getKey());
if (cloneRestrictions) copyOrUpdateCollectRestriction(childSourceEl, clonedChildEl, true);
if(importEl) {
importEPStructureElementRecursively(childSourceEl, clonedChildEl);
} else {
copyEPStructureElementRecursively(childSourceEl, clonedChildEl, withArtefacts, cloneRestrictions);
}
EPStructureToStructureLink link = new EPStructureToStructureLink();
link.setParent(targetEl);
link.setChild(clonedChildEl);
targetEl.getInternalChildren().add(link);
}
}
private EPStructureToArtefactLink instantiateClone(EPStructureToArtefactLink link) {
EPStructureToArtefactLink clone = new EPStructureToArtefactLink();
clone.setArtefact(link.getArtefact());
clone.setAuthor(link.getAuthor());
clone.setCreationDate(new Date());
clone.setReflexion(link.getReflexion());
return clone;
}
private EPStructureElement instantiateClone(PortfolioStructure source) {
EPStructureElement targetEl = null;
//don't forget the inheritence
if (source instanceof EPPage) {
targetEl = new EPPage();
targetEl.setTitle(((EPPage) source).getTitle());
targetEl.setDescription(((EPPage) source).getDescription());
} else if(source instanceof EPStructureElement) {
targetEl = new EPStructureElement();
targetEl.setTitle(((EPStructureElement) source).getTitle());
targetEl.setDescription(((EPStructureElement) source).getDescription());
}
return targetEl;
}
/**
*
* @param source
* @param target
* @param update if true, the old existing restrictions will be overwritten
*/
private void copyOrUpdateCollectRestriction(PortfolioStructure source, PortfolioStructure target, boolean update) {
if(source == null || target == null) {
return;
}
List<CollectRestriction> targetRestrictions = target.getCollectRestrictions();
if ((source.getCollectRestrictions() == null || source.getCollectRestrictions().isEmpty()) && (target.getCollectRestrictions() != null && !target.getCollectRestrictions().isEmpty()) && update){
// remove former existing restrictions
targetRestrictions.clear();
return;
}
if (update) {
targetRestrictions.clear();
}
for(CollectRestriction sourceRestriction: source.getCollectRestrictions()) {
CollectRestriction targetRestriction = new CollectRestriction();
targetRestriction.setArtefactType(sourceRestriction.getArtefactType());
targetRestriction.setAmount(sourceRestriction.getAmount());
targetRestriction.setRestriction(sourceRestriction.getRestriction());
targetRestrictions.add(targetRestriction);
}
}
public boolean isTemplateInUse(PortfolioStructureMap template, OLATResourceable targetOres,
String targetSubPath, String targetBusinessPath) {
StringBuilder sb = new StringBuilder();
sb.append("select count(map) from ").append(EPStructuredMap.class.getName()).append(" map")
.append(" where map.structuredMapSource=:template");
if (targetOres != null) {
sb.append(" and map.targetResource.resourceableId=:resourceId")
.append(" and map.targetResource.resourceableTypeName=:resourceType");
}
if (targetSubPath != null) {
sb.append(" and map.targetResource.subPath=:subPath");
}
if (targetBusinessPath != null) {
sb.append(" and map.targetResource.businessPath=:businessPath");
}
DBQuery query = dbInstance.createQuery(sb.toString());
query.setEntity("template", template);
if (targetOres != null) {
query.setLong("resourceId", targetOres.getResourceableId());
query.setString("resourceType", targetOres.getResourceableTypeName());
}
if (targetSubPath != null) {
query.setString("subPath", targetSubPath);
}
if (targetBusinessPath != null) {
query.setString("businessPath", targetBusinessPath);
}
Number count = (Number)query.uniqueResult();
return count.intValue() > 0;
}
public PortfolioStructureMap loadPortfolioStructuredMap(IdentityRef identity, PortfolioStructureMap template,
OLATResourceable targetOres, String targetSubPath, String targetBusinessPath) {
if (template == null) throw new NullPointerException();
if (!(template instanceof EPStructuredMapTemplate)) throw new AssertException("Only template are acceptable");
StringBuilder sb = new StringBuilder();
sb.append("select map from ").append(EPStructuredMap.class.getName()).append(" map")
.append(" left join fetch map.targetResource as targetResource")
.append(" inner join map.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup")
.append(" where map.structuredMapSource=:template");
if (targetOres != null) {
sb.append(" and targetResource.resourceableId=:resourceId")
.append(" and targetResource.resourceableTypeName=:resourceType");
}
if (targetSubPath != null) {
sb.append(" and targetResource.subPath=:subPath");
}
if (targetBusinessPath != null) {
sb.append(" and targetResource.businessPath=:businessPath");
}
sb.append(" and exists (select membership from bgroupmember as membership " )
.append(" where baseGroup=membership.group and membership.identity.key=:identityKey and membership.role='").append(GroupRoles.owner.name()).append("'")
.append(" )");
TypedQuery<PortfolioStructureMap> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), PortfolioStructureMap.class)
.setParameter("template", template)
.setParameter("identityKey", identity.getKey());
if (targetOres != null) {
query.setParameter("resourceId", targetOres.getResourceableId());
query.setParameter("resourceType", targetOres.getResourceableTypeName());
}
if (targetSubPath != null) {
query.setParameter("subPath", targetSubPath);
}
if (targetBusinessPath != null) {
query.setParameter("businessPath", targetBusinessPath);
}
List<PortfolioStructureMap> maps = query.getResultList();
// if not found, it is an empty list
return maps.isEmpty() ? null : maps.get(0);
}
/**
*
* @param identity Mandatory
* @param targetOres Mandatory
* @param targetSubPath Optional
* @param targetBusinessPath Optional
* @return
*/
public List<PortfolioStructureMap> loadPortfolioStructuredMaps(IdentityRef identity,
OLATResourceable targetOres, String targetSubPath, String targetBusinessPath) {
StringBuilder sb = new StringBuilder();
sb.append("select map from ").append(EPStructuredMap.class.getName()).append(" map")
.append(" inner join map.groups as relGroup on relGroup.defaultGroup=true")
.append(" inner join relGroup.group as baseGroup")
.append(" inner join fetch map.targetResource as targetResource")
.append(" where targetResource.resourceableId=:resourceId and targetResource.resourceableTypeName=:resourceType");
if (targetSubPath != null) {
sb.append(" and targetResource.subPath=:subPath");
}
if (targetBusinessPath != null) {
sb.append(" and targetResource.businessPath=:businessPath");
}
sb.append(" and exists (select membership from bgroupmember as membership " )
.append(" where baseGroup=membership.group and membership.identity.key=:identityKey and membership.role='").append(GroupRoles.owner.name()).append("'")
.append(" )");
TypedQuery<PortfolioStructureMap> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), PortfolioStructureMap.class)
.setParameter("identityKey", identity.getKey())
.setParameter("resourceId", targetOres.getResourceableId())
.setParameter("resourceType", targetOres.getResourceableTypeName());
if (targetSubPath != null) {
query.setParameter("subPath", targetSubPath);
}
if (targetBusinessPath != null) {
query.setParameter("businessPath", targetBusinessPath);
}
return query.getResultList();
}
/**
* Load the repository entry of a template with the map key
* @param key The template key
* @return The repository entry
*/
public RepositoryEntry loadPortfolioRepositoryEntryByMapKey(Long key) {
if (key == null) throw new NullPointerException();
StringBuilder sb = new StringBuilder();
sb.append("select repo from ").append(RepositoryEntry.class.getName()).append(" repo")
.append(" where repo.olatResource in (select map.olatResource from ")
.append(EPStructuredMapTemplate.class.getName())
.append(" map where map.key=:key")
.append(")");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setLong("key", key);
@SuppressWarnings("unchecked")
List<RepositoryEntry> entries = query.list();
// if not found, it is an empty list
if (entries.isEmpty()) return null;
return entries.get(0);
}
/**
* @param olatResourceable cannot be null
* @return The structure element or null if not found
*/
public PortfolioStructure loadPortfolioStructure(OLATResourceable olatResourceable) {
if (olatResourceable == null) throw new NullPointerException();
OLATResource resource = resourceManager.findResourceable(olatResourceable);
if (resource == null) return null;
StringBuilder sb = new StringBuilder();
sb.append("select element from ").append(EPStructureElement.class.getName()).append(" element")
.append(" where element.olatResource=:resource");
List<PortfolioStructure> resources = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), PortfolioStructure.class)
.setParameter("resource", resource)
.getResultList();
// if not found, it is an empty list
return resources.isEmpty() ? null : resources.get(0);
}
/**
* @param olatResourceable cannot be null
* @return The structure element or null if not found
*/
public EPMapShort loadMapShortByResourceId(Long resourceableId) {
StringBuilder sb = new StringBuilder();
sb.append("select element from ").append(EPMapShort.class.getName()).append(" element")
.append(" inner join fetch element.olatResource resource")
.append(" where resource.resId=:resourceId and resource.resName in ('EPDefaultMap','EPStructuredMap','EPStructuredMapTemplate')");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setLong("resourceId", resourceableId);
@SuppressWarnings("unchecked")
List<EPMapShort> resources = query.list();
// if not found, it is an empty list
if (resources.isEmpty()) return null;
return resources.get(0);
}
/**
* Load a portfolio structure by its primary key
* @param key cannot be null
* @return The structure element or null if not found
*/
public PortfolioStructure loadPortfolioStructureByKey(Long key) {
if (key == null) throw new NullPointerException();
StringBuilder sb = new StringBuilder();
sb.append("select element from ").append(EPStructureElement.class.getName()).append(" element")
.append(" left join fetch element.olatResource as oRes")
.append(" where element.key=:key");;
List<PortfolioStructure> resources = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), PortfolioStructure.class)
.setParameter("key", key)
.getResultList();
// if not found, it is an empty list
if (resources.isEmpty()) return null;
return resources.get(0);
}
/**
* Reload an object
* @param structure
* @return The reloaded object or null if not found
*/
public PortfolioStructure reloadPortfolioStructure(PortfolioStructure structure) {
if (structure == null) throw new NullPointerException();
try {
return dbInstance.loadObject(EPStructureElement.class, structure.getKey());
} catch (ObjectNotFoundException e) {
return null;
}
}
public OLATResource loadOlatResourceFromStructureElByKey(Long key) {
if (key == null) throw new NullPointerException();
StringBuilder sb = new StringBuilder();
sb.append("select element.olatResource from ").append(EPStructureElement.class.getName()).append(" element")
.append(" where element.key=:key or element.olatResource.resId=:key ");
DBQuery query = dbInstance.createQuery(sb.toString());
query.setLong("key", key);
@SuppressWarnings("unchecked")
List<OLATResource> resources = query.list();
// if not found, it is an empty list
if (resources.isEmpty()) return null;
return resources.get(0);
}
/**
* Create a basic structure element
* @param title
* @param description
* @return The structure element
*/
protected PortfolioStructure createPortfolioStructure(PortfolioStructure root, String title, String description) {
EPStructureElement el = new EPStructureElement();
el.setRoot((EPStructureElement)root);
if(root != null && root.getRootMap() == null && root instanceof PortfolioStructureMap) {
el.setRootMap((PortfolioStructureMap)root);
} else if (root != null) {
el.setRootMap(root.getRootMap());
}
return fillStructureElement(el, title, description);
}
/**
* Create a page element
* @param title
* @param description
* @return The structure element
*/
protected PortfolioStructure createPortfolioPage(PortfolioStructure root, String title, String description) {
EPPage el = new EPPage();
el.setRoot((EPStructureElement)root);
if(root != null && root.getRootMap() == null && root instanceof PortfolioStructureMap) {
el.setRootMap((PortfolioStructureMap)root);
} else if(root != null) {
el.setRootMap(root.getRootMap());
}
return fillStructureElement(el, title, description);
}
protected PortfolioStructureMap createPortfolioStructuredMap(PortfolioStructureMap template,
Identity identity, String title, String description, OLATResourceable targetOres, String targetSubPath, String targetBusinessPath) {
EPStructuredMap el = new EPStructuredMap();
el.setStructuredMapSource((EPStructuredMapTemplate)template);
el.setStructureElSource(template.getKey());
if(template != null) {
copyOrUpdateCollectRestriction(template, el, false);
}
EPTargetResource targetResource = el.getTargetResource();
if(targetOres != null) {
targetResource.setResourceableId(targetOres.getResourceableId());
targetResource.setResourceableTypeName(targetOres.getResourceableTypeName());
}
if(StringHelper.containsNonWhitespace(targetSubPath)) {
targetResource.setSubPath(targetSubPath);
}
if(StringHelper.containsNonWhitespace(targetBusinessPath)) {
targetResource.setBusinessPath(targetBusinessPath);
}
fillStructureElement(el, title, description);
//create security group
EPStructureElementToGroupRelation ownerGroup = createBaseGroup(el, identity);
Set<EPStructureElementToGroupRelation> relations = new HashSet<>();
relations.add(ownerGroup);
el.setGroups(relations);
return el;
}
protected PortfolioStructureMap createPortfolioDefaultMap(Identity identity, String title, String description) {
EPDefaultMap el = new EPDefaultMap();
fillStructureElement(el, title, description);
//create security group
EPStructureElementToGroupRelation ownerGroup = createBaseGroup(el, identity);
Set<EPStructureElementToGroupRelation> relations = new HashSet<>();
relations.add(ownerGroup);
el.setGroups(relations);
return el;
}
protected PortfolioStructureMap createPortfolioDefaultMap(String title, String description) {
EPDefaultMap el = new EPDefaultMap();
fillStructureElement(el, title, description);
return el;
}
private EPStructureElement fillStructureElement(EPStructureElement el, String title, String description) {
el.setTitle(title);
el.setDescription(description);
OLATResource resource = resourceManager.createOLATResourceInstance(el.getClass());
el.setOlatResource(resource);
dbInstance.getCurrentEntityManager().persist(resource);
return el;
}
private EPStructureElement fillStructureElement(EPStructureElement el, String title, String description, OLATResource resource) {
el.setTitle(title);
el.setDescription(description);
el.setOlatResource(resource);
if(resource.getKey() == null) {
dbInstance.getCurrentEntityManager().persist(resource);
}
return el;
}
/**
* Create a map template, create an OLAT resource and a repository entry with a security group
* of type owner to the repository and add the identity has an owner.
* @param identity
* @param title
* @param description
* @return The structure element
*/
public PortfolioStructureMap createPortfolioMapTemplate(Identity identity, String title, String description) {
EPStructuredMapTemplate el = new EPStructuredMapTemplate();
fillStructureElement(el, title, description);
//create a repository entry with default security settings
RepositoryEntry re = createRepositoryEntry(identity, el.getOlatResource(), title);
dbInstance.commit();
Group ownerGroup = repositoryService.getDefaultGroup(re);
EPStructureElementToGroupRelation relation = createBaseRelation(el, ownerGroup);
Set<EPStructureElementToGroupRelation> relations = new HashSet<>();
relations.add(relation);
el.setGroups(relations);
return el;
}
/**
* Import the structure.
* @param root
* @param identity
* @return
*/
public PortfolioStructureMap importPortfolioMapTemplate(PortfolioStructure root, OLATResource resource) {
EPStructuredMapTemplate el = new EPStructuredMapTemplate();
fillStructureElement(el, root.getTitle(), root.getDescription(), resource);
EPStructuredMapTemplate rootTemp = (EPStructuredMapTemplate) root;
rootTemp.setStructureElSource(null);
el.setStyle(((EPStructureElement)root).getStyle());
importEPStructureElementRecursively((EPStructureElement)root, el);
//create an empty group
Group ownerGroup = groupDao.createGroup();
EPStructureElementToGroupRelation relation = createBaseRelation(el, ownerGroup);
Set<EPStructureElementToGroupRelation> relations = new HashSet<>();
relations.add(relation);
el.setGroups(relations);
return el;
}
private void importEPStructureElementRecursively(EPStructureElement sourceEl, EPStructureElement targetEl) {
//clone the links
List<EPStructureToStructureLink> childLinks = sourceEl.getInternalChildren();
for(EPStructureToStructureLink childLink:childLinks) {
EPStructureElement childSourceEl = (EPStructureElement) childLink.getChild();
childSourceEl.setStructureElSource(null); // remove source-info on imports.
copy(childLink, targetEl, false, true, true);
}
savePortfolioStructure(targetEl);
}
/**
* Create an OLAT Resource with the type of a template map.
* @return
*/
public OLATResource createPortfolioMapTemplateResource() {
OLATResource resource = resourceManager.createOLATResourceInstance(EPStructuredMapTemplate.class);
return resource;
}
/**
* Create a template map with the given repsoitory entry and olat resource (in the repository entry).
* The repository entry must already be persisted.
* @param identity
* @param entry
* @return
*/
public PortfolioStructureMap createAndPersistPortfolioMapTemplateFromEntry(Identity identity, RepositoryEntry entry) {
EPStructuredMapTemplate el = (EPStructuredMapTemplate)loadPortfolioStructure(entry.getOlatResource());
if(el == null) {
el = new EPStructuredMapTemplate();
}
el.setTitle(entry.getDisplayname());
el.setDescription(entry.getDescription());
el.setOlatResource(entry.getOlatResource());
//create security group
Group group = repositoryEntyRelationDao.getDefaultGroup(entry);
if(group == null) {
group = groupDao.createGroup();
groupDao.addMembershipTwoWay(group, identity, GroupRoles.owner.name());
}
EPStructureElementToGroupRelation relation = createBaseRelation(el, group);
Set<EPStructureElementToGroupRelation> relations = new HashSet<>();
relations.add(relation);
el.setGroups(relations);
dbInstance.saveObject(el);
return el;
}
/**
* Add an author to the repository entry linked to the map
* @param map
* @param author
*/
public void addAuthor(PortfolioStructureMap map, Identity author) {
if(map instanceof EPStructuredMapTemplate) {
EPStructuredMapTemplate mapImpl = (EPStructuredMapTemplate)map;
RepositoryEntry re = repositoryManager.lookupRepositoryEntry(mapImpl.getOlatResource(), true);
if (!repositoryEntyRelationDao.hasRole(author, re, GroupRoles.owner.name())) {
repositoryEntyRelationDao.addRole(author, re, GroupRoles.owner.name());
}
}
}
/**
* Remove an author to repository entry linked to the map
* @param map
* @param author
*/
public void removeAuthor(PortfolioStructureMap map, Identity author) {
if(map instanceof EPStructuredMapTemplate) {
EPStructuredMapTemplate mapImpl = (EPStructuredMapTemplate)map;
RepositoryEntry re = repositoryManager.lookupRepositoryEntry(mapImpl.getOlatResource(), true);
if (repositoryEntyRelationDao.hasRole(author, re, GroupRoles.owner.name())) {
repositoryEntyRelationDao.removeRole(author, re, GroupRoles.owner.name());
}
}
}
private RepositoryEntry createRepositoryEntry(Identity identity, OLATResource oresable, String title) {
// create a repository entry
RepositoryEntry addedEntry = repositoryService.create(identity, null, "-", title, null, oresable, RepositoryEntry.ACC_OWNERS);
return addedEntry;
}
private EPStructureElementToGroupRelation createBaseGroup(EPStructureElement element, Identity author) {
//create security group
Group ownerGroup = groupDao.createGroup();
EPStructureElementToGroupRelation relation = new EPStructureElementToGroupRelation();
relation.setDefaultGroup(true);
relation.setCreationDate(new Date());
relation.setGroup(ownerGroup);
relation.setStructureElement(element);
groupDao.addMembershipTwoWay(ownerGroup, author, GroupRoles.owner.name());
return relation;
}
private EPStructureElementToGroupRelation createBaseRelation(EPStructureElement element, Group ownerGroup) {
//create security group
EPStructureElementToGroupRelation relation = new EPStructureElementToGroupRelation();
relation.setDefaultGroup(true);
relation.setCreationDate(new Date());
relation.setGroup(ownerGroup);
relation.setStructureElement(element);
return relation;
}
/**
* Add or update a restriction to the collection of artefacts for a given structure element
* @param structure
* @param artefactType
* @param restriction
* @param amount
*/
public void addCollectRestriction(PortfolioStructure structure, String artefactType, String restriction, int amount) {
if(structure == null) throw new NullPointerException("Structure cannot be null");
EPStructureElement structEl = (EPStructureElement)structure;
List<CollectRestriction> restrictions = structEl.getCollectRestrictions();
CollectRestriction cr = new CollectRestriction();
cr.setArtefactType(artefactType);
cr.setRestriction(restriction);
cr.setAmount(amount);
restrictions.add(cr);
}
protected void submitMap(EPStructuredMap map) {
map.setStatus(StructureStatusEnum.CLOSED);
map.setReturnDate(new Date());
dbInstance.updateObject(map);
}
public void savePortfolioStructure(PortfolioStructure portfolioStructure) {
if(portfolioStructure instanceof PersistentObject) {
PersistentObject persistentStructure = (PersistentObject)portfolioStructure;
if(persistentStructure.getKey() == null) {
if(portfolioStructure.getOlatResource().getKey() == null) {
dbInstance.getCurrentEntityManager().persist(portfolioStructure.getOlatResource());
}
dbInstance.getCurrentEntityManager().persist(portfolioStructure);
} else {
dbInstance.updateObject(portfolioStructure);
}
}
}
private static class KeyStructureToStructureLinkComparator implements Comparator<EPStructureToStructureLink>, Serializable {
private static final long serialVersionUID = 366101659547497002L;
public KeyStructureToStructureLinkComparator() {
//
}
@Override
public int compare(EPStructureToStructureLink o1, EPStructureToStructureLink o2) {
if(o1 == null) return -1;
if(o2 == null) return 1;
PortfolioStructure ps1 = o1.getChild();
PortfolioStructure ps2 = o2.getChild();
if(ps1 instanceof EPStructureElement && ps2 instanceof EPStructureElement) {
EPStructureElement eps1 = (EPStructureElement)ps1;
EPStructureElement eps2 = (EPStructureElement)ps2;
Long t1 = eps1.getStructureElSource() == null ? eps1.getKey() : eps1.getStructureElSource();
Long t2 = eps2.getStructureElSource() == null ? eps2.getKey() : eps2.getStructureElSource();
if(t1 == null) return -1;
if(t2 == null) return 1;
return t1.compareTo(t2);
}
return -1;
}
}
protected boolean setReflexionForArtefactToStructureLink(AbstractArtefact artefact, PortfolioStructure structure, String reflexion) {
EPStructureElement structureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)structure);
List<EPStructureToArtefactLink> links = structureEl.getInternalArtefacts();
boolean changed = false;
for (EPStructureToArtefactLink epStructureToArtefactLink : links) {
if (epStructureToArtefactLink.getArtefact().getKey().equals(artefact.getKey())){
epStructureToArtefactLink.setReflexion(reflexion);
if(epStructureToArtefactLink.getKey() == null) {
dbInstance.saveObject(epStructureToArtefactLink);
} else {
dbInstance.updateObject(epStructureToArtefactLink);
}
changed = true;
break;
}
}
//savePortfolioStructure(structure);
return changed;
}
protected String getReflexionForArtefactToStructureLink(AbstractArtefact artefact, PortfolioStructure structure){
if (structure == null) return null;
EPStructureElement structureEl = (EPStructureElement)dbInstance.loadObject((EPStructureElement)structure);
List<EPStructureToArtefactLink> links = structureEl.getInternalArtefacts();
for (EPStructureToArtefactLink epStructureToArtefactLink : links) {
if (epStructureToArtefactLink.getArtefact().getKey().equals(artefact.getKey())){
return epStructureToArtefactLink.getReflexion();
}
}
return null;
}
}