Package org.olat.catalog

Source Code of org.olat.catalog.CatalogManager

/**
* 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.
* <p>
*/

package org.olat.catalog;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.olat.admin.user.delete.service.UserDeletionManager;
import org.olat.basesecurity.Constants;
import org.olat.basesecurity.Manager;
import org.olat.basesecurity.ManagerFactory;
import org.olat.basesecurity.SecurityGroup;
import org.olat.bookmark.BookmarkManager;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.persistence.DBFactory;
import org.olat.core.commons.persistence.DBQuery;
import org.olat.core.commons.persistence.PersistenceHelper;
import org.olat.core.id.Identity;
import org.olat.core.id.OLATResourceable;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.repository.RepositoryEntry;
import org.olat.resource.OLATResource;
import org.olat.user.UserDataDeletable;

/**
* Description: <br>
* The CatalogManager is responsible for the persistence of CatalogEntries.
* Further it provides access methods to retrieve structures of CatalogEntries
* for a given CatalogEntry, e.g. children, catalog entries which act as roots,
* delete subcategory structure.
* <p>
* Moreover it also has access methods providing all catalog entries referencing
* a given repository entry.
* <p>
* The CatalogManager also provides hooks used by the repository entry manager
* to signal changes on a repository entry which might have changed. Such
* changes can invoke the removal from the catalog, e.g. restricting access,
* deleting a repository entry.
*
* Date: 2005/10/14 13:21:42<br>
* @author Felix Jost
*/
public class CatalogManager implements UserDataDeletable {
  private OLog log = Tracing.createLoggerFor(this.getClass());
  private static CatalogManager catalogManager = new CatalogManager();
  /**
   * Default value for the catalog root <code>CATALOGROOT</code>
   */
  public static final String CATALOGROOT = "CATALOG ROOT";
  /**
   * Resource identifyer for catalog entries
   */
  public static final String CATALOGENTRY = "CatalogEntry";

  private CatalogManager() {
    // singleton
    UserDeletionManager.getInstance().registerDeletableUserData(this);
  }

  /**
   * @return Return singleton instance
   */
  public static CatalogManager getInstance() {
    return catalogManager;
  }

  /**
   * @return transient catalog entry object
   */
  public CatalogEntry createCatalogEntry() {
    return new CatalogEntryImpl();
  }

  /**
   * Children of this CatalogEntry as a list of CatalogEntries
   * @param ce
   * @return List of catalog entries that are childern entries of given entry
   */
  public List<CatalogEntry> getChildrenOf(CatalogEntry ce) {
    String sqlQuery = "select cei from org.olat.catalog.CatalogEntryImpl as cei "
      + " where cei.parent = :parent order by cei.name ";
      DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
      dbQuery.setEntity("parent", ce);
      // cache this query
      dbQuery.setCacheable(true);
      return dbQuery.list();
  }


  /**
   * Returns a list catalog categories
   *
   * @return List of catalog entries of type CatalogEntry.TYPE_NODE
   */
  public List<CatalogEntry> getAllCatalogNodes() {
    String sqlQuery = "select cei from org.olat.catalog.CatalogEntryImpl as cei "
    + " where cei.type= :type ";
    DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
    dbQuery.setInteger("type", CatalogEntry.TYPE_NODE);
    // cache this query
    dbQuery.setCacheable(true);
    return dbQuery.list();
  }

 
  /**
   * Checks if the given catalog entry has any child of the given type. The
   * query will be cached.
   *
   * @param ce
   * @param type CatalogEntry.TYPE_LEAF or CatalogEntry.TYPE_NODE
   * @return true: entry has at least one child of type node
   */
  public boolean hasChildEntries(CatalogEntry ce, int type) {
    String sqlQuery = "select count(cei) from org.olat.catalog.CatalogEntryImpl as cei "
    + " where cei.parent = :parent AND cei.type= :type ";
    DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
    dbQuery.setEntity("parent", ce);
    dbQuery.setInteger("type", type);
    // cache this query
    dbQuery.setCacheable(true);
    List res = dbQuery.list();
    Long cntL = (Long) res.get(0);
    return (cntL.longValue() > 0);
  }

