/* * RHQ Management Platform * Copyright (C) 2005-2013 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 2 of the License. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package org.rhq.enterprise.server.resource; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.ejb.EJB; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.remoting.CannotConnectException; import org.rhq.core.clientapi.agent.inventory.CreateResourceRequest; import org.rhq.core.clientapi.agent.inventory.CreateResourceResponse; import org.rhq.core.clientapi.agent.inventory.DeleteResourceRequest; import org.rhq.core.clientapi.agent.inventory.DeleteResourceResponse; import org.rhq.core.clientapi.agent.inventory.ResourceFactoryAgentService; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.configuration.PropertySimple; import org.rhq.core.domain.content.InstalledPackage; import org.rhq.core.domain.content.PackageType; import org.rhq.core.domain.content.PackageVersion; import org.rhq.core.domain.content.transfer.ResourcePackageDetails; import org.rhq.core.domain.criteria.ResourceCriteria; import org.rhq.core.domain.resource.Agent; import org.rhq.core.domain.resource.CannotConnectToAgentException; import org.rhq.core.domain.resource.CreateResourceHistory; import org.rhq.core.domain.resource.CreateResourceStatus; import org.rhq.core.domain.resource.DeleteResourceHistory; import org.rhq.core.domain.resource.DeleteResourceStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCreationDataType; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.server.PersistenceUtility; import org.rhq.core.domain.util.PageControl; import org.rhq.core.domain.util.PageList; import org.rhq.core.domain.util.PageOrdering; import org.rhq.core.util.exception.ThrowableUtil; import org.rhq.enterprise.server.RHQConstants; import org.rhq.enterprise.server.agentclient.AgentClient; import org.rhq.enterprise.server.auth.SubjectManagerLocal; import org.rhq.enterprise.server.authz.AuthorizationManagerLocal; import org.rhq.enterprise.server.authz.PermissionException; import org.rhq.enterprise.server.content.ContentManagerHelper; import org.rhq.enterprise.server.content.ContentManagerLocal; import org.rhq.enterprise.server.core.AgentManagerLocal; /** * Bean to handle interaction with the resource factory subsystem of the plugin container. !! Warning, the factory * interface is there to remove managed things from disk. Use caution when using this and don't confuse it with removing * something from the system inventory. !! * * @author Jason Dobies */ @Stateless public class ResourceFactoryManagerBean implements ResourceFactoryManagerLocal, ResourceFactoryManagerRemote { private static final Log LOG = LogFactory.getLog(ResourceFactoryManagerBean.class); // Constants -------------------------------------------- /** * Amount of time a request may be outstanding against an agent before it is marked as timed out. */ private static final int REQUEST_TIMEOUT = 1000 * 60 * 60; // Attributes -------------------------------------------- @PersistenceContext(unitName = RHQConstants.PERSISTENCE_UNIT_NAME) private EntityManager entityManager; @EJB private AgentManagerLocal agentManager; @EJB private AuthorizationManagerLocal authorizationManager; @EJB private SubjectManagerLocal subjectManager; @EJB private ResourceFactoryManagerLocal resourceFactoryManager; @EJB private ResourceManagerLocal resourceManager; @EJB private ContentManagerLocal contentManager; // ResourceFactoryManagerLocal Implementation -------------------------------------------- @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void completeCreateResource(CreateResourceResponse response) { if (LOG.isDebugEnabled()) { LOG.debug("Received call to complete create resource: " + response); } // Load the persisted history entry CreateResourceHistory history = entityManager.find(CreateResourceHistory.class, response.getRequestId()); // There is some inconsistency if we're completing a request that was not in the database if (history == null) { LOG.error("Attempting to complete a request that was not found in the database: " + response.getRequestId()); return; } // Update the history entry history.setNewResourceKey(response.getResourceKey()); history.setErrorMessage(response.getErrorMessage()); history.setStatus(response.getStatus()); // The configuration may now have error messages in it, so merge with the persisted one if (response.getResourceConfiguration() != null) { entityManager.merge(response.getResourceConfiguration()); } } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public void completeDeleteResourceRequest(DeleteResourceResponse response) { if (LOG.isDebugEnabled()) { LOG.debug("Received call to complete delete resource: " + response); } // Load the persisted history entry DeleteResourceHistory history = entityManager.find(DeleteResourceHistory.class, response.getRequestId()); // There is some inconsistency if we're completing a request that was not in the database if (history == null) { LOG.error("Attempting to complete a request that was not found in the database: " + response.getRequestId()); return; } // Update the history entry history.setErrorMessage(response.getErrorMessage()); history.setStatus(response.getStatus()); // If successful mark resource as deleted and uninventory children if (response.getStatus() == DeleteResourceStatus.SUCCESS) { resourceManager.uninventoryResourceInNewTransaction(response.getResourceId()); } } @SuppressWarnings("unchecked") public void checkForTimedOutRequests() { try { Query query; // Create Requests query = entityManager.createNamedQuery(CreateResourceHistory.QUERY_FIND_WITH_STATUS); query.setParameter("status", CreateResourceStatus.IN_PROGRESS); List<CreateResourceHistory> createHistories = query.getResultList(); if (createHistories == null) { return; } for (CreateResourceHistory request : createHistories) { long duration = request.getDuration(); // If the duration exceeds the timeout threshold, mark it as timed out if (duration > REQUEST_TIMEOUT) { if (LOG.isDebugEnabled()) { LOG.debug("Timing out request after duration: " + duration + " Request: " + request); } request.setErrorMessage("Request with duration " + duration + " exceeded the timeout threshold of " + REQUEST_TIMEOUT); request.setStatus(CreateResourceStatus.TIMED_OUT); } } // Delete Requests query = entityManager.createNamedQuery(CreateResourceHistory.QUERY_FIND_WITH_STATUS); query.setParameter("status", CreateResourceStatus.IN_PROGRESS); List<DeleteResourceHistory> deleteHistories = query.getResultList(); if (deleteHistories == null) { return; } for (DeleteResourceHistory request : deleteHistories) { long duration = request.getDuration(); // If the duration exceeds the timeout threshold, mark it as timed out if (duration > REQUEST_TIMEOUT) { if (LOG.isDebugEnabled()) { LOG.debug("Timing out request after duration: " + duration + " Request: " + request); } request.setErrorMessage("Request with duration " + duration + " exceeded the timeout threshold of " + REQUEST_TIMEOUT); request.setStatus(DeleteResourceStatus.TIMED_OUT); } } } catch (Throwable e) { LOG.error("Error while processing timed out requests", e); } } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public CreateResourceHistory persistCreateHistory(Subject user, int parentResourceId, int resourceTypeId, String createResourceName, Configuration configuration) { // Load relationships Resource parentResource = entityManager.getReference(Resource.class, parentResourceId); ResourceType resourceType = entityManager.getReference(ResourceType.class, resourceTypeId); // CreateResourceHistory.configuration is one-to-one, so make sure to clone the config, zeroing out all id's. Configuration configurationClone = (configuration != null) ? configuration.deepCopy(false) : null; // Persist and establish relationships CreateResourceHistory history = new CreateResourceHistory(parentResource, resourceType, user.getName(), configurationClone); history.setCreatedResourceName(createResourceName); history.setStatus(CreateResourceStatus.IN_PROGRESS); entityManager.persist(history); parentResource.addCreateChildResourceHistory(history); // Caller will need this parentResource.getAgent(); return history; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public CreateResourceHistory persistCreateHistory(Subject user, int parentResourceId, int resourceTypeId, String createResourceName, PackageVersion packageVersion, Configuration deploymentTimeConfiguration) { // Load relationships Resource parentResource = entityManager.getReference(Resource.class, parentResourceId); ResourceType resourceType = entityManager.getReference(ResourceType.class, resourceTypeId); // Persist and establish relationships // TODO: Note, InstalledPackage is set to null because it doesn't really make sense. An InstalledPackage // represents a backing package relationship between a Resource and a PackageVersion, not its parent. // I think it should probably be removed from the history entity. -jshaughn 9/1/09. CreateResourceHistory history = new CreateResourceHistory(parentResource, resourceType, user.getName(), (InstalledPackage) null); history.setCreatedResourceName(createResourceName); history.setConfiguration(deploymentTimeConfiguration); history.setStatus(CreateResourceStatus.IN_PROGRESS); entityManager.persist(history); parentResource.addCreateChildResourceHistory(history); // Caller will need this parentResource.getAgent(); return history; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public DeleteResourceHistory persistDeleteHistory(Subject user, int resourceId) { // Load relationships Resource resource = entityManager.find(Resource.class, resourceId); // Persist and establish relationships DeleteResourceHistory history = new DeleteResourceHistory(resource, user.getName()); history.setStatus(DeleteResourceStatus.IN_PROGRESS); entityManager.persist(history); return history; } public CreateResourceHistory getCreateHistoryItem(int historyItemId) { Query query = entityManager.createNamedQuery(CreateResourceHistory.QUERY_FIND_BY_ID); query.setParameter("id", historyItemId); CreateResourceHistory history = (CreateResourceHistory) query.getSingleResult(); return history; } public int getCreateChildResourceHistoryCount(int parentResourceId, Long beginDate, Long endDate) { Query query = PersistenceUtility.createCountQuery(entityManager, CreateResourceHistory.QUERY_FIND_BY_PARENT_RESOURCE_ID); query.setParameter("id", parentResourceId); query.setParameter("startTime", beginDate); query.setParameter("endTime", endDate); long totalCount = (Long) query.getSingleResult(); return (int) totalCount; } @SuppressWarnings("unchecked") public PageList<CreateResourceHistory> findCreateChildResourceHistory(Subject subject, int parentResourceId, Long beginDate, Long endDate, PageControl pageControl) { pageControl.initDefaultOrderingField("crh.id", PageOrdering.DESC); int totalCount = getCreateChildResourceHistoryCount(parentResourceId, beginDate, endDate); Query query = PersistenceUtility.createQueryWithOrderBy(entityManager, CreateResourceHistory.QUERY_FIND_BY_PARENT_RESOURCE_ID, pageControl); query.setParameter("id", parentResourceId); query.setParameter("startTime", beginDate); query.setParameter("endTime", endDate); List<CreateResourceHistory> history = query.getResultList(); PageList<CreateResourceHistory> pageList = new PageList<CreateResourceHistory>(history, totalCount, pageControl); return pageList; } public int getDeleteChildResourceHistoryCount(int parentResourceId, Long beginDate, Long endDate) { Query query = PersistenceUtility.createCountQuery(entityManager, DeleteResourceHistory.QUERY_FIND_BY_PARENT_RESOURCE_ID); query.setParameter("id", parentResourceId); query.setParameter("startTime", beginDate); query.setParameter("endTime", endDate); long totalCount = (Long) query.getSingleResult(); return (int) totalCount; } @SuppressWarnings("unchecked") public PageList<DeleteResourceHistory> findDeleteChildResourceHistory(Subject subject, int parentResourceId, Long beginDate, Long endDate, PageControl pageControl) { pageControl.initDefaultOrderingField("drh.id", PageOrdering.DESC); int totalCount = getDeleteChildResourceHistoryCount(parentResourceId, beginDate, endDate); Query query = PersistenceUtility.createQueryWithOrderBy(entityManager, DeleteResourceHistory.QUERY_FIND_BY_PARENT_RESOURCE_ID, pageControl); query.setParameter("id", parentResourceId); query.setParameter("startTime", beginDate); query.setParameter("endTime", endDate); List<DeleteResourceHistory> history = query.getResultList(); PageList<DeleteResourceHistory> pageList = new PageList<DeleteResourceHistory>(history, totalCount, pageControl); return pageList; } public CreateResourceHistory createResource(Subject user, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, String packageName, String packageVersionNumber, Integer architectureId, Configuration deploymentTimeConfiguration, InputStream packageBitStream) { return createResource(user, parentResourceId, newResourceTypeId, newResourceName, pluginConfiguration, packageName, packageVersionNumber, architectureId, deploymentTimeConfiguration, packageBitStream, (Map<String, String>) null, (Integer) null); } public CreateResourceHistory createResource(Subject user, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, String packageName, String packageVersionNumber, Integer architectureId, Configuration deploymentTimeConfiguration, InputStream packageBitStream, Map<String, String> packageUploadDetails) { return createResource(user, parentResourceId, newResourceTypeId, newResourceName, pluginConfiguration, packageName, packageVersionNumber, architectureId, deploymentTimeConfiguration, packageBitStream, packageUploadDetails, null); } public CreateResourceHistory createResource(Subject user, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, String packageName, String packageVersionNumber, Integer architectureId, Configuration deploymentTimeConfiguration, InputStream packageBitStream, Map<String, String> packageUploadDetails, Integer timeout) { LOG.info("Received call to create package backed resource under parent [" + parentResourceId + "]"); Resource parentResource = entityManager.find(Resource.class, parentResourceId); // Check permissions first if (!authorizationManager .hasResourcePermission(user, Permission.CREATE_CHILD_RESOURCES, parentResource.getId())) { throw new PermissionException("User [" + user.getName() + "] does not have permission to create a child resource for resource [" + parentResource + "]"); } ResourceType newResourceType = entityManager.find(ResourceType.class, newResourceTypeId); PackageType newPackageType = contentManager.getResourceCreationPackageType(newResourceTypeId); if (!newResourceType.isCreatable() || (newResourceType.getCreationDataType() != ResourceCreationDataType.CONTENT)) { throw new RuntimeException("Cannot create " + newResourceType + " child Resource under parent " + parentResource + ", since the " + newResourceType + " type does not support content-based Resource creation."); } abortResourceCreationIfExistingSingleton(parentResource, newResourceType); // unless version is set start versioning the package by timestamp packageVersionNumber = (null == packageVersionNumber) ? Long.toString(System.currentTimeMillis()) : packageVersionNumber; // default to no required architecture architectureId = (null != architectureId) ? architectureId : contentManager.getNoArchitecture().getId(); // Create/locate package and package version PackageVersion packageVersion = null; if (packageUploadDetails == null) { packageVersion = contentManager.createPackageVersionWithDisplayVersion(user, packageName, newPackageType.getId(), packageVersionNumber, null, architectureId, packageBitStream); } else { packageVersion = contentManager.getUploadedPackageVersion(user, packageName, newPackageType.getId(), packageVersionNumber, architectureId, packageBitStream, packageUploadDetails, null); } return doCreatePackageBackedResource(user, parentResource, newResourceType, newResourceName, pluginConfiguration, deploymentTimeConfiguration, packageVersion, timeout); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // Remote Interface Impl // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! public CreateResourceHistory createResource(Subject user, int parentResourceId, int resourceTypeId, String resourceName, Configuration pluginConfiguration, Configuration resourceConfiguration) { return createResource(user, parentResourceId, resourceTypeId, resourceName, pluginConfiguration, resourceConfiguration, (Integer) null); } public CreateResourceHistory createResource(Subject user, int parentResourceId, int resourceTypeId, String resourceName, Configuration pluginConfiguration, Configuration resourceConfiguration, Integer timeout) { if (LOG.isDebugEnabled()) { LOG.debug("Received call to create configuration backed resource under parent: " + parentResourceId + " of type: " + resourceTypeId); } ResourceType resourceType = entityManager.find(ResourceType.class, resourceTypeId); Resource parentResource = entityManager.find(Resource.class, parentResourceId); Agent agent = parentResource.getAgent(); // Check permissions first if (!authorizationManager .hasResourcePermission(user, Permission.CREATE_CHILD_RESOURCES, parentResource.getId())) { throw new PermissionException("User [" + user.getName() + "] does not have permission to create a child resource for resource [" + parentResource + "]"); } if (!resourceType.isCreatable() || (resourceType.getCreationDataType() != ResourceCreationDataType.CONFIGURATION)) { throw new RuntimeException("Cannot create " + resourceType + " child Resource under parent " + parentResource + ", since the " + resourceType + " type does not support configuration-based Resource creation."); } abortResourceCreationIfExistingSingleton(parentResource, resourceType); // Persist in separate transaction so it is committed immediately, before the request is sent to the agent CreateResourceHistory persistedHistory = resourceFactoryManager.persistCreateHistory(user, parentResourceId, resourceTypeId, resourceName, resourceConfiguration); // Package into transfer object CreateResourceRequest request = new CreateResourceRequest(persistedHistory.getId(), parentResourceId, resourceName, resourceType.getName(), resourceType.getPlugin(), pluginConfiguration, resourceConfiguration, timeout); try { AgentClient agentClient = agentManager.getAgentClient(agent); ResourceFactoryAgentService resourceFactoryAgentService = agentClient.getResourceFactoryAgentService(); resourceFactoryAgentService.createResource(request); return persistedHistory; } catch (Exception e) { LOG.error("Error while sending create resource request to agent service", e); // Submit the error as a failure response String errorMessage = ThrowableUtil.getAllMessages(e); CreateResourceResponse response = new CreateResourceResponse(persistedHistory.getId(), null, null, CreateResourceStatus.FAILURE, errorMessage, resourceConfiguration); resourceFactoryManager.completeCreateResource(response); throw new RuntimeException("Error while sending create resource request to agent service", e); } } @Override public CreateResourceHistory createPackageBackedResource(Subject subject, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, String packageName, String packageVersionNumber, Integer architectureId, Configuration deploymentTimeConfiguration, byte[] packageBits, Integer timeout) { return createResource(subject, parentResourceId, newResourceTypeId, newResourceName, pluginConfiguration, packageName, packageVersionNumber, architectureId, deploymentTimeConfiguration, new ByteArrayInputStream( packageBits), (Map<String, String>) null, timeout); } @Override public CreateResourceHistory createPackageBackedResourceViaContentHandle(Subject subject, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, String packageName, String packageVersion, Integer architectureId, Configuration deploymentTimeConfiguration, String temporaryContentHandle, Integer timeout) { FileInputStream packageBitStream = null; try { packageBitStream = new FileInputStream(contentManager.getTemporaryContentFile(temporaryContentHandle)); } catch (FileNotFoundException e) { throw new RuntimeException(e); } return createResource(subject, parentResourceId, newResourceTypeId, newResourceName, pluginConfiguration, packageName, packageVersion, architectureId, deploymentTimeConfiguration, packageBitStream, (Map<String, String>) null, timeout); } @Override public CreateResourceHistory createPackageBackedResource(Subject subject, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, String packageName, String packageVersionNumber, Integer architectureId, Configuration deploymentTimeConfiguration, byte[] packageBits) { return createResource(subject, parentResourceId, newResourceTypeId, newResourceName, pluginConfiguration, packageName, packageVersionNumber, architectureId, deploymentTimeConfiguration, new ByteArrayInputStream( packageBits)); } @Override public CreateResourceHistory createPackageBackedResourceViaPackageVersion(Subject subject, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, Configuration deploymentTimeConfiguration, int packageVersionId) { return createPackageBackedResourceViaPackageVersion(subject, parentResourceId, newResourceTypeId, newResourceName, pluginConfiguration, deploymentTimeConfiguration, packageVersionId, (Integer) null); } @Override public CreateResourceHistory createPackageBackedResourceViaPackageVersion(Subject subject, int parentResourceId, int newResourceTypeId, String newResourceName, Configuration pluginConfiguration, Configuration deploymentTimeConfiguration, int packageVersionId, Integer timeout) { Resource parentResource = entityManager.find(Resource.class, parentResourceId); // Check permissions first if (!authorizationManager.hasResourcePermission(subject, Permission.CREATE_CHILD_RESOURCES, parentResource.getId())) { throw new PermissionException("User [" + subject.getName() + "] does not have permission to create a child resource for resource [" + parentResource + "]"); } ResourceType newResourceType = entityManager.find(ResourceType.class, newResourceTypeId); PackageVersion packageVersion = entityManager.find(PackageVersion.class, packageVersionId); if (!newResourceType.isCreatable() || (newResourceType.getCreationDataType() != ResourceCreationDataType.CONTENT)) { throw new RuntimeException("Cannot create " + newResourceType + " child Resource under parent " + parentResource + ", since the " + newResourceType + " type does not support content-based Resource creation."); } abortResourceCreationIfExistingSingleton(parentResource, newResourceType); return doCreatePackageBackedResource(subject, parentResource, newResourceType, newResourceName, pluginConfiguration, deploymentTimeConfiguration, packageVersion, timeout); } private CreateResourceHistory doCreatePackageBackedResource(Subject subject, Resource parentResource, ResourceType newResourceType, String newResourceName, Configuration pluginConfiguration, Configuration deploymentTimeConfiguration, PackageVersion packageVersion, Integer timeout) { Agent agent = parentResource.getAgent(); // add the timeout to the deploymentTimeConfiguration if (deploymentTimeConfiguration != null) { if (timeout != null) { deploymentTimeConfiguration.put(new PropertySimple("userProvidedTimeoutMillis", timeout)); } } // Persist in separate transaction so it is committed immediately, before the request is sent to the agent CreateResourceHistory persistedHistory = resourceFactoryManager.persistCreateHistory(subject, parentResource.getId(), newResourceType.getId(), newResourceName, packageVersion, deploymentTimeConfiguration); // Package into transfer object ResourcePackageDetails packageDetails = ContentManagerHelper.packageVersionToDetails(packageVersion); packageDetails.setDeploymentTimeConfiguration(deploymentTimeConfiguration); CreateResourceRequest request = new CreateResourceRequest(persistedHistory.getId(), parentResource.getId(), newResourceName, newResourceType.getName(), newResourceType.getPlugin(), pluginConfiguration, packageDetails, timeout); try { AgentClient agentClient = agentManager.getAgentClient(agent); ResourceFactoryAgentService resourceFactoryAgentService = agentClient.getResourceFactoryAgentService(); resourceFactoryAgentService.createResource(request); return persistedHistory; } catch (NoResultException nre) { return null; //eat the exception. Some of the queries return no results if no package yet exists which is fine. } catch (CannotConnectException e) { LOG.error("Error while sending create resource request to agent service", e); // Submit the error as a failure response String errorMessage = ThrowableUtil.getAllMessages(e); CreateResourceResponse response = new CreateResourceResponse(persistedHistory.getId(), null, null, CreateResourceStatus.FAILURE, errorMessage, null); resourceFactoryManager.completeCreateResource(response); throw new CannotConnectToAgentException("Error while sending create resource request to agent service", e); } catch (Exception e) { LOG.error("Error while sending create resource request to agent service", e); // Submit the error as a failure response String errorMessage = ThrowableUtil.getAllMessages(e); CreateResourceResponse response = new CreateResourceResponse(persistedHistory.getId(), null, null, CreateResourceStatus.FAILURE, errorMessage, null); resourceFactoryManager.completeCreateResource(response); throw new RuntimeException("Error while sending create resource request to agent service", e); } } public List<DeleteResourceHistory> deleteResources(Subject user, int[] resourceIds) { List<Integer> deleteResourceIds = new ArrayList<Integer>(); List<DeleteResourceHistory> deleteResourceHistories = new ArrayList<DeleteResourceHistory>(); for (Integer resourceId : resourceIds) { if (!deleteResourceIds.contains(resourceId)) { deleteResourceHistories.add(deleteResource(user, resourceId)); } } return deleteResourceHistories; } public DeleteResourceHistory deleteResource(Subject subject, int resourceId) { if (LOG.isDebugEnabled()) { LOG.debug("Received call to delete resource: " + resourceId); } Resource resource = entityManager.find(Resource.class, resourceId); Agent agent = resource.getAgent(); // Check permissions first if (!authorizationManager.hasResourcePermission(subject, Permission.DELETE_RESOURCE, resource.getId())) { throw new PermissionException("User [" + subject.getName() + "] does not have permission to delete resource [" + resource + "]"); } // Persist in separate transaction so it is committed immediately, before the request is sent to the agent DeleteResourceHistory persistedHistory = resourceFactoryManager.persistDeleteHistory(subject, resourceId); // Package into transfer object DeleteResourceRequest request = new DeleteResourceRequest(persistedHistory.getId(), resourceId); try { AgentClient agentClient = agentManager.getAgentClient(agent); ResourceFactoryAgentService resourceFactoryAgentService = agentClient.getResourceFactoryAgentService(); resourceFactoryAgentService.deleteResource(request); return persistedHistory; } catch (CannotConnectException e) { LOG.error("Error while sending delete resource request to agent service", e); // Submit the error as a failure response String errorMessage = ThrowableUtil.getAllMessages(e); DeleteResourceResponse response = new DeleteResourceResponse(persistedHistory.getId(), resourceId, DeleteResourceStatus.FAILURE, errorMessage); resourceFactoryManager.completeDeleteResourceRequest(response); throw new CannotConnectToAgentException("Error while sending delete resource request to agent service", e); } catch (Exception e) { LOG.error("Error while sending delete resource request to agent service", e); // Submit the error as a failure response String errorMessage = ThrowableUtil.getAllMessages(e); DeleteResourceResponse response = new DeleteResourceResponse(persistedHistory.getId(), resourceId, DeleteResourceStatus.FAILURE, errorMessage); resourceFactoryManager.completeDeleteResourceRequest(response); throw new RuntimeException("Error while sending delete resource request to agent service", e); } } private void abortResourceCreationIfExistingSingleton(Resource parentResource, ResourceType resourceType) { if (resourceType.isSingleton()) { ResourceCriteria resourceCriteria = new ResourceCriteria(); resourceCriteria.addFilterParentResourceId(parentResource.getId()); resourceCriteria.addFilterResourceTypeId(resourceType.getId()); resourceCriteria.clearPaging();//disable paging as the code assumes all the results will be returned. PageList<Resource> childResourcesOfType = resourceManager.findResourcesByCriteria( subjectManager.getOverlord(), resourceCriteria); if (childResourcesOfType.size() >= 1) { throw new RuntimeException("Cannot create " + resourceType + " child Resource under parent " + parentResource + ", since " + resourceType + " is a singleton type, and there is already a child Resource of that type. " + "If the existing child Resource corresponds to a managed Resource which no longer exists, " + "uninventory it and then try again."); } } } }