/* * RHQ Management Platform * Copyright (C) 2005-2011 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.plugins.jbossas5.deploy; import java.io.File; import java.net.URI; import java.util.Collection; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.deployers.spi.management.KnownDeploymentTypes; import org.jboss.deployers.spi.management.ManagementView; import org.jboss.deployers.spi.management.deploy.DeploymentManager; import org.jboss.managed.api.DeploymentState; import org.jboss.managed.api.ManagedDeployment; import org.jboss.profileservice.spi.NoSuchDeploymentException; import org.jboss.profileservice.spi.ProfileKey; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.content.PackageDetailsKey; import org.rhq.core.domain.content.transfer.ResourcePackageDetails; import org.rhq.core.domain.resource.CreateResourceStatus; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.pluginapi.content.FileContentDelegate; import org.rhq.core.pluginapi.inventory.CreateResourceReport; import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.plugins.jbossas5.connection.ProfileServiceConnection; import org.rhq.plugins.jbossas5.util.ConversionUtils; import org.rhq.plugins.jbossas5.util.DeploymentUtils; /** * This implementation handles deploying stuff using the standard JBoss deployment APIs. * * @author Lukas Krejci */ public class ManagedComponentDeployer implements Deployer { private static final Log LOG = LogFactory.getLog(ManagedComponentDeployer.class); private static final ProfileKey FARM_PROFILE_KEY = new ProfileKey("farm"); private static final ProfileKey APPLICATIONS_PROFILE_KEY = new ProfileKey("applications"); private PackageDownloader downloader; private ProfileServiceConnection profileServiceConnection; private ResourceContext<?> parentResourceContext; /** * @deprecated To be used only by the ESB plugin (backwards compatibility). * Replaced by {@link #ManagedComponentDeployer(ProfileServiceConnection, PackageDownloader, ResourceContext)} */ @Deprecated public ManagedComponentDeployer(ProfileServiceConnection profileServiceConnection, PackageDownloader downloader) { this(profileServiceConnection, downloader, null); } public ManagedComponentDeployer(ProfileServiceConnection profileServiceConnection, PackageDownloader downloader, ResourceContext<?> parentResourceContext) { this.downloader = downloader; this.profileServiceConnection = profileServiceConnection; this.parentResourceContext = parentResourceContext; } public void deploy(CreateResourceReport createResourceReport, ResourceType resourceType) { createResourceReport.setStatus(null); File archiveFile = null; try { ResourcePackageDetails details = createResourceReport.getPackageDetails(); PackageDetailsKey key = details.getKey(); archiveFile = downloader.prepareArchive(key, resourceType); String archiveName = key.getName(); if (!DeploymentUtils.hasCorrectExtension(archiveName, resourceType)) { createResourceReport.setStatus(CreateResourceStatus.FAILURE); createResourceReport.setErrorMessage("Incorrect extension specified on filename [" + archiveName + "]"); return; } abortIfApplicationAlreadyDeployed(resourceType, archiveFile); Configuration deployTimeConfig = details.getDeploymentTimeConfiguration(); boolean deployExploded = deployTimeConfig.getSimple("deployExploded").getBooleanValue(); DeploymentManager deploymentManager = this.profileServiceConnection.getDeploymentManager(); boolean deployFarmed = deployTimeConfig.getSimple("deployFarmed").getBooleanValue(); if (deployFarmed) { Collection<ProfileKey> profileKeys = deploymentManager.getProfiles(); boolean farmSupported = false; for (ProfileKey profileKey : profileKeys) { if (profileKey.getName().equals(FARM_PROFILE_KEY.getName())) { farmSupported = true; break; } } if (!farmSupported) { throw new IllegalStateException("This application server instance is not a node in a cluster, " + "so it does not support farmed deployments. Supported deployment profiles are " + profileKeys + "."); } if (deployExploded) { throw new IllegalArgumentException( "Deploying farmed applications in exploded form is not supported by the Profile Service."); } deploymentManager.loadProfile(FARM_PROFILE_KEY); } String[] deploymentNames; try { deploymentNames = DeploymentUtils.deployArchive(deploymentManager, archiveFile, deployExploded); } finally { // Make sure to switch back to the 'applications' profile if we switched to the 'farm' profile above. if (deployFarmed) { deploymentManager.loadProfile(APPLICATIONS_PROFILE_KEY); } } if (deploymentNames == null || deploymentNames.length != 1) { throw new RuntimeException("deploy operation returned invalid result: " + deploymentNames); } // e.g.: vfszip:/C:/opt/jboss-6.0.0.Final/server/default/deploy/foo.war String deploymentName = deploymentNames[0]; // If deployed exploded, we need to store the SHA of source package in META-INF/MANIFEST.MF for correct // versioning. if (deployExploded && this.parentResourceContext != null) { URI deploymentURI = URI.create(deploymentName); // e.g.: /C:/opt/jboss-6.0.0.Final/server/default/deploy/foo.war String deploymentPath = deploymentURI.getPath(); File deploymentFile = new File(deploymentPath); FileContentDelegate fileContentDelegate = new FileContentDelegate(); fileContentDelegate.saveDeploymentSHA(archiveFile, deploymentFile, parentResourceContext.getFutureChildResourceDataDirectory(archiveName)); } // Reload the management view to pickup the ManagedDeployment for the app we just deployed. ManagementView managementView = this.profileServiceConnection.getManagementView(); managementView.load(); ManagedDeployment managedDeployment = null; try { managedDeployment = managementView.getDeployment(deploymentName); } catch (NoSuchDeploymentException e) { LOG.error("Failed to find managed deployment '" + deploymentName + "' after deploying '" + archiveName + "', so cannot start the application."); createResourceReport.setStatus(CreateResourceStatus.INVALID_ARTIFACT); createResourceReport.setErrorMessage("Unable to start application '" + deploymentName + "' after deploying it, since lookup of the associated ManagedDeployment failed."); } if (managedDeployment != null) { DeploymentState state = managedDeployment.getDeploymentState(); if (state != DeploymentState.STARTED) { // The app failed to start - do not consider this a FAILURE, since it was at least deployed // successfully. However, set the status to INVALID_ARTIFACT and set an error message, so // the user is informed of the condition. createResourceReport.setStatus(CreateResourceStatus.INVALID_ARTIFACT); createResourceReport.setErrorMessage("Failed to start application '" + deploymentName + "' after deploying it."); } } createResourceReport.setResourceName(archiveName); createResourceReport.setResourceKey(archiveName); if (createResourceReport.getStatus() == null) { // Deployment was 100% successful, including starting the app. createResourceReport.setStatus(CreateResourceStatus.SUCCESS); } } catch (Throwable t) { LOG.error("Error deploying application for request [" + createResourceReport + "].", t); createResourceReport.setStatus(CreateResourceStatus.FAILURE); createResourceReport.setException(t); } finally { if (archiveFile != null) { downloader.destroyArchive(archiveFile); } } } private void abortIfApplicationAlreadyDeployed(ResourceType resourceType, File archiveFile) throws Exception { String archiveFileName = archiveFile.getName(); KnownDeploymentTypes deploymentType = ConversionUtils.getDeploymentType(resourceType); String deploymentTypeString = deploymentType.getType(); ManagementView managementView = profileServiceConnection.getManagementView(); managementView.load(); Set<ManagedDeployment> managedDeployments = managementView.getDeploymentsForType(deploymentTypeString); for (ManagedDeployment managedDeployment : managedDeployments) { if (managedDeployment.getSimpleName().equals(archiveFileName)) throw new IllegalArgumentException("An application named '" + archiveFileName + "' is already deployed."); } } }