ch.puzzle.itc.mobiliar.business.resourcerelation.boundary.RelationEditor.java Source code

Java tutorial

Introduction

Here is the source code for ch.puzzle.itc.mobiliar.business.resourcerelation.boundary.RelationEditor.java

Source

/*
 * AMW - Automated Middleware allows you to manage the configurations of
 * your Java EE applications on an unlimited number of different environments
 * with various versions, including the automated deployment of those apps.
 * Copyright (C) 2013-2016 by Puzzle ITC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package ch.puzzle.itc.mobiliar.business.resourcerelation.boundary;

import java.util.*;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;

import ch.puzzle.itc.mobiliar.business.foreignable.control.ForeignableService;
import ch.puzzle.itc.mobiliar.business.foreignable.entity.ForeignableOwner;
import ch.puzzle.itc.mobiliar.business.foreignable.entity.ForeignableOwnerViolationException;
import ch.puzzle.itc.mobiliar.business.resourcegroup.boundary.ResourceGroupLocator;
import ch.puzzle.itc.mobiliar.business.resourcegroup.boundary.ResourceLocator;
import ch.puzzle.itc.mobiliar.business.resourcegroup.control.ResourceGroupPersistenceService;
import ch.puzzle.itc.mobiliar.business.resourcegroup.control.ResourceRepository;
import ch.puzzle.itc.mobiliar.business.resourcegroup.control.ResourceTypeDomainService;
import ch.puzzle.itc.mobiliar.business.resourcegroup.entity.NamedIdentifiable;
import ch.puzzle.itc.mobiliar.business.resourcegroup.entity.ResourceEntity;
import ch.puzzle.itc.mobiliar.business.resourcegroup.entity.ResourceGroupEntity;
import ch.puzzle.itc.mobiliar.business.resourcegroup.entity.ResourceTypeEntity;
import ch.puzzle.itc.mobiliar.business.resourcerelation.control.ResourceRelationService;
import ch.puzzle.itc.mobiliar.business.resourcerelation.entity.AbstractResourceRelationEntity;
import ch.puzzle.itc.mobiliar.business.resourcerelation.entity.ResourceRelationTypeEntity;
import ch.puzzle.itc.mobiliar.business.utils.ValidationException;
import ch.puzzle.itc.mobiliar.common.exception.ElementAlreadyExistsException;
import ch.puzzle.itc.mobiliar.common.exception.ResourceNotFoundException;
import ch.puzzle.itc.mobiliar.common.exception.ResourceTypeNotFoundException;
import ch.puzzle.itc.mobiliar.common.util.DefaultResourceTypeDefinition;
import com.google.common.base.Enums;
import org.apache.commons.lang.StringUtils;

/**
 * A boundary for relation editing
 * 
 * @author cweber
 */
