/** * 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.resource.references; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Set; import org.olat.basesecurity.GroupRoles; import org.olat.core.commons.persistence.DB; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.Roles; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.course.CourseFactory; import org.olat.course.CourseModule; import org.olat.course.ICourse; import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntryManagedFlag; import org.olat.repository.RepositoryManager; import org.olat.repository.manager.RepositoryEntryDAO; import org.olat.repository.manager.RepositoryEntryRelationDAO; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceImpl; import org.olat.resource.OLATResourceManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * Initial Date: May 27, 2004 * * @author Mike Stock * * Comment: * */ @Service("referenceManager") public class ReferenceManager { private static final OLog log = Tracing.createLoggerFor(ReferenceManager.class); @Autowired private DB dbInstance; @Autowired private RepositoryManager repositoryManager; @Autowired private RepositoryEntryDAO repositoryEntryDAO; @Autowired private OLATResourceManager olatResourceManager; @Autowired private RepositoryEntryRelationDAO reToGroupDao; /** * Add a new reference. The meaning of source and target is * such as the source references the target. * * @param source * @param target * @param userdata */ public void addReference(OLATResourceable source, OLATResourceable target, String userdata) { OLATResourceImpl sourceImpl = (OLATResourceImpl)olatResourceManager.findResourceable(source); OLATResourceImpl targetImpl = (OLATResourceImpl)olatResourceManager.findResourceable(target); ReferenceImpl ref = new ReferenceImpl(); ref.setSource(sourceImpl); ref.setTarget(targetImpl); ref.setUserdata(userdata); ref.setCreationDate(new Date()); dbInstance.getCurrentEntityManager().persist(ref); } /** * List all references the source holds. * * @param source * @return List of renerences. */ public List<Reference> getReferences(OLATResourceable source) { Long sourceKey = getResourceKey(source); if (sourceKey == null) { return new ArrayList<Reference> (0); } return dbInstance.getCurrentEntityManager() .createNamedQuery("referencesBySourceId", Reference.class) .setParameter("sourceKey", sourceKey) .getResultList(); } /** * List all sources which hold references to the target. * * @param target * @return List of references. */ public List<Reference> getReferencesTo(OLATResourceable target) { Long targetKey = getResourceKey(target); if (targetKey == null) { return new ArrayList<Reference>(0); } return dbInstance.getCurrentEntityManager() .createNamedQuery("referencesByTargetId", Reference.class) .setParameter("targetKey", targetKey) .getResultList(); } public List<RepositoryEntry> getRepositoryReferencesTo(OLATResourceable target) { Long targetKey = getResourceKey(target); StringBuilder sb = new StringBuilder(); sb.append("select v from ").append(RepositoryEntry.class.getName()).append(" as v") .append(" where v.olatResource in (select ref.source from references as ref where ref.target.key=:targetKey)"); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), RepositoryEntry.class) .setParameter("targetKey", targetKey) .getResultList(); } public List<ReferenceInfos> getReferencesInfos(List<RepositoryEntry> res, Identity identity, Roles roles) { if(res == null || res.isEmpty()) return Collections.emptyList(); List<Long> sourceKeys = new ArrayList<>(); for(RepositoryEntry re:res) { sourceKeys.add(re.getOlatResource().getKey()); } StringBuilder sb = new StringBuilder(); sb.append("select ref from references ref") .append(" where ref.target.key in (select orig.target.key from references orig where orig.source.key in (:sourceKeys))"); List<Reference> references = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Reference.class) .setParameter("sourceKeys", sourceKeys) .getResultList(); Set<Long> targetResourceKeys = new HashSet<>(); Set<Long> notOrphansResourceKeys = new HashSet<>(); for(Iterator<Reference> itRef = references.iterator(); itRef.hasNext(); ) { Reference reference = itRef.next(); OLATResource source = reference.getSource(); OLATResource target = reference.getTarget(); targetResourceKeys.add(target.getKey()); if(!sourceKeys.contains(source.getKey())) { notOrphansResourceKeys.add(target.getKey()); } } boolean isOlatAdmin = roles.isOLATAdmin(); List<RepositoryEntry> entries = repositoryEntryDAO.loadByResourceKeys(targetResourceKeys); List<ReferenceInfos> infos = new ArrayList<>(entries.size()); for(RepositoryEntry entry:entries) { Long resourceKey = entry.getOlatResource().getKey(); boolean notOrphan = notOrphansResourceKeys.contains(resourceKey); boolean deleteManaged = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.delete); boolean isInstitutionalResourceManager = !roles.isGuestOnly() && repositoryManager.isInstitutionalRessourceManagerFor(identity, roles, entry); boolean isOwner = isOlatAdmin || reToGroupDao.hasRole(identity, entry, GroupRoles.owner.name()) || isInstitutionalResourceManager; ReferenceInfos refInfos = new ReferenceInfos(entry, !notOrphan, isOwner, deleteManaged); infos.add(refInfos); } return infos; } /** * find the references source -> target -> source * * * @param source * @return */ public List<Reference> getReferencesOfReferences(OLATResource source) { StringBuilder sb = new StringBuilder(); sb.append("select ref from references ref") .append(" where ref.source.key != :sourceKey and ref.target.key in (select orig.target.key from references orig where orig.source.key=:sourceKey)"); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Reference.class) .setParameter("sourceKey", source.getKey()) .getResultList(); } private Long getResourceKey(OLATResourceable resource) { Long sourceKey; if(resource instanceof OLATResource) { sourceKey = ((OLATResource)resource).getKey(); } else { OLATResource sourceImpl = olatResourceManager.findResourceable(resource); if (sourceImpl == null) { sourceKey = null; } else { sourceKey = sourceImpl.getKey(); } } return sourceKey; } /** * Get an HTML summary of existing references or null if no references exist. * @param target * @param locale * @return HTML fragment or null if no references exist. */ public String getReferencesToSummary(OLATResourceable target, Locale locale) { Translator translator = Util.createPackageTranslator(this.getClass(), locale); StringBuilder result = new StringBuilder(100); List<Reference> refs = getReferencesTo(target); if (refs.size() == 0) return null; for (Reference ref:refs) { if(result.length() > 0) result.append(", "); OLATResource source = ref.getSource(); // special treatment for referenced courses: find out the course title if (source.getResourceableTypeName().equals(CourseModule.getCourseTypeName())) { try { ICourse course = CourseFactory.loadCourse(source); result.append(translator.translate("ref.course", new String[] { StringHelper.escapeHtml(course.getCourseTitle()) })); } catch (Exception e) { log.error("", e); result.append(translator.translate("ref.course", new String[] { "<strike>" + source.getKey().toString() + "</strike>" })); } } else { result.append(source.getKey().toString()); } } return result.toString(); } public List<String> getReferencesToSummary(OLATResourceable target) { List<Reference> refs = getReferencesTo(target); List<String> refNames = new ArrayList<>(refs.size()); if (refs.size() > 0) { for (Reference ref:refs) { OLATResource source = ref.getSource(); // special treatment for referenced courses: find out the course title if (source.getResourceableTypeName().equals(CourseModule.getCourseTypeName())) { try { ICourse course = CourseFactory.loadCourse(source); refNames.add(StringHelper.escapeHtml(course.getCourseTitle())); } catch (Exception e) { log.error("", e); refNames.add("<strike>" + source.getKey().toString() + "</strike>"); } } else { refNames.add(source.getKey().toString()); } } } return refNames; } /** * Delete all references of an OLAT-resource as source or target. * @param olatResource an OLAT-Resource */ public int deleteAllReferencesOf(OLATResource olatResource) { String dq = "delete from references as refs where refs.source.key=:resourceKey or refs.target.key=:resourceKey"; return dbInstance.getCurrentEntityManager().createQuery(dq) .setParameter("resourceKey", olatResource.getKey()) .executeUpdate(); } /** * @param ref */ public void delete(Reference ref) { ReferenceImpl reloadedRef = dbInstance.getCurrentEntityManager() .getReference(ReferenceImpl.class, ref.getKey()); dbInstance.getCurrentEntityManager().remove(reloadedRef); } }