  /**
   * Filters all catalog entries of type leaf that are owned by the given user
   * @param identity
   * @param catalogEntries List of catalog entries to be filtered
   * @return List of catalog entries
   */
  public List filterOwnedLeafs(Identity identity, List catalogEntries) {
    List ownedEntries = new ArrayList();
    Manager securityManager = ManagerFactory.getManager();

    Iterator iter = catalogEntries.iterator();
    while (iter.hasNext()) {
      CatalogEntry cate = (CatalogEntry) iter.next();
      if (cate.getType() == CatalogEntry.TYPE_LEAF) {
        RepositoryEntry repe = cate.getRepositoryEntry();
        SecurityGroup secGroup = repe.getOwnerGroup();
        if (securityManager.isIdentityInSecurityGroup(identity, secGroup)) {
          ownedEntries.add(cate);
        }
      }
    }
    return ownedEntries;
  }

 
  /**
   * Reload the given catalog entry from db or from hibernate second level cache
   * @param catalogEntry
   * @return reloaded catalog entry
   */
  public CatalogEntry loadCatalogEntry(CatalogEntry catalogEntry) {
    return (CatalogEntry) DBFactory.getInstance().loadObject(catalogEntry);
  }

  /**
   * Load the catalog entry by the given ID
   * @param catEntryId
   * @return
   */
  public CatalogEntry loadCatalogEntry(Long catEntryId) {
    return (CatalogEntry) DBFactory.getInstance().loadObject(CatalogEntryImpl.class, catEntryId);
  }
 
  /**
   * persist catalog entry
   *
   * @param ce
   */
  public void saveCatalogEntry(CatalogEntry ce) {
    DBFactory.getInstance().saveObject(ce);
  }

  /**
   * update catalog entry on db
   *
   * @param ce
   */
  public void updateCatalogEntry(CatalogEntry ce) {
    DBFactory.getInstance().updateObject(ce);
  }

  public List entriesWithOwnerFrom(Identity owner,CatalogEntry ce) {
    List retVal = new ArrayList();
    /*
     *
     */
    findEntriesOf(owner, ce, retVal);
    return retVal;
  }
  
  private void findEntriesOf(Identity owner, CatalogEntry root, List entries) {
    /*
     * check if node is owned by identity
     */
    Manager secMgr = ManagerFactory.getManager();
    SecurityGroup owners = root.getOwnerGroup();
    if(owners!=null && secMgr.isIdentityInSecurityGroup(owner, owners)) {
      entries.add(root);
    }
    /*
     * check subtree, by visit children first strategy
     */
    List children = getChildrenOf(root);
    Iterator iter = children.iterator();
    while (iter.hasNext()) {
      CatalogEntry nextCe = (CatalogEntry) iter.next();
      findEntriesOf(owner, nextCe, entries);
    }
  }
  /**
   * delete a catalog entry and a potentially referenced substructure from db.
   * Be aware of how to use this deletion, as all the referenced substructure is
   * deleted.
   *
   * @param ce
   */
  public void deleteCatalogEntry(CatalogEntry ce) {
    log.debug("deleteCatalogEntry start... ce=" + ce);
    Manager securityManager = ManagerFactory.getManager();
    if (ce.getType() == CatalogEntry.TYPE_LEAF) {
      //delete catalog entry, then delete owner group
      SecurityGroup owner = ce.getOwnerGroup();
      DBFactory.getInstance().deleteObject(ce);
      if (owner != null) {
        log.debug("deleteCatalogEntry case_1: delete owner-group=" + owner);
        securityManager.deleteSecurityGroup(owner);
      }
    } else {
      List secGroupsToBeDeleted = new ArrayList();
      //FIXME pb: the transaction must also include the deletion of the security
      // groups. Why not using this method as a recursion and seperating the
      // deletion of the ce and the groups by collecting the groups? IMHO there
      // are not less db queries. This way the code is much less clear, e.g. the method
      // deleteCatalogSubtree does not really delete the subtree, it leaves the
      // security groups behind. I would preferre to have one delete method that
      // deletes its children first by calling itself on the children and then deletes
      // itself ant its security group. The nested transaction that occures is actually
      // not a problem, the DB object can handel this.
      deleteCatalogSubtree(ce,secGroupsToBeDeleted);
      // after deleting all entries, delete all secGroups corresponding
      for (Iterator iter = secGroupsToBeDeleted.iterator(); iter.hasNext();) {
        SecurityGroup grp = (SecurityGroup) iter.next();
        log.debug("deleteCatalogEntry case_2: delete groups of deleteCatalogSubtree grp=" + grp);
        securityManager.deleteSecurityGroup(grp);
      }
    }
    log.debug("deleteCatalogEntry END");
  }

