/*
* RHQ Management Platform
* Copyright (C) 2005-2010 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.enterprise.gui.inventory.resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.model.SelectItem;
import javax.persistence.NoResultException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.model.UploadItem;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.configuration.definition.ConfigurationTemplate;
import org.rhq.core.domain.content.Architecture;
import org.rhq.core.domain.content.PackageType;
import org.rhq.core.domain.resource.CreateResourceHistory;
import org.rhq.core.domain.resource.CreateResourceStatus;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.core.gui.util.FacesContextUtility;
import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.core.util.exception.ThrowableUtil;
import org.rhq.enterprise.gui.legacy.ParamConstants;
import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility;
import org.rhq.enterprise.server.configuration.ConfigurationManagerLocal;
import org.rhq.enterprise.server.content.ContentManagerLocal;
import org.rhq.enterprise.server.content.ContentUIManagerLocal;
import org.rhq.enterprise.server.resource.ResourceFactoryManagerLocal;
import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.resource.ResourceTypeNotFoundException;
import org.rhq.enterprise.server.util.LookupUtil;
/**
* Handles the workflow for creating a new package-backed Resource.
*
* The associated Facelets page is: /rhq/resource/inventory/create-package-1.xhtml
*
* @author Jason Dobies
* @author Ian Springer
*/
public class CreateNewPackageChildResourceUIBean {
// Constants --------------------------------------------
public static final String MANAGED_BEAN_NAME = "CreateNewPackageChildResourceUIBean";
private static final String OUTCOME_SUCCESS_OR_FAILURE = "successOrFailure";
// private static final String OUTCOME_SUCCESS = "success";
private static final String OUTCOME_CANCEL = "cancel";
private static final String DEFAULT_VERSION = "0";
// Attributes --------------------------------------------
private final Log log = LogFactory.getLog(this.getClass());
private ResourceType resourceType;
private PackageType packageType;
private String packageName;
private String version = DEFAULT_VERSION;
private Integer selectedArchitectureId;
private CreateResourceHistory retryCreateItem;
private ConfigurationDefinition configurationDefinition;
private Configuration configuration;
public CreateNewPackageChildResourceUIBean() {
this.resourceType = lookupResourceType();
this.packageType = lookupPackageType();
this.configurationDefinition = lookupConfigurationDefinition();
this.configuration = lookupConfiguration();
}
// Actions --------------------------------------------
/**
* Performs the creation of an package-backed Resource.
*
* @return outcome of the creation attempt
*/
public String createResource() {
Subject user = EnterpriseFacesContextUtility.getSubject();
UploadNewChildPackageUIBean uploadUIBean;
uploadUIBean = FacesContextUtility.getManagedBean(UploadNewChildPackageUIBean.class);
UploadItem fileItem = uploadUIBean.getFileItem();
//store information about uploaded file for packageDetails as most of it is already available
Map<String, String> packageUploadDetails = new HashMap<String, String>();
packageUploadDetails.put(ContentManagerLocal.UPLOAD_FILE_SIZE, String.valueOf(fileItem.getFileSize()));
packageUploadDetails.put(ContentManagerLocal.UPLOAD_FILE_INSTALL_DATE, String.valueOf(System
.currentTimeMillis()));
packageUploadDetails.put(ContentManagerLocal.UPLOAD_OWNER, user.getName());
packageUploadDetails.put(ContentManagerLocal.UPLOAD_FILE_NAME, fileItem.getFileName());
try {//Easier to implement here than in server side bean. Shouldn't affect performance too much.
packageUploadDetails.put(ContentManagerLocal.UPLOAD_MD5, new MessageDigestGenerator(
MessageDigestGenerator.MD5).calcDigestString(fileItem.getFile()));
packageUploadDetails.put(ContentManagerLocal.UPLOAD_SHA256, new MessageDigestGenerator(
MessageDigestGenerator.SHA_256).calcDigestString(fileItem.getFile()));
} catch (IOException e1) {
log.warn("Error calculating file digest(s) : " + e1.getMessage());
e1.printStackTrace();
}
// Validate
if ((fileItem == null) || fileItem.getFile() == null) {
FacesContextUtility.addMessage(FacesMessage.SEVERITY_ERROR, "A package file must be uploaded");
return null;
}
if ((getVersion() == null) || (getVersion().trim().length() == 0)) {
FacesContextUtility.addMessage(FacesMessage.SEVERITY_ERROR, "A package version must be specified.");
return null;
}
ConfigurationManagerLocal configurationManager = LookupUtil.getConfigurationManager();
ConfigurationDefinition pluginConfigurationDefinition = configurationManager
.getPluginConfigurationDefinitionForResourceType(user, resourceType.getId());
Configuration pluginConfiguration = null;
if (pluginConfigurationDefinition != null) {
pluginConfiguration = pluginConfigurationDefinition.getDefaultTemplate().getConfiguration();
}
try {
try {
log.debug("Streaming new package bits from uploaded file: " + fileItem.getFile());
InputStream packageContentStream = new FileInputStream(fileItem.getFile());
try {
if (isSupportsArchitecture()) {
// pull in architecture selection
selectedArchitectureId = getSelectedArchitectureId();
}
// Collect data for create call
Resource parentResource = EnterpriseFacesContextUtility.getResource();
Configuration deployTimeConfiguration = getConfiguration();
String packageName = fileItem.getFileName();
// some browsers (IE in particular) passes an absolute filename, we just want the name of the file, no paths
if (packageName != null) {
packageName = packageName.replace('\\', '/');
if (packageName.length() > 2 && packageName.charAt(1) == ':') {
packageName = packageName.substring(2);
}
packageName = new File(packageName).getName();
}
try {
ResourceFactoryManagerLocal resourceFactoryManager = LookupUtil.getResourceFactoryManager();
// RHQ-666 - Changed to not request the resource name from the user; simply pass null
// JON 2.0 RC3 - use timestamp versioning; pass null for version
// resourceFactoryManager.createResource(user, parentResource.getId(), getResourceTypeId(), null,
// pluginConfiguration, packageName, null, selectedArchitectureId, deployTimeConfiguration,
// packageContentStream);
if (packageUploadDetails != null) {
resourceFactoryManager.createResource(user, parentResource.getId(), getResourceTypeId(), null,
pluginConfiguration, packageName, getVersion(), selectedArchitectureId,
deployTimeConfiguration, packageContentStream, packageUploadDetails);
} else {
resourceFactoryManager.createResource(user, parentResource.getId(), getResourceTypeId(), null,
pluginConfiguration, packageName, null, selectedArchitectureId, deployTimeConfiguration,
packageContentStream);
}
} catch (NoResultException nre) {
//eat the exception. Some of the queries return no results if no package yet exists which is fine.
} catch (Exception e) {
String errorMessages = ThrowableUtil.getAllMessages(e);
FacesContextUtility.addMessage(FacesMessage.SEVERITY_ERROR,
"Failed to send create resource request to agent. Cause: " + errorMessages);
log.error("Failed to create new child Resource of type [" + getResourceType() + "].", e);
return OUTCOME_SUCCESS_OR_FAILURE;
}
} finally {
packageContentStream.close();
}
} catch (IOException e) {
String errorMessages = ThrowableUtil.getAllMessages(e);
FacesContextUtility.addMessage(FacesMessage.SEVERITY_ERROR,
"Failed to retrieve the input stream. Cause: " + errorMessages);
return OUTCOME_SUCCESS_OR_FAILURE;
}
// If we got this far, there were no errors, so output a success message
FacesContextUtility.addMessage(FacesMessage.SEVERITY_INFO,
"Create resource request successfully sent to the agent.");
} finally {
// clean up the temp file
cleanup(uploadUIBean);
}
return OUTCOME_SUCCESS_OR_FAILURE;
}
public boolean isSupportsArchitecture() {
return packageType.isSupportsArchitecture();
}
private void cleanup(UploadNewChildPackageUIBean uploadUIBean) {
if (uploadUIBean != null) {
uploadUIBean.clear();
}
// clean out fields for next usage
this.configuration = null;
this.configurationDefinition = null;
this.packageType = null;
this.resourceType = null;
}
public String cancel() {
UploadNewChildPackageUIBean uploadUIBean;
uploadUIBean = FacesContextUtility.getManagedBean(UploadNewChildPackageUIBean.class);
cleanup(uploadUIBean);
return OUTCOME_CANCEL;
}
public SelectItem[] getArchitectures() {
Subject subject = EnterpriseFacesContextUtility.getSubject();
ContentManagerLocal contentManager = LookupUtil.getContentManager();
List<Architecture> architectures = contentManager.findArchitectures(subject);
SelectItem[] items = new SelectItem[architectures.size()];
int itemCounter = 0;
for (Architecture arch : architectures) {
SelectItem item = new SelectItem(arch.getId(), arch.getName());
items[itemCounter++] = item;
}
return items;
}
private ResourceType lookupResourceType() {
ResourceTypeManagerLocal resourceTypeManager = LookupUtil.getResourceTypeManager();
Subject subject = EnterpriseFacesContextUtility.getSubject();
ResourceType resourceType;
try {
resourceType = resourceTypeManager.getResourceTypeById(subject, getResourceTypeId());
} catch (ResourceTypeNotFoundException e) {
throw new IllegalStateException(e); // generally should never happen
}
return resourceType;
}
private PackageType lookupPackageType() {
if (resourceType == null) {
resourceType = lookupResourceType();
}
ContentManagerLocal contentManager = LookupUtil.getContentManager();
PackageType packageType = contentManager.getResourceCreationPackageType(this.resourceType.getId());
return packageType;
}
protected ConfigurationDefinition lookupConfigurationDefinition() {
if (packageType == null) {
packageType = lookupPackageType();
}
ConfigurationDefinition configurationDefinition = this.packageType.getDeploymentConfigurationDefinition();
return configurationDefinition;
}
protected Configuration lookupConfiguration() {
ConfigurationTemplate deployTimeConfigurationTemplates = null;
ConfigurationDefinition configDef = getConfigurationDefinition();
if (configDef != null) {
deployTimeConfigurationTemplates = configDef.getDefaultTemplate();
}
Configuration deployTimeConfiguration = (deployTimeConfigurationTemplates != null) ? deployTimeConfigurationTemplates
.createConfiguration()
: new Configuration();
return deployTimeConfiguration;
}
// Accessors --------------------------------------------
/**
* Temporary hack to get around the bug in the richfaces data table that breaks links in each row. Ultimately, each
* failed row will have a button to retry the create. Until that bug is fixed, use a separate dropdown with each
* failed create to select the one to retry.
*
* @return list of failed create history requests
*/
public SelectItem[] getFailedCreateHistory() {
Subject subject = EnterpriseFacesContextUtility.getSubject();
Resource parentResource = EnterpriseFacesContextUtility.getResource();
ResourceFactoryManagerLocal resourceFactoryManager = LookupUtil.getResourceFactoryManager();
PageControl pageControl = new PageControl(0, 1000);
PageList<CreateResourceHistory> pageList = resourceFactoryManager.findCreateChildResourceHistory(subject,
parentResource.getId(), null, null, pageControl);
List<SelectItem> selectItemsList = new ArrayList<SelectItem>();
for (CreateResourceHistory history : pageList) {
if ((history.getStatus() == CreateResourceStatus.FAILURE)
|| (history.getStatus() == CreateResourceStatus.TIMED_OUT)) {
selectItemsList.add(new SelectItem(history, history.getCreatedResourceName()));
}
}
SelectItem[] items = selectItemsList.toArray(new SelectItem[selectItemsList.size()]);
return items;
}
public CreateResourceHistory getRetryCreateItem() {
return retryCreateItem;
}
public void setRetryCreateItem(CreateResourceHistory retryCreateItem) {
this.retryCreateItem = retryCreateItem;
}
public PackageType getPackageType() {
if (this.packageType == null)
this.packageType = lookupPackageType();
return packageType;
}
public void setPackageType(PackageType packageType) {
this.packageType = packageType;
}
public ResourceType getResourceType() {
if (this.resourceType == null)
this.resourceType = lookupResourceType();
return resourceType;
}
public void setResourceType(ResourceType resourceType) {
this.resourceType = resourceType;
}
public int getSelectedArchitectureId() {
return selectedArchitectureId;
}
public void setSelectedArchitectureId(int selectedArchitectureId) {
this.selectedArchitectureId = selectedArchitectureId;
}
public ConfigurationDefinition getConfigurationDefinition() {
if (this.configurationDefinition == null)
this.configurationDefinition = lookupConfigurationDefinition();
return configurationDefinition;
}
public Configuration getConfiguration() {
if (this.configuration == null)
this.configuration = lookupConfiguration();
return configuration;
}
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
public String getNullConfigurationDefinitionMessage() {
return "This resource type does not expose deployment-time configuration values.";
}
public String getNullConfigurationMessage() {
return "Unable to create an initial deployment-time configuration for resource being added.";
}
private int getResourceTypeId() {
try {
return EnterpriseFacesContextUtility.getResourceType().getId();
} catch (Exception e) {
return (Integer) FacesContextUtility.getFacesContext().getExternalContext().getRequestMap().get(
ParamConstants.RESOURCE_TYPE_ID_PARAM);
}
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public SelectItem[] getPackageTypes() {
Resource resource = EnterpriseFacesContextUtility.getResource();
ContentUIManagerLocal contentUIManager = LookupUtil.getContentUIManager();
List<PackageType> packageTypes = contentUIManager.getPackageTypes(resource.getResourceType().getId());
SelectItem[] items = new SelectItem[packageTypes.size()];
int itemCounter = 0;
for (PackageType packageType : packageTypes) {
SelectItem item = new SelectItem(packageType.getId(), packageType.getDisplayName());
items[itemCounter++] = item;
}
return items;
}
}