/*
* 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.coregui.client.inventory.groups.detail.configuration;
import static java.util.EnumSet.of;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.widgets.IButton;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.composite.ResourceConfigurationComposite;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.domain.resource.ResourceAncestryFormat;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.resource.composite.ResourcePermission;
import org.rhq.core.domain.resource.group.ResourceGroup;
import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite;
import org.rhq.core.domain.util.ResourceTypeUtility;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.LinkManager;
import org.rhq.coregui.client.RefreshableView;
import org.rhq.coregui.client.components.configuration.ConfigurationEditor;
import org.rhq.coregui.client.components.configuration.GroupConfigurationEditor;
import org.rhq.coregui.client.components.configuration.GroupMemberConfiguration;
import org.rhq.coregui.client.components.configuration.PropertyValueChangeEvent;
import org.rhq.coregui.client.components.configuration.PropertyValueChangeListener;
import org.rhq.coregui.client.gwt.ConfigurationGWTServiceAsync;
import org.rhq.coregui.client.gwt.GWTServiceLookup;
import org.rhq.coregui.client.inventory.resource.detail.ResourceDetailView;
import org.rhq.coregui.client.inventory.resource.type.ResourceTypeRepository;
import org.rhq.coregui.client.util.enhanced.EnhancedIButton;
import org.rhq.coregui.client.util.enhanced.EnhancedIButton.ButtonColor;
import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;
import org.rhq.coregui.client.util.message.Message;
import org.rhq.coregui.client.util.message.MessageCenter;
/**
* A view for editing a group's configuration.
*
* @author Ian Springer
*/
public class GroupResourceConfigurationEditView extends EnhancedVLayout implements PropertyValueChangeListener,
RefreshableView {
private final ConfigurationGWTServiceAsync configurationService = GWTServiceLookup.getConfigurationService();
private ResourceGroup group;
private ResourcePermission resourcePermission;
private ConfigurationDefinition configurationDefinition;
private List<GroupMemberConfiguration> memberConfigurations;
private ToolStrip buttonbar;
private ConfigurationEditor editor;
private IButton saveButton;
private boolean refreshing = false;
public GroupResourceConfigurationEditView(ResourceGroupComposite groupComposite) {
super();
this.group = groupComposite.getResourceGroup();
this.resourcePermission = groupComposite.getResourcePermission();
}
@Override
protected void onDraw() {
super.onDraw();
refresh();
if (!this.resourcePermission.isConfigureWrite()) {
Message message = new Message(MSG.view_group_resConfig_edit_noperm(), Message.Severity.Info, of(
Message.Option.Transient, Message.Option.Sticky));
CoreGUI.getMessageCenter().notify(message);
}
}
private ToolStrip createButtonBar() {
this.buttonbar = new ToolStrip();
buttonbar.setWidth100();
buttonbar.setExtraSpace(10);
buttonbar.setMembersMargin(5);
buttonbar.setLayoutMargin(5);
this.saveButton = new EnhancedIButton(MSG.common_button_save(), ButtonColor.BLUE);
this.saveButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent clickEvent) {
save();
}
});
this.saveButton.disable();
buttonbar.addMember(saveButton);
return buttonbar;
}
@Override
public void refresh() {
if (this.refreshing) {
return; // we are already in the process of refreshing, don't do it again
}
this.refreshing = true;
if (editor != null) {
editor.destroy();
removeMember(editor);
buttonbar.destroy();
removeMember(buttonbar);
}
// TODO (ips): If editor != null, use editor.reload() instead.
loadConfigurationDefinition();
loadConfigurations();
}
private void initEditor() {
if (this.configurationDefinition != null && this.memberConfigurations != null) {
this.editor = new GroupConfigurationEditor(this.configurationDefinition, this.memberConfigurations);
this.editor.setOverflow(Overflow.AUTO);
this.editor.addPropertyValueChangeListener(this);
this.editor.setReadOnly(!this.resourcePermission.isConfigureWrite());
addMember(this.editor);
addMember(createButtonBar());
this.refreshing = false; // when we get here, we know we are done the refresh
}
}
private void loadConfigurationDefinition() {
if (this.configurationDefinition == null) {
final ResourceType type = this.group.getResourceType();
ResourceTypeRepository.Cache.getInstance().getResourceTypes(new Integer[] { type.getId() },
of(ResourceTypeRepository.MetadataType.resourceConfigurationDefinition),
new ResourceTypeRepository.TypesLoadedCallback() {
public void onTypesLoaded(Map<Integer, ResourceType> types) {
configurationDefinition = types.get(type.getId()).getResourceConfigurationDefinition();
if (configurationDefinition == null) {
throw new IllegalStateException("Configuration is not supported by this group.");
}
initEditor();
}
});
}
}
private void loadConfigurations() {
this.memberConfigurations = null;
this.configurationService.findResourceConfigurationsForGroup(group.getId(),
new AsyncCallback<Map<Integer, Configuration>>() {
public void onFailure(Throwable caught) {
handleLoadFailure(caught);
}
public void onSuccess(final Map<Integer, Configuration> configMap) {
final Integer[] resourceIds = configMap.keySet().toArray(new Integer[configMap.size()]);
GWTServiceLookup.getResourceService().getResourcesAncestry(resourceIds,
ResourceAncestryFormat.EXTENDED, new AsyncCallback<Map<Integer, String>>() {
public void onFailure(Throwable caught) {
handleLoadFailure(caught);
}
public void onSuccess(Map<Integer, String> labelMap) {
memberConfigurations = new ArrayList<GroupMemberConfiguration>(configMap.size());
for (Integer resourceId : resourceIds) {
String label = labelMap.get(resourceId);
Configuration configuration = configMap.get(resourceId);
GroupMemberConfiguration memberConfiguration = new GroupMemberConfiguration(
resourceId, label, configuration);
if (configuration == null || configuration.getProperties().isEmpty()) {
throw new RuntimeException(
"The server did not return the configuration for one or more member resources.");
}
memberConfigurations.add(memberConfiguration);
}
initEditor();
}
});
}
});
}
private void handleLoadFailure(Throwable caught) {
refreshing = false;
if (caught.getMessage().contains("ConfigurationUpdateStillInProgressException")) {
final String msg = MSG.view_group_resConfig_edit_loadFail(group.toString());
CoreGUI.getMessageCenter().notify(new Message(msg, Message.Severity.Warning));
} else {
CoreGUI.getErrorHandler().handleError(MSG.view_group_resConfig_edit_loadFail(group.toString()), caught);
}
}
private void save() {
List<ResourceConfigurationComposite> resourceConfigurations = convertToCompositeList();
GWTServiceLookup.getConfigurationService().updateResourceConfigurationsForGroup(this.group.getId(),
resourceConfigurations, new AsyncCallback<Void>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(
MSG.view_group_resConfig_edit_saveFailure(
ResourceTypeUtility.displayName(group.getResourceType()), group.getName()),
caught);
}
public void onSuccess(Void result) {
String configHistoryUrl = LinkManager.getEntityTabLink(EntityContext.forGroup(group),
ResourceDetailView.Tab.Configuration.NAME,
ResourceDetailView.Tab.Configuration.SubTab.HISTORY);
String configHistoryView = configHistoryUrl.substring(1); // chop off the leading '#'
Message message = new Message(MSG.view_group_resConfig_edit_saveInitiated_concise(), MSG
.view_group_resConfig_edit_saveInitiated_full(
ResourceTypeUtility.displayName(group.getResourceType()),
group.getName()), Message.Severity.Info);
CoreGUI.goToView(configHistoryView, message);
}
});
}
private List<ResourceConfigurationComposite> convertToCompositeList() {
List<ResourceConfigurationComposite> resourceConfigurations = new ArrayList<ResourceConfigurationComposite>(
this.memberConfigurations.size());
for (GroupMemberConfiguration memberConfiguration : this.memberConfigurations) {
resourceConfigurations.add(new ResourceConfigurationComposite(memberConfiguration.getId(),
memberConfiguration.getConfiguration()));
}
return resourceConfigurations;
}
@Override
public void propertyValueChanged(PropertyValueChangeEvent event) {
MessageCenter messageCenter = CoreGUI.getMessageCenter();
Message message;
if (event.isInvalidPropertySetChanged()) {
Map<String, String> invalidPropertyNames = event.getInvalidPropertyNames();
if (invalidPropertyNames.isEmpty()) {
this.saveButton.enable();
message = new Message(MSG.view_group_resConfig_edit_valid(), Message.Severity.Info, EnumSet.of(
Message.Option.Transient, Message.Option.Sticky));
} else {
this.saveButton.disable();
message = new Message(MSG.view_group_resConfig_edit_invalid(invalidPropertyNames.values().toString()),
Message.Severity.Error, EnumSet.of(Message.Option.Transient, Message.Option.Sticky));
}
messageCenter.notify(message);
} else if (event.getInvalidPropertyNames().isEmpty()) {
this.saveButton.enable();
} else {
this.saveButton.disable();
}
}
}