  /**
   * recursively delete the structure starting from the catalog entry.
   *
   * @param ce
   */
  private void deleteCatalogSubtree(CatalogEntry ce, List secGroupsToBeDeleted) {
    DB db = DBFactory.getInstance();

    List children = getChildrenOf(ce);
    Iterator iter = children.iterator();
    while (iter.hasNext()) {
      CatalogEntry nextCe = (CatalogEntry) iter.next();
      deleteCatalogSubtree(nextCe,secGroupsToBeDeleted);
    }
    ce = (CatalogEntry) db.loadObject(ce);
    //mark owner group for deletion.
    SecurityGroup owner = ce.getOwnerGroup();
    if (owner != null) secGroupsToBeDeleted.add(owner);
    // delete user bookmarks
    OLATResourceable ores = createOLATResouceableFor(ce);
    BookmarkManager.getInstance().deleteAllBookmarksFor(ores);
    // delete catalog entry itself
    db.deleteObject(ce);
  }

  /**
   * find all catalog entries referencing the supplied Repository Entry.
   *
   * @param repoEntry
   * @return List of catalog entries
   */
  public List getCatalogEntriesReferencing(RepositoryEntry repoEntry) {
    String sqlQuery = "select cei from " + " org.olat.catalog.CatalogEntryImpl as cei " + " ,org.olat.repository.RepositoryEntry as re "
        + " where cei.repositoryEntry = re AND re.key= :reKey ";
    DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
    dbQuery.setCacheable(true);
    dbQuery.setLong("reKey", repoEntry.getKey().longValue());
    List resSet = dbQuery.list();
    return resSet;
  }

  /**
   * find all catalog categorie that the given repository entry is a child of
   *
   * @param repoEntry
   * @return List of catalog entries
   */
  public List getCatalogCategoriesFor(RepositoryEntry repoEntry) {
    String sqlQuery = "select distinct parent from org.olat.catalog.CatalogEntryImpl as parent "
      + ", org.olat.catalog.CatalogEntryImpl as cei "
      + ", org.olat.repository.RepositoryEntry as re "
      + " where cei.repositoryEntry = re "
      + " and re.key= :reKey "
      + " and cei.parent = parent ";
    DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
    dbQuery.setCacheable(true);
    dbQuery.setLong("reKey", repoEntry.getKey().longValue());
    List resSet = dbQuery.list();
    return resSet;
  }

  /**
   * find catalog entries by supplied name
   *
   * @param name
   * @return List of catalog entries
   */
  public List getCatalogEntriesByName(String name) {
    String sqlQuery = "select cei from org.olat.catalog.CatalogEntryImpl as cei where cei.name = :name";
    DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
    dbQuery.setString("name",name);
    dbQuery.setCacheable(true);
    return dbQuery.list();
   
  }