@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class RelationEditor {

    @Inject
    EntityManager entityManager;

    @Inject
    ResourceRelationService resourceRelationService;

    @Inject
    ResourceRelationBoundary resourceRelationBoundary;

    @Inject
    ResourceTypeDomainService resourceTypeDomainService;

    @Inject
    ResourceRepository resourceRepository;

    @Inject
    ResourceLocator resourceLocator;

    @Inject
    ResourceGroupLocator resourceGroupLocator;

    @Inject
    ForeignableService foreignableService;

    @Inject
    private ResourceGroupPersistenceService resourceGroupService;

    public enum ResourceRelationType {
        CONSUMED, PROVIDED
    }

    /**
     * Load all resourceGroups for the given type
     * 
     * @param typeName
     * @param resourceId
     *             - the resourceGroup for this resource will be excluded
     * @return a list with resourceGroup entities
     */
    public List<? extends NamedIdentifiable> loadResourceGroupsForType(String typeName, Integer resourceId) {
        ResourceEntity resource = resourceRepository.loadWithResourceGroupAndRelatedResourcesForId(resourceId);
        return resourceGroupService.loadGroupsForTypeNameExcludeSelected(typeName,
                Collections.singletonList(resource.getResourceGroup().getId()));
    }

    /**
     * @param masterId
     * @param provided
     * @param relationName
     * @throws ResourceNotFoundException
     * @throws ElementAlreadyExistsException
     */
    public void addRelation(Integer masterId, Integer slaveGroupId, boolean provided, String relationName,
            ForeignableOwner changingOwner) throws ResourceNotFoundException, ElementAlreadyExistsException {
        resourceRelationService.addRelationByGroup(masterId, slaveGroupId, provided, relationName, null,
                changingOwner);
    }

    /**
     *
     * @param masterGroupName
     * @param slaveGroupName
     * @param provided
     * @param relationName
     * @param typeIdentifier
     * @param releaseName
     * @param changingOwner
     * @throws ResourceNotFoundException
     * @throws ElementAlreadyExistsException
     * @throws ValidationException
     */
    public void addResourceRelationForSpecificRelease(String masterGroupName, String slaveGroupName,
            boolean provided, String relationName, String typeIdentifier, String releaseName,
            ForeignableOwner changingOwner)
            throws ResourceNotFoundException, ElementAlreadyExistsException, ValidationException {

        ResourceEntity master = resourceLocator.getResourceByGroupNameAndRelease(masterGroupName, releaseName);
        if (master == null) {
            throw new ResourceNotFoundException(
                    "Resource with name '" + masterGroupName + "' and Release '" + releaseName + "' not found");
        }
        // a Resource shall only be provided by one ResourceGroup
        if (typeIdentifier.toLowerCase().equals("provided")
                && !resourceRelationBoundary.isAddableAsProvidedResourceToResourceGroup(master, slaveGroupName)) {
            throw new ValidationException(
                    "Resource '" + slaveGroupName + "' is already provided by another ResourceGroup");
        }

        ResourceGroupEntity slaveGroup = null;
        try {
            slaveGroup = resourceGroupLocator.getResourceGroupByName(slaveGroupName);
        } catch (RuntimeException e) {
            throw new ResourceNotFoundException("ResourceGroup with name '" + slaveGroupName + "' not found");
        }

        resourceRelationService.addRelationByGroup(master.getId(), slaveGroup.getId(), provided, relationName,
                typeIdentifier, changingOwner);
    }

    public void addResourceTypeRelation(ResourceTypeEntity masterType, Integer slaveResourceTypeId)
            throws ResourceTypeNotFoundException {
        ResourceTypeEntity slaveResourceType = entityManager.find(ResourceTypeEntity.class, slaveResourceTypeId);
        Set<ResourceRelationTypeEntity> relations = slaveResourceType.getResourceRelationTypesB();
        List<String> identifiers = new ArrayList<>();
        for (ResourceRelationTypeEntity relation : relations) {
            if (relation.getResourceTypeA().getId().equals(masterType.getId())) {
                identifiers.add(relation.getRelationIdentifier());
            }
        }
        resourceTypeDomainService.createResourceTypeRelation(masterType.getId(), slaveResourceTypeId,
                resourceTypeDomainService.nextFreeIdentifier(identifiers, slaveResourceType.getName(), null));
    }

    /**
     * Removes a consumed or provided ResourceRelationEntity, identified either by its relation name (aka relation identifier) or by the name of the slave resouce (group)
     *
     * @param relations a Collection containing consumed or provided ResourceRelationEntities (the haystack)
     * @param relationName the relation "name" or the name of the slave resource (group)
     * @return boolean true if it has been removed, false if it could not be found
     * @throws ForeignableOwnerViolationException
     * @throws ResourceNotFoundException
     * @throws ElementAlreadyExistsException
     */
    public boolean removeMatchingRelation(Collection<? extends AbstractResourceRelationEntity> relations,
            String relationName)
            throws ForeignableOwnerViolationException, ResourceNotFoundException, ElementAlreadyExistsException {
        for (AbstractResourceRelationEntity relation : relations) {
            if (isMatchingRelationName(relation, relationName)) {
                removeRelation(ForeignableOwner.getSystemOwner(), relation.getId());
                return true;
            }
        }
        return false;
    }

    protected boolean isMatchingRelationName(AbstractResourceRelationEntity relation, String relationName) {
        if (relation.getIdentifier() != null && relation.getIdentifier().equals(relationName)) {
            return true;
        }
        return relation.getIdentifier() == null && relation.getSlaveResource().getName().equals(relationName);
    }

    /**
     * @param relationId
     * @throws ResourceNotFoundException
     * @throws ElementAlreadyExistsException
     */
    public void removeRelation(ForeignableOwner deletingOwner, Integer relationId)
            throws ResourceNotFoundException, ElementAlreadyExistsException, ForeignableOwnerViolationException {
        AbstractResourceRelationEntity resourceRelationEntity = resourceRelationService
                .getResourceRelation(relationId);

        foreignableService.verifyDeletableByOwner(deletingOwner, resourceRelationEntity);
        resourceRelationService.removeRelation(resourceRelationEntity);
    }

    /**
     * @throws ResourceNotFoundException
     * @throws ElementAlreadyExistsException
     */
    public void removeResourceTypeRelation(Integer resourceTypeRelationId) throws ResourceTypeNotFoundException {
        resourceTypeDomainService.removeResourceTypeRelation(resourceTypeRelationId);
    }

    public Set<ResourceGroupEntity> getApplicationsFromOtherResourcesInGroup(ResourceEntity resource) {

        // ... but we can also add those applications, which are already consumed by another resource of our
        // own resoure group as long as it is not connected to our release...
        Set<ResourceGroupEntity> applicationsFromOtherResourcesInGroup = new HashSet<>();
        resource = entityManager.find(ResourceEntity.class, resource.getId());
        for (ResourceEntity r : resource.getResourceGroup().getResources()) {
            if (!resource.equals(r)) {
                List<ResourceEntity> resourceEntities = r
                        .getConsumedRelatedResourcesByResourceType(DefaultResourceTypeDefinition.APPLICATION);
                if (resourceEntities != null) {
                    for (ResourceEntity r2 : resourceEntities) {
                        applicationsFromOtherResourcesInGroup
                                .add(getResourceGroupWithAllResources(r2.getResourceGroup().getId()));
                    }
                }
            }
        }
        return applicationsFromOtherResourcesInGroup;
    }

    public ResourceGroupEntity getResourceGroupWithAllResources(Integer resourceGroupId) {
        try {
            TypedQuery<ResourceGroupEntity> resGroupQuery = entityManager.createQuery(
                    "select rg from ResourceGroupEntity rg left join fetch rg.resources where rg.id=:id",
                    ResourceGroupEntity.class).setParameter("id", resourceGroupId);
            return resGroupQuery.getSingleResult();
        } catch (NoResultException e) {
            return null;
        }
    }

    public boolean isValidResourceRelationType(String resourceRelationTypeString) {
        if (StringUtils.isEmpty(resourceRelationTypeString)) {
            return false;
        }
        return (Enums.getIfPresent(ResourceRelationType.class, resourceRelationTypeString.toUpperCase())
                .isPresent());
    }

}