@Override
  public void addCollection(Context context, Community community, Collection collection)
      throws SQLException, AuthorizeException {
    // Check authorisation
    authorizeService.authorizeAction(context, community, Constants.ADD);

    log.info(
        LogManager.getHeader(
            context,
            "add_collection",
            "community_id=" + community.getID() + ",collection_id=" + collection.getID()));

    if (!community.getCollections().contains(collection)) {
      community.addCollection(collection);
      collection.addCommunity(community);
    }
    context.addEvent(
        new Event(
            Event.ADD,
            Constants.COMMUNITY,
            community.getID(),
            Constants.COLLECTION,
            collection.getID(),
            community.getHandle(),
            getIdentifiers(context, community)));
  }
  @Override
  public void removeCollection(Context context, Community community, Collection collection)
      throws SQLException, AuthorizeException, IOException {
    // Check authorisation
    authorizeService.authorizeAction(context, community, Constants.REMOVE);

    community.removeCollection(collection);
    ArrayList<String> removedIdentifiers = collectionService.getIdentifiers(context, collection);
    String removedHandle = collection.getHandle();
    UUID removedId = collection.getID();

    collection.removeCommunity(community);
    if (CollectionUtils.isEmpty(collection.getCommunities())) {
      collectionService.delete(context, collection);
    }

    log.info(
        LogManager.getHeader(
            context,
            "remove_collection",
            "community_id=" + community.getID() + ",collection_id=" + collection.getID()));

    // Remove any mappings
    context.addEvent(
        new Event(
            Event.REMOVE,
            Constants.COMMUNITY,
            community.getID(),
            Constants.COLLECTION,
            removedId,
            removedHandle,
            removedIdentifiers));
  }
  /** Internal method to process subcommunities recursively */
  protected void addCollectionList(Community community, List<Collection> collectionList)
      throws SQLException {
    for (Community subcommunity : community.getSubcommunities()) {
      addCollectionList(subcommunity, collectionList);
    }

    for (Collection collection : community.getCollections()) {
      collectionList.add(collection);
    }
  }
  @Override
  public void update(Context context, Community community) throws SQLException, AuthorizeException {
    // Check authorisation
    canEdit(context, community);

    log.info(
        LogManager.getHeader(context, "update_community", "community_id=" + community.getID()));

    communityDAO.save(context, community);
    if (community.isModified()) {
      context.addEvent(
          new Event(
              Event.MODIFY,
              Constants.COMMUNITY,
              community.getID(),
              null,
              getIdentifiers(context, community)));
      community.setModified();
    }
    if (community.isMetadataModified()) {
      context.addEvent(
          new Event(
              Event.MODIFY_METADATA,
              Constants.COMMUNITY,
              community.getID(),
              community.getDetails(),
              getIdentifiers(context, community)));
      community.clearModified();
    }
    community.clearDetails();
  }
  @Override
  public void removeSubcommunity(
      Context context, Community parentCommunity, Community childCommunity)
      throws SQLException, AuthorizeException, IOException {
    // Check authorisation
    authorizeService.authorizeAction(context, parentCommunity, Constants.REMOVE);

    ArrayList<String> removedIdentifiers = getIdentifiers(context, childCommunity);
    String removedHandle = childCommunity.getHandle();
    UUID removedId = childCommunity.getID();

    parentCommunity.removeSubCommunity(childCommunity);
    childCommunity.getParentCommunities().remove(parentCommunity);
    if (CollectionUtils.isEmpty(childCommunity.getParentCommunities())) {
      rawDelete(context, childCommunity);
    }
    log.info(
        LogManager.getHeader(
            context,
            "remove_subcommunity",
            "parent_comm_id="
                + parentCommunity.getID()
                + ",child_comm_id="
                + childCommunity.getID()));

    context.addEvent(
        new Event(
            Event.REMOVE,
            Constants.COMMUNITY,
            parentCommunity.getID(),
            Constants.COMMUNITY,
            removedId,
            removedHandle,
            removedIdentifiers));
  }
  @Override
  public void addSubcommunity(Context context, Community parentCommunity, Community childCommunity)
      throws SQLException, AuthorizeException {
    // Check authorisation
    authorizeService.authorizeAction(context, parentCommunity, Constants.ADD);

    log.info(
        LogManager.getHeader(
            context,
            "add_subcommunity",
            "parent_comm_id="
                + parentCommunity.getID()
                + ",child_comm_id="
                + childCommunity.getID()));

    if (!parentCommunity.getSubcommunities().contains(childCommunity)) {
      parentCommunity.addSubCommunity(childCommunity);
      childCommunity.addParentCommunity(parentCommunity);
    }
    context.addEvent(
        new Event(
            Event.ADD,
            Constants.COMMUNITY,
            parentCommunity.getID(),
            Constants.COMMUNITY,
            childCommunity.getID(),
            parentCommunity.getHandle(),
            getIdentifiers(context, parentCommunity)));
  }
  @Override
  public List<Collection> getAllCollections(Context context, Community community)
      throws SQLException {
    List<Collection> collectionList = new ArrayList<Collection>();
    List<Community> subCommunities = community.getSubcommunities();
    for (Community subCommunity : subCommunities) {
      addCollectionList(subCommunity, collectionList);
    }

    List<Collection> collections = community.getCollections();
    for (Collection collection : collections) {
      collectionList.add(collection);
    }
    return collectionList;
  }
  @Override
  public void removeAdministrators(Context context, Community community)
      throws SQLException, AuthorizeException {
    // Check authorisation - Must be an Admin of the parent community (or system admin) to delete
    // Admin group
    AuthorizeUtil.authorizeRemoveAdminGroup(context, community);

    // just return if there is no administrative group.
    if (community.getAdministrators() == null) {
      return;
    }

    // Remove the link to the community table.
    community.setAdmins(null);
  }
 @Override
 public int countItems(Context context, Community community) throws SQLException {
   int total = 0;
   // add collection counts
   List<Collection> cols = community.getCollections();
   for (Collection col : cols) {
     total += itemService.countItems(context, col);
   }
   // add sub-community counts
   List<Community> comms = community.getSubcommunities();
   for (int j = 0; j < comms.size(); j++) {
     total += countItems(context, comms.get(j));
   }
   return total;
 }
  @Override
  public void setMetadata(Context context, Community community, String field, String value)
      throws MissingResourceException, SQLException {
    if ((field.trim()).equals("name") && (value == null || value.trim().equals(""))) {
      try {
        value = I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled");
      } catch (MissingResourceException e) {
        value = "Untitled";
      }
    }

    String[] MDValue = getMDValueByLegacyField(field);

    /*
     * Set metadata field to null if null
     * and trim strings to eliminate excess
     * whitespace.
     */
    if (value == null) {
      clearMetadata(context, community, MDValue[0], MDValue[1], MDValue[2], Item.ANY);
    } else {
      setMetadataSingleValue(context, community, MDValue[0], MDValue[1], MDValue[2], null, value);
    }
    community.addDetails(field);
  }
  @Override
  public void delete(Context context, Community community)
      throws SQLException, AuthorizeException, IOException {
    // Check authorisation
    // FIXME: If this was a subcommunity, it is first removed from it's
    // parent.
    // This means the parentCommunity == null
    // But since this is also the case for top-level communities, we would
    // give everyone rights to remove the top-level communities.
    // The same problem occurs in removing the logo
    if (!authorizeService.authorizeActionBoolean(
        context, getParentObject(context, community), Constants.REMOVE)) {
      authorizeService.authorizeAction(context, community, Constants.DELETE);
    }
    ArrayList<String> removedIdentifiers = getIdentifiers(context, community);
    String removedHandle = community.getHandle();
    UUID removedId = community.getID();

    // If not a top-level community, have parent remove me; this
    // will call rawDelete() before removing the linkage
    Community parent = (Community) getParentObject(context, community);

    if (parent != null) {
      // remove the subcommunities first
      Iterator<Community> subcommunities = community.getSubcommunities().iterator();
      while (subcommunities.hasNext()) {
        Community subCommunity = subcommunities.next();
        subcommunities.remove();
        delete(context, subCommunity);
      }
      // now let the parent remove the community
      removeSubcommunity(context, parent, community);

      return;
    }

    rawDelete(context, community);
    context.addEvent(
        new Event(
            Event.REMOVE,
            Constants.SITE,
            siteService.findSite(context).getID(),
            Constants.COMMUNITY,
            removedId,
            removedHandle,
            removedIdentifiers));
  }
 @Override
 public DSpaceObject getParentObject(Context context, Community community) throws SQLException {
   List<Community> parentCommunities = community.getParentCommunities();
   if (CollectionUtils.isNotEmpty(parentCommunities)) {
     return parentCommunities.iterator().next();
   } else {
     return null;
   }
 }
 @Override
 public void updateLastModified(Context context, Community community) {
   // Also fire a modified event since the community HAS been modified
   context.addEvent(
       new Event(
           Event.MODIFY,
           Constants.COMMUNITY,
           community.getID(),
           null,
           getIdentifiers(context, community)));
 }
  @Override
  public Group createAdministrators(Context context, Community community)
      throws SQLException, AuthorizeException {
    // Check authorisation - Must be an Admin to create more Admins
    AuthorizeUtil.authorizeManageAdminGroup(context, community);

    Group admins = community.getAdministrators();
    if (admins == null) {
      // turn off authorization so that Community Admins can create Sub-Community Admins
      context.turnOffAuthorisationSystem();
      admins = groupService.create(context);
      context.restoreAuthSystemState();

      admins.setName(context, "COMMUNITY_" + community.getID() + "_ADMIN");
      groupService.update(context, admins);
    }

    authorizeService.addPolicy(context, community, Constants.ADMIN, admins);

    // register this as the admin group
    community.setAdmins(admins);
    return admins;
  }
  /**
   * Internal method to remove the community and all its children from the database, and perform any
   * pre/post-cleanup
   *
   * @throws SQLException
   * @throws AuthorizeException
   * @throws IOException
   */
  protected void rawDelete(Context context, Community community)
      throws SQLException, AuthorizeException, IOException {
    log.info(
        LogManager.getHeader(context, "delete_community", "community_id=" + community.getID()));

    context.addEvent(
        new Event(
            Event.DELETE,
            Constants.COMMUNITY,
            community.getID(),
            community.getHandle(),
            getIdentifiers(context, community)));

    // Remove collections
    Iterator<Collection> collections = community.getCollections().iterator();

    while (collections.hasNext()) {
      Collection collection = collections.next();
      collections.remove();
      removeCollection(context, community, collection);
    }
    // delete subcommunities
    Iterator<Community> subCommunities = community.getSubcommunities().iterator();

    while (subCommunities.hasNext()) {
      Community subComm = subCommunities.next();
      subCommunities.remove();
      delete(context, subComm);
    }

    // Remove the logo
    setLogo(context, community, null);

    // Remove all authorization policies
    authorizeService.removeAllPolicies(context, community);

    // Remove any Handle
    handleService.unbindHandle(context, community);

    deleteMetadata(context, community);

    Group g = community.getAdministrators();

    // Delete community row
    communityDAO.delete(context, community);

    // Remove administrators group - must happen after deleting community

    if (g != null) {
      groupService.delete(context, g);
    }
  }
  @Override
  public Bitstream setLogo(Context context, Community community, InputStream is)
      throws AuthorizeException, IOException, SQLException {
    // Check authorisation
    // authorized to remove the logo when DELETE rights
    // authorized when canEdit
    if (!((is == null)
        && authorizeService.authorizeActionBoolean(context, community, Constants.DELETE))) {
      canEdit(context, community);
    }

    // First, delete any existing logo
    Bitstream oldLogo = community.getLogo();
    if (oldLogo != null) {
      log.info(LogManager.getHeader(context, "remove_logo", "community_id=" + community.getID()));
      community.setLogo(null);
      bitstreamService.delete(context, oldLogo);
    }

    if (is != null) {
      Bitstream newLogo = bitstreamService.create(context, is);
      community.setLogo(newLogo);

      // now create policy for logo bitstream
      // to match our READ policy
      List<ResourcePolicy> policies =
          authorizeService.getPoliciesActionFilter(context, community, Constants.READ);
      authorizeService.addPolicies(context, policies, newLogo);

      log.info(
          LogManager.getHeader(
              context,
              "set_logo",
              "community_id=" + community.getID() + "logo_bitstream_id=" + newLogo.getID()));
    }

    return community.getLogo();
  }
  @Override
  public Community create(Community parent, Context context, String handle)
      throws SQLException, AuthorizeException {
    if (!(authorizeService.isAdmin(context)
        || (parent != null
            && authorizeService.authorizeActionBoolean(context, parent, Constants.ADD)))) {
      throw new AuthorizeException("Only administrators can create communities");
    }

    Community newCommunity = communityDAO.create(context, new Community());

    try {
      if (handle == null) {
        handleService.createHandle(context, newCommunity);
      } else {
        handleService.createHandle(context, newCommunity, handle);
      }
    } catch (IllegalStateException ie) {
      // If an IllegalStateException is thrown, then an existing object is already using this handle
      throw ie;
    }

    if (parent != null) {
      parent.addSubCommunity(newCommunity);
      newCommunity.addParentCommunity(parent);
    }

    // create the default authorization policy for communities
    // of 'anonymous' READ
    Group anonymousGroup = groupService.findByName(context, Group.ANONYMOUS);

    authorizeService.createResourcePolicy(
        context, newCommunity, anonymousGroup, null, Constants.READ, null);

    communityDAO.save(context, newCommunity);

    context.addEvent(
        new Event(
            Event.CREATE,
            Constants.COMMUNITY,
            newCommunity.getID(),
            newCommunity.getHandle(),
            getIdentifiers(context, newCommunity)));

    // if creating a top-level Community, simulate an ADD event at the Site.
    if (parent == null) {
      context.addEvent(
          new Event(
              Event.ADD,
              Constants.SITE,
              siteService.findSite(context).getID(),
              Constants.COMMUNITY,
              newCommunity.getID(),
              newCommunity.getHandle(),
              getIdentifiers(context, newCommunity)));
    }

    log.info(
        LogManager.getHeader(context, "create_community", "community_id=" + newCommunity.getID())
            + ",handle="
            + newCommunity.getHandle());

    return newCommunity;
  }