  /**
   * Find catalog entries for certain identity
   *
   * @param name
   * @return List of catalog entries
   */
  public List getCatalogEntriesOwnedBy(Identity identity) {
    String sqlQuery = "select cei from org.olat.catalog.CatalogEntryImpl as cei inner join fetch cei.ownerGroup, " +
      " org.olat.basesecurity.SecurityGroupMembershipImpl as sgmsi" +
      " where " +
      " cei.ownerGroup = sgmsi.securityGroup and" +
      " sgmsi.identity = :identity";
    DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
    dbQuery.setEntity("identity", identity);
    dbQuery.setCacheable(true);
    return dbQuery.list();
   
  }

  /**
   * add a catalog entry to the specified parent
   *
   * @param parent
   * @param newEntry
   */
  public void addCatalogEntry(CatalogEntry parent, CatalogEntry newEntry) {
    log.debug("addCatalogEntry parent=" + parent);
    newEntry.setParent(parent);
    log.debug("addCatalogEntry newEntry=" + newEntry);
    log.debug("addCatalogEntry newEntry.getOwnerGroup()=" + newEntry.getOwnerGroup());
    saveCatalogEntry(newEntry);
  }

  /**
   * Find all CatalogEntries which can act as catalog roots. Frankly speaking
   * only one is found up to now, but for later stages one can think of getting
   * more such roots. An empty list indicates an error.
   *
   * @return List of catalog entries
   */
  public List getRootCatalogEntries() {
    String sqlQuery = "select cei from org.olat.catalog.CatalogEntryImpl as cei where cei.parent is null";
    DBQuery dbQuery = DBFactory.getInstance().createQuery(sqlQuery);
    dbQuery.setCacheable(true);
    return dbQuery.list();
  }

  /**
   * init called on module start-up
   */
  public void init() {
    List roots = getRootCatalogEntries();
    if (roots.isEmpty()) { // not initialized yet
      Manager secMgr = ManagerFactory.getManager();
      /*
       * copy a snapshot of olatAdmins into catalogAdmins do not put
       * secMgr.findSecurityGroupByName(Constants.GROUP_ADMIN) directly into a
       * CatalogEntry!!
       */
      SecurityGroup olatAdmins = secMgr.findSecurityGroupByName(Constants.GROUP_ADMIN);
      List olatAdminIdents = secMgr.getIdentitiesOfSecurityGroup(olatAdmins);
      SecurityGroup catalogAdmins = secMgr.createAndPersistSecurityGroup();
      for (int i = 0; i < olatAdminIdents.size(); i++) {
        secMgr.addIdentityToSecurityGroup((Identity) olatAdminIdents.get(i), catalogAdmins);
      }
      /*
       * start with something called CATALOGROOT, you can rename it to whatever
       * name you like later as OLATAdmin
       */
      // parent == null -> no parent -> I am a root node.
      saveCatEntry(CATALOGROOT, null, CatalogEntry.TYPE_NODE, catalogAdmins, null, null);
      DBFactory.getInstance(false).intermediateCommit();
    }
  }

  private CatalogEntry saveCatEntry(String name, String desc, int type, SecurityGroup ownerGroup, RepositoryEntry repoEntry,
      CatalogEntry parent) {
    CatalogEntry ce = createCatalogEntry();
    ce.setName(name);
    ce.setDescription(desc);
    ce.setOwnerGroup(ownerGroup);
    ce.setRepositoryEntry(repoEntry);
    ce.setParent(parent);
    ce.setType(type);
    saveCatalogEntry(ce);
    return ce;
  }

