/*
* Copyright (c) 2010 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.server.action.execution.profile;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eurekastreams.commons.actions.TaskHandlerExecutionStrategy;
import org.eurekastreams.commons.actions.context.ActionContext;
import org.eurekastreams.commons.actions.context.TaskHandlerActionContext;
import org.eurekastreams.commons.server.UserActionRequest;
import org.eurekastreams.server.action.request.DeleteFromSearchIndexRequest;
import org.eurekastreams.server.domain.Organization;
import org.eurekastreams.server.domain.strategies.OrganizationHierarchyTraverser;
import org.eurekastreams.server.domain.strategies.OrganizationHierarchyTraverserBuilder;
import org.eurekastreams.server.persistence.OrganizationMapper;
import org.eurekastreams.server.persistence.mappers.DomainMapper;
import org.eurekastreams.server.persistence.mappers.FindByIdMapper;
import org.eurekastreams.server.persistence.mappers.cache.CacheKeys;
import org.eurekastreams.server.persistence.mappers.requests.FindByIdRequest;
import org.eurekastreams.server.persistence.mappers.requests.MoveOrganizationPeopleRequest;
import org.eurekastreams.server.persistence.mappers.requests.MoveOrganizationPeopleResponse;
import org.eurekastreams.server.search.modelview.OrganizationModelView;
import edu.emory.mathcs.backport.java.util.Collections;
/**
* Delete an organization. This assumes that the organization has no orgs or groups underneath it. People reporting to
* org will be moved to deleted org's parent org, org will be removed from people's related orgs collection.
*
*/
public class DeleteOrganizationExecution implements TaskHandlerExecutionStrategy<ActionContext>
{
// TODO: Change mapppers over to interfaces when mappers have been refactored.
/**
* Mapper to move People out of organization.
*/
private DomainMapper<MoveOrganizationPeopleRequest, MoveOrganizationPeopleResponse> movePeopleMapper;
/**
* Mapper to get person ids for those that have given org as related org.
*/
private DomainMapper<Long, Set<Long>> relatedOrgPersonIdsMapper;
/**
* Mapper for getting organization DTOs.
*/
private DomainMapper<List<Long>, List<OrganizationModelView>> orgDTOByIdMapper;
/**
* {@link FindByIdMapper}.
*/
private FindByIdMapper<Organization> orgByIdMapper;
/**
* Mapper to delete org and related objects.
*/
private DomainMapper<Long, Boolean> deleteOrgMapper;
/**
* {@link OrganizationMapper}. This is used for updating org stats only.
*/
@SuppressWarnings("deprecation")
private OrganizationMapper organizationMapper;
/**
* The organization hierarchy traverser builder - needed because this class is reused by all threads, we can't share
* OrganizationHierarchyTraversers.
*/
private OrganizationHierarchyTraverserBuilder orgTraverserBuilder;
/**
* Constructor.
*
* @param inMovePeopleMapper
* Mapper to move People out of organization.
* @param inOrgDTOByIdMapper
* Mapper for getting organization DTOs.
* @param inOrgByIdMapper
* {@link FindByIdMapper}.
* @param inDeleteOrgMapper
* Mapper to delete org and related objects.
* @param inRelatedOrgPersonIdsMapper
* Mapper to get person ids for all users that have deleted org as related org.
* @param inOrganizationMapper
* {@link OrganizationMapper}. This is used for updating org stats only.
* @param inOrgTraverserBuilder
* The organization hierarchy traverser builder.
*/
public DeleteOrganizationExecution(
final DomainMapper<MoveOrganizationPeopleRequest, MoveOrganizationPeopleResponse> inMovePeopleMapper,
final DomainMapper<List<Long>, List<OrganizationModelView>> inOrgDTOByIdMapper,
final FindByIdMapper<Organization> inOrgByIdMapper, final DomainMapper<Long, Boolean> inDeleteOrgMapper,
final DomainMapper<Long, Set<Long>> inRelatedOrgPersonIdsMapper,
final OrganizationMapper inOrganizationMapper,
final OrganizationHierarchyTraverserBuilder inOrgTraverserBuilder)
{
movePeopleMapper = inMovePeopleMapper;
orgDTOByIdMapper = inOrgDTOByIdMapper;
orgByIdMapper = inOrgByIdMapper;
deleteOrgMapper = inDeleteOrgMapper;
relatedOrgPersonIdsMapper = inRelatedOrgPersonIdsMapper;
organizationMapper = inOrganizationMapper;
orgTraverserBuilder = inOrgTraverserBuilder;
}
/**
* Delete Organization and directly associated entities.
*
* @param inActionContext
* The action context.
* @return parent org short name;
*/
@SuppressWarnings("deprecation")
@Override
public String execute(final TaskHandlerActionContext<ActionContext> inActionContext)
{
// ***START DB UPDATES****
// get org id to delete.
Long orgId = (Long) inActionContext.getActionContext().getParams();
// get org DTO and parent org entity (entity needed later)..
OrganizationModelView orgDto = orgDTOByIdMapper.execute(Collections.singletonList(orgId)).get(0);
Organization parentOrg = orgByIdMapper.execute(new FindByIdRequest("Organization", orgDto
.getParentOrganizationId()));
// move all people/personal stream activities out of org.
MoveOrganizationPeopleResponse movePeopleResponse = movePeopleMapper.execute(new MoveOrganizationPeopleRequest(
orgDto.getShortName(), parentOrg.getShortName()));
Set<Long> movedPeopleIds = movePeopleResponse.getMovedPersonIds();
Set<Long> movedActivityIds = movePeopleResponse.getMovedActivityIds();
// get ids of people that have org as related org.
Set<Long> relatedOrgPersonIds = relatedOrgPersonIdsMapper.execute(orgId);
// delete the org.
deleteOrgMapper.execute(orgId);
// recalculate org statistics for branch where org removed.
OrganizationHierarchyTraverser orgTraverser = orgTraverserBuilder.getOrganizationHierarchyTraverser();
orgTraverser.traverseHierarchy(parentOrg);
organizationMapper.updateOrganizationStatistics(orgTraverser);
// ***END DB UPDATES****
// queue up async tasks.
// Only reindex all people that were moved out of org.
HashSet<String> cacheKeysToRemove = new HashSet<String>();
for (Long personId : movedPeopleIds)
{
inActionContext.getUserActionRequests().add(new UserActionRequest("indexPersonById", null, personId));
}
// re-cache both moved people and people that had org as related org.
Set<Long> personCacheKeysToModify = new HashSet<Long>(movedPeopleIds);
personCacheKeysToModify.addAll(relatedOrgPersonIds);
for (Long personId : personCacheKeysToModify)
{
cacheKeysToRemove.add(CacheKeys.PERSON_BY_ID + personId);
}
// queue up async tasks to reindex moved activities, add cache key for re-cache.
for (Long activityId : movedActivityIds)
{
inActionContext.getUserActionRequests().add(new UserActionRequest("indexActivityById", null, activityId));
cacheKeysToRemove.add(CacheKeys.ACTIVITY_BY_ID + activityId);
}
// reindex and re-cache all orgs up tree from deleted org
// already have parent orgs from updating stats, so use them again here to avoid more calls to datastores.
Set<Organization> parentOrgs = orgTraverser.getOrganizations();
for (Organization org : parentOrgs)
{
inActionContext.getUserActionRequests().add(
new UserActionRequest("indexOrganizationById", null, org.getId()));
cacheKeysToRemove.add(CacheKeys.ORGANIZATION_BY_ID + org.getId());
cacheKeysToRemove.add(CacheKeys.ORGANIZATION_BY_SHORT_NAME + org.getShortName());
cacheKeysToRemove.add(CacheKeys.ORGANIZATION_RECURSIVE_CHILDREN + org.getId());
}
// remove cache keys for org being deleted.
cacheKeysToRemove.add(CacheKeys.ORGANIZATION_BY_ID + orgId);
cacheKeysToRemove.add(CacheKeys.ORGANIZATION_BY_SHORT_NAME + orgDto.getShortName());
cacheKeysToRemove.add(CacheKeys.ORGANIZATION_RECURSIVE_CHILDREN + orgId);
// remove org from search index
inActionContext.getUserActionRequests().add(
new UserActionRequest("deleteFromSearchIndexAction", null, new DeleteFromSearchIndexRequest(
Organization.class, Arrays.asList(orgId))));
// remove org tree DTO
cacheKeysToRemove.add(CacheKeys.ORGANIZATION_TREE_DTO);
// remove all major components from cache. This is not all inclusive as the peripheral stuff will just
// expire away and there's no real need to keep maintaining this list as cache is modified.
inActionContext.getUserActionRequests().add(
new UserActionRequest("deleteCacheKeysAction", null, cacheKeysToRemove));
return parentOrg.getShortName();
}
}