/*
* RHQ Management Platform
* Copyright (C) 2005-2008 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.configuration.resource;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import javax.faces.application.FacesMessage;
import javax.faces.event.ValueChangeEvent;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.Nullable;
import org.richfaces.model.UploadItem;
import org.rhq.core.domain.auth.Subject;
import org.rhq.core.domain.configuration.AbstractResourceConfigurationUpdate;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.Property;
import org.rhq.core.domain.configuration.RawConfiguration;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.configuration.definition.ConfigurationFormat;
import org.rhq.core.gui.util.FacesContextUtility;
import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.enterprise.gui.common.upload.FileUploadUIBean;
import org.rhq.enterprise.gui.configuration.AbstractConfigurationUIBean;
import org.rhq.enterprise.gui.util.EnterpriseFacesContextUtility;
import org.rhq.enterprise.server.configuration.ConfigurationManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;
// This class is temporarily decleared in components.xml since it is declared under two names - ViewUIBean and
// UIBean. This class is undergoing some refactoring and part of that will include declaring the @Name and @Scope
// annotations again.
//
//@Name(value = "ExistingResourceConfigurationViewUIBean")
//@Scope(ScopeType.PAGE)
public class ExistingResourceConfigurationUIBean extends AbstractConfigurationUIBean {
public static final String MANAGED_BEAN_NAME = "ExistingResourceConfigurationUIBean";
private static final boolean STRUCTURED_MODE = true;
private static final boolean RAW_MODE = false;
private boolean mode = STRUCTURED_MODE;
// @Out
private Collection<RawConfigDirectory> rawConfigDirectories;
// @Out
private FileUploadUIBean fileUploader = new FileUploadUIBean();
private String modalEditorContents;
private int numberOfModifiedFiles;
public ExistingResourceConfigurationUIBean() {
removeSessionScopedBeanIfInView("/rhq/resource/configuration/view.xhtml",
ExistingResourceConfigurationUIBean.class);
}
//@Create
public void begin() {
if (isRawSupported() || isStructuredAndRawSupported()) {
initConfigDirectories();
} else {
rawConfigDirectories = Collections.emptyList();
}
}
private void initConfigDirectories() {
Map<String, RawConfigDirectory> dirs = new HashMap<String, RawConfigDirectory>();
for (RawConfiguration rawConfig : getConfiguration().getRawConfigurations()) {
String parentDirPath = getParentDir(rawConfig);
RawConfigDirectory dir = dirs.get(parentDirPath);
if (dir == null) {
dir = new RawConfigDirectory();
dir.setPath(parentDirPath);
}
dir.addRawConfig(rawConfig);
dirs.put(parentDirPath, dir);
}
rawConfigDirectories = dirs.values();
}
private String getParentDir(RawConfiguration rawConfig) {
File file = new File(rawConfig.getPath());
return file.getParentFile().getAbsolutePath();
}
public String editConfiguration() {
mode = STRUCTURED_MODE;
return SUCCESS_OUTCOME;
}
public String editRawConfiguration() {
mode = RAW_MODE;
return SUCCESS_OUTCOME;
}
public void changeTabs(ValueChangeEvent event) {
if (event.getNewValue().equals("rawTab")) {
switchToRaw();
mode = RAW_MODE;
} else if (event.getNewValue().equals("structuredTab")) {
switchToStructured();
mode = STRUCTURED_MODE;
}
}
public String switchToRaw() {
Configuration configuration = LookupUtil.getConfigurationManager().translateResourceConfiguration(
EnterpriseFacesContextUtility.getSubject(), getResourceId(), getConfiguration(), true);
setConfiguration(configuration);
for (RawConfiguration raw : configuration.getRawConfigurations()) {
getRaws().put(raw.getPath(), raw);
}
current = null;
setConfiguration(configuration);
updateModifiedCache();
mode = RAW_MODE;
return null;
}
private void updateModifiedCache() {
Configuration configuration = getConfiguration();
for (RawConfiguration updatedRaw : configuration.getRawConfigurations()) {
RawConfiguration cachedRaw = modified.get(updatedRaw.getPath());
if (cachedRaw != null && !updatedRaw.getSha256().equals(cachedRaw.getSha256())) {
modified.remove(cachedRaw.getPath());
}
}
}
public String switchToStructured() {
Configuration configuration = LookupUtil.getConfigurationManager().translateResourceConfiguration(
EnterpriseFacesContextUtility.getSubject(), getResourceId(), getMergedConfiguration(), false);
for (Property property : configuration.getAllProperties().values()) {
property.setConfiguration(configuration);
}
for (RawConfiguration raw : configuration.getRawConfigurations()) {
getRaws().put(raw.getPath(), raw);
setConfiguration(configuration);
}
current = null;
setConfiguration(configuration);
for (RawConfiguration raw : configuration.getRawConfigurations()) {
System.out.println(raw.getPath() + " -\n" + raw.getContents() + "\n");
}
updateModifiedCache();
mode = STRUCTURED_MODE;
return null;
}
public String updateConfiguration() {
return updateConfiguration(true);
}
public String updateRawConfiguration() {
return updateConfiguration(false);
}
public void saveModalEditorContents() {
setCurrentContents(modalEditorContents);
}
public String updateConfiguration(boolean fromStructured) {
int resourceId = EnterpriseFacesContextUtility.getResource().getId();
Configuration mergedConfiguration = getMergedConfiguration();
AbstractResourceConfigurationUpdate updateRequest = this.configurationManager
.updateStructuredOrRawConfiguration(EnterpriseFacesContextUtility.getSubject(), resourceId,
mergedConfiguration, fromStructured);
if (updateRequest != null) {
switch (updateRequest.getStatus()) {
case SUCCESS:
case INPROGRESS:
FacesContextUtility.addMessage(FacesMessage.SEVERITY_INFO, "Configuration update request with id "
+ updateRequest.getId() + " has been sent to the Agent.");
clearConfiguration();
return SUCCESS_OUTCOME;
case FAILURE:
FacesContextUtility.addMessage(FacesMessage.SEVERITY_ERROR, "Configuration update request with id "
+ updateRequest.getId() + " failed.", updateRequest.getErrorMessage());
if (null != mergedConfiguration) {
for (RawConfiguration raw : mergedConfiguration.getRawConfigurations()) {
String message = raw.errorMessage;
if (message != null) {
FacesContextUtility.addMessage(FacesMessage.SEVERITY_ERROR, raw.getPath(), message);
}
}
}
return FAILURE_OUTCOME;
case NOCHANGE:
FacesContextUtility.addMessage(FacesMessage.SEVERITY_WARN,
"No changes were made to the configuration, so " + "no update request has been sent to the Agent.");
clearConfiguration();
return SUCCESS_OUTCOME;
}
}
return FAILURE_OUTCOME;
}
public String finishAddMap() {
FacesContextUtility.addMessage(FacesMessage.SEVERITY_INFO, "Map added.");
return SUCCESS_OUTCOME;
}
public String finishEditMap() {
FacesContextUtility.addMessage(FacesMessage.SEVERITY_INFO, "Map updated.");
return SUCCESS_OUTCOME;
}
protected int getConfigurationDefinitionKey() {
return EnterpriseFacesContextUtility.getResource().getResourceType().getId();
}
@Nullable
protected ConfigurationDefinition lookupConfigurationDefinition() {
int resourceTypeId = EnterpriseFacesContextUtility.getResource().getResourceType().getId();
ConfigurationDefinition configurationDefinition = this.configurationManager
.getResourceConfigurationDefinitionForResourceType(EnterpriseFacesContextUtility.getSubject(),
resourceTypeId);
return configurationDefinition;
}
protected int getConfigurationKey() {
return EnterpriseFacesContextUtility.getResource().getId();
}
protected ConfigurationManagerLocal configurationManager = LookupUtil.getConfigurationManager();
@Nullable
protected Configuration lookupConfiguration() {
Subject subject = EnterpriseFacesContextUtility.getSubject();
int resourceId = EnterpriseFacesContextUtility.getResource().getId();
AbstractResourceConfigurationUpdate configurationUpdate = this.configurationManager
.getLatestResourceConfigurationUpdate(subject, resourceId);
Configuration configuration = (configurationUpdate != null) ? configurationUpdate.getConfiguration() : null;
return configuration;
}
private final Log log = LogFactory.getLog(AbstractConfigurationUIBean.class);
private Integer resourceId = null;
private static final long serialVersionUID = 4837157548556168146L;
public String commit() {
Subject subject = EnterpriseFacesContextUtility.getSubject();
LookupUtil.getConfigurationManager().updateResourceConfiguration(subject, getResourceId(),
getMergedConfiguration());
return "/rhq/resource/configuration/view.xhtml?id=" + getResourceId();
}
private Configuration getMergedConfiguration() {
for (RawConfiguration raw : getModified().values()) {
getRaws().put(raw.getPath(), raw);
log.error("Just merged in raw path =[" + raw.getPath() + "]");
log.error(" file =[" + new String(raw.getContents()) + "]");
}
getConfiguration().getRawConfigurations().clear();
getConfiguration().getRawConfigurations().addAll(getRaws().values());
return getConfiguration();
}
public String editCurrent() {
RawConfiguration editedRaw = getCurrent();
RawConfiguration originalRaw = raws.get(editedRaw.getPath());
if (editedRaw.getSha256().equals(originalRaw.getSha256())) {
--numberOfModifiedFiles;
RawConfigUIBean rawUIBean = findRawConfigUIBeanByPath(editedRaw.getPath());
// rawUIBean.setModified(false);
getModified().remove(editedRaw.getPath());
} else {
++numberOfModifiedFiles;
}
return null;
}
public void undoEdit(String path) {
modified.remove(path);
RawConfigUIBean bean = findRawConfigUIBeanByPath(path);
if (bean != null) {
// bean.setModified(false);
// bean.setIcon("/images/blank.png");
}
}
public int getConfigId() {
return getConfiguration().getId();
}
private ConfigurationFormat getConfigurationFormat() {
return getConfigurationDefinition().getConfigurationFormat();
}
public RawConfiguration getCurrent() {
if (null == current) {
Iterator<RawConfiguration> iterator = getRaws().values().iterator();
if (iterator.hasNext()) {
current = iterator.next();
} else {
current = new RawConfiguration();
current.setPath("/dev/null");
String sha256 = new MessageDigestGenerator(MessageDigestGenerator.SHA_256).calcDigestString("");
current.setContents("", sha256);
}
}
return current;
}
public String getCurrentContents() {
return new String(getCurrent().getContents());
}
public String getCurrentPath() {
return getCurrent().getPath();
}
public String getModalEditorHeader() {
return getCurrentPath();
}
public String getModalEditorContents() {
if (modalEditorContents == null) {
modalEditorContents = getCurrentContents();
}
return modalEditorContents;
}
public void setModalEditorContents(String contents) {
modalEditorContents = contents;
}
public TreeMap<String, RawConfiguration> getModified() {
if (modified == null) {
modified = new TreeMap<String, RawConfiguration>();
}
return modified;
}
public String getSelectedTab() {
if (mode == STRUCTURED_MODE) {
return "structuredTab";
}
return "rawTab";
}
public void setSelectedTab(String tab) {
if (tab.equals("structuredTab")) {
mode = STRUCTURED_MODE;
} else {
mode = RAW_MODE;
}
}
public Object[] getPaths() {
return getRaws().keySet().toArray();
}
/**
*
* @return the id associated with the resource.
* The value Cached in order to be available on the completeUpload page,
* where seeing the resource id conflicts with the rich completeUpload tag.
*/
public int getResourceId() {
if (resourceId == null) {
resourceId = EnterpriseFacesContextUtility.getResource().getId();
}
return resourceId;
}
public boolean isStructuredMode() {
return mode == STRUCTURED_MODE;
}
public boolean isRawMode() {
return mode == RAW_MODE;
}
public boolean isDisplayChangedFilesLabel() {
if (isStructuredMode()) {
return false;
}
if (isRawSupported()) {
return true;
}
return isRawMode();
}
public String getModifiedFilesMsg() {
if (!isDisplayChangedFilesLabel() || numberOfModifiedFiles == 0) {
return "";
}
if (numberOfModifiedFiles == 1) {
return "1 file changed in this configuration";
}
return numberOfModifiedFiles + " files changed in this configuration";
}
public boolean isModified(String path) {
return getModified().keySet().contains(path);
}
public boolean isRawSupported() {
return getConfigurationDefinition().getConfigurationFormat() == ConfigurationFormat.RAW;
}
public boolean isStructuredSupported() {
return getConfigurationDefinition().getConfigurationFormat() == ConfigurationFormat.STRUCTURED;
}
public boolean isStructuredAndRawSupported() {
return getConfigurationDefinition().getConfigurationFormat() == ConfigurationFormat.STRUCTURED_AND_RAW;
}
public boolean isFileUploadAvailable() {
return isRawSupported() || (isStructuredAndRawSupported() && isRawMode());
}
/**
* Indicates which of the raw configuration files is currently selected.
* @param s
*/
public void select(String s) {
selectedPath = s;
setCurrentPath(selectedPath);
setCurrentContents(getCurrentContents());
modalEditorContents = getCurrentContents();
}
public void setCurrentContents(String updated) {
String original = new String(getCurrent().getContents());
if (!updated.equals(original)) {
current = current.deepCopy(false);
String sha256 = new MessageDigestGenerator(MessageDigestGenerator.SHA_256).calcDigestString(updated);
current.setContents(updated, sha256);
markCurrentRawConfigUIBeanModified();
getModified().put(current.getPath(), current);
}
}
private void markCurrentRawConfigUIBeanModified() {
RawConfigUIBean bean = findRawConfigUIBeanByPath(current.getPath());
if (bean != null) {
// bean.setModified(true);
}
}
private RawConfigUIBean findRawConfigUIBeanByPath(String path) {
for (RawConfigDirectory dir : rawConfigDirectories) {
for (RawConfigUIBean bean : dir.getRawConfigUIBeans()) {
if (bean.getPath().equals(current.getPath())) {
return bean;
}
}
}
return null;
}
public void setCurrentPath(String path) {
RawConfiguration raw = getModified().get(path);
if (null == raw) {
raw = getRaws().get(path);
}
if (null != raw) {
current = raw;
}
}
public void setModified(RawConfiguration raw) {
getModified().put(raw.getPath(), raw);
}
public String download() {
try {
File file = new File(getCurrentPath());
HttpServletResponse response = FacesContextUtility.getResponse();
response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
OutputStream ostream = response.getOutputStream();
ostream.write(getCurrentContents().getBytes());
ostream.flush();
ostream.close();
FacesContextUtility.getFacesContext().responseComplete();
return null;
} catch (IOException e) {
log.error("Failed to complete download request for " + getCurrentPath(), e);
throw new RuntimeException(e);
}
}
/**
* This is a no-op, since the completeUpload work was done by completeUpload file
* But is kept as a target for the "save" icon from the full screen page
*/
public String update() {
return "/rhq/resource/configuration/edit-raw.xhtml?currentResourceId=" + getResourceId();
}
public String completeUpload() {
try {
if (fileUploader.getFileItem() != null) {
UploadItem fileItem = fileUploader.getFileItem();
if (fileItem.isTempFile()) {
setCurrentContents(FileUtils.readFileToString(fileItem.getFile()));
} else {
setCurrentContents(new String(fileItem.getData()));
}
fileUploader.clear();
}
return null;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
void dumpProperties(Configuration conf, Log log) {
for (String key : conf.getAllProperties().keySet()) {
log.error("property=" + conf.getAllProperties().get(key));
}
}
void populateRaws() {
Collection<RawConfiguration> rawConfigurations = getConfiguration().getRawConfigurations();
for (RawConfiguration raw : rawConfigurations) {
raws.put(raw.getPath(), raw);
}
}
public void setRaws(TreeMap<String, RawConfiguration> raws) {
this.raws = raws;
}
public TreeMap<String, RawConfiguration> getRaws() {
if (null == raws) {
raws = new TreeMap<String, RawConfiguration>();
populateRaws();
}
return raws;
}
String selectedPath;
private TreeMap<String, RawConfiguration> raws;
TreeMap<String, RawConfiguration> modified = new TreeMap<String, RawConfiguration>();
RawConfiguration current = null;
}