  /**
   * Move the given catalog entry to the new parent
   * @param toBeMovedEntry
   * @param newParentEntry
   * return true: success; false: failure
   */
  public boolean moveCatalogEntry(CatalogEntry toBeMovedEntry, CatalogEntry newParentEntry) {
    CatalogManager cm = CatalogManager.getInstance();
    // reload current item to prevent stale object modification
    toBeMovedEntry = cm.loadCatalogEntry(toBeMovedEntry);
    newParentEntry = cm.loadCatalogEntry(newParentEntry);   
    // check that the new parent is not a leaf
    if (newParentEntry.getType() == CatalogEntry.TYPE_LEAF) return false;
    // check that the new parent is not a child of the to be moved entry
    CatalogEntry tempEntry = newParentEntry;
    while (tempEntry != null) {
      if (tempEntry.getKey().equals(toBeMovedEntry.getKey())) {
        // ups, the new parent is within the to be moved entry - abort
        return false;
      }
      tempEntry = tempEntry.getParent();
    }
    // set new parent and save
    toBeMovedEntry.setParent(newParentEntry);
    cm.updateCatalogEntry(toBeMovedEntry);
    return true;
  }


  /**
   * @param repositoryEntry
   */
  public void resourceableDeleted(RepositoryEntry repositoryEntry) {
    // if a repository entry gets deleted, the referencing Catalog Entries gets
    // retired to
    log.debug("sourceableDeleted start... repositoryEntry=" + repositoryEntry);
    List references = getCatalogEntriesReferencing(repositoryEntry);
    if (references != null && !references.isEmpty()) {
      for (int i = 0; i < references.size(); i++) {
        deleteCatalogEntry((CatalogEntry) references.get(i));
      }
    }
  }

  /**
   * Remove identity as owner of catalog-entry.
   * If there is no other owner, the olat-administrator (define in olat_config.xml) will be added as owner.
   * 
   * @see org.olat.user.UserDataDeletable#deleteUserData(org.olat.core.id.Identity)
   */
  public void deleteUserData(Identity identity, String newDeletedUserName) {
    // Remove as owner
    List catalogEntries = getCatalogEntriesOwnedBy(identity);
    for (Iterator iter = catalogEntries.iterator(); iter.hasNext();) {
      CatalogEntry catalogEntry = (CatalogEntry) iter.next();
     
      ManagerFactory.getManager().removeIdentityFromSecurityGroup(identity, catalogEntry.getOwnerGroup());
      if (ManagerFactory.getManager().countIdentitiesOfSecurityGroup(catalogEntry.getOwnerGroup()) == 0 ) {
        // This group has no owner anymore => add OLAT-Admin as owner
        ManagerFactory.getManager().addIdentityToSecurityGroup(UserDeletionManager.getInstance().getAdminIdentity(), catalogEntry.getOwnerGroup());
        Tracing.logInfo("Delete user-data, add Administrator-identity as owner of catalogEntry=" + catalogEntry.getName(), this.getClass());
      }
    }
    Tracing.logDebug("All owner entries in catalog deleted for identity=" + identity, this.getClass());
  }

  /**
   * checks if the given catalog entry is within one of the given catalog
   * categories
   *
   * @param toBeCheckedEntry
   * @param entriesList
   * @return
   */
  public boolean isEntryWithinCategory(CatalogEntry toBeCheckedEntry, List<CatalogEntry> entriesList) {
    CatalogEntry tempEntry = toBeCheckedEntry;
    while (tempEntry != null) {           
      if (PersistenceHelper.listContainsObjectByKey(entriesList, tempEntry)) {
        return true;
      }
      tempEntry = tempEntry.getParent();
    }
    return false;
  }

  /**
   * Create a volatile OLATResourceable for a given catalog entry that can be
   * used to create a bookmark to this catalog entry
   *
   * @param currentCatalogEntry
   * @return
   */
  public OLATResourceable createOLATResouceableFor(final CatalogEntry currentCatalogEntry) {
    if (currentCatalogEntry == null) return null;
    return new OLATResourceable() {
      public Long getResourceableId() {
        return new Long(currentCatalogEntry.getKey());
      }

      public String getResourceableTypeName() {
        return CATALOGENTRY;
      }
    };
  }

}
TOP

Related Classes of org.olat.catalog.CatalogManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.