/*
* RHQ Management Platform
* Copyright (C) 2005-2014 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.coregui.client.admin.storage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.StaticTextItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.validator.IsIntegerValidator;
import com.smartgwt.client.widgets.form.validator.Validator;
import com.smartgwt.client.widgets.layout.LayoutSpacer;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import org.rhq.core.domain.cloud.StorageNodeConfigurationComposite;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.coregui.client.CoreGUI;
import org.rhq.coregui.client.RefreshableView;
import org.rhq.coregui.client.components.form.EnhancedDynamicForm;
import org.rhq.coregui.client.components.form.ValueWithUnitsItem;
import org.rhq.coregui.client.gwt.GWTServiceLookup;
import org.rhq.coregui.client.util.enhanced.EnhancedIButton;
import org.rhq.coregui.client.util.enhanced.EnhancedToolStrip;
import org.rhq.coregui.client.util.enhanced.EnhancedVLayout;
import org.rhq.coregui.client.util.message.Message;
/**
* The component for editing the storage node configuration
*
* @author Jirka Kremser
*/
public class StorageNodeConfigurationEditor extends EnhancedVLayout implements RefreshableView {
private EnhancedDynamicForm form;
private EnhancedIButton saveButton;
private boolean oddRow;
private final StorageNodeConfigurationComposite configuration;
private static String FIELD_HEAP_MAX = "heap_max";
private static String FIELD_HEAP_NEW = "heap_new";
private static String FIELD_THREAD_STACK_SIZE = "thread_stack_size";
private static String FIELD_JMX_PORT = "jmx_port";
private static String FIELD_COMMITLOG = "commitlog";
private static String FIELD_DATA = "data";
private static String FIELD_SAVED_CACHES = "saved-caches";
public StorageNodeConfigurationEditor(final StorageNodeConfigurationComposite configuration) {
super();
this.configuration = configuration;
}
private void save(final StorageNodeConfigurationComposite configuration) {
GWTServiceLookup.getStorageService().updateConfiguration(configuration, new AsyncCallback<Void>() {
public void onSuccess(Void result) {
Message msg = new Message(MSG.view_adminTopology_storageNodes_settings_message_updateSuccess(),
Message.Severity.Info);
CoreGUI.getMessageCenter().notify(msg);
}
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.view_adminTopology_storageNodes_clusterSettings_message_updateFail(), caught);
}
});
}
private List<FormItem> buildOneFormRowWithCombobox(String name, String title, String value, String description) {
return buildOneFormRow(name, title, value, description, true, null);
}
private List<FormItem> buildOneFormRowWithValidator(String name, String title, String value, String description,
Validator validator) {
return buildOneFormRow(name, title, value, description, false, validator);
}
private List<FormItem> buildOneFormRow(String name, String title, String value, String description,
boolean unitsDropdown, Validator validator) {
List<FormItem> fields = new ArrayList<FormItem>();
StaticTextItem nameItem = new StaticTextItem();
nameItem.setStartRow(true);
nameItem.setValue("<b>" + title + "</b>");
nameItem.setShowTitle(false);
nameItem.setCellStyle(oddRow ? "OddRow" : "EvenRow");
fields.add(nameItem);
FormItem valueItem = null;
if (unitsDropdown) {
valueItem = buildJVMMemoryItem(name, value);
} else {
valueItem = new TextItem();
valueItem.setName(name);
valueItem.setValue(value);
valueItem.setWidth(220);
if (validator != null) {
valueItem.setValidators(validator);
}
}
valueItem.setValidateOnChange(true);
valueItem.setAlign(Alignment.CENTER);
valueItem.setShowTitle(false);
valueItem.setRequired(true);
valueItem.setCellStyle(oddRow ? "OddRow" : "EvenRow");
fields.add(valueItem);
StaticTextItem descriptionItem = new StaticTextItem();
descriptionItem.setValue(description);
descriptionItem.setShowTitle(false);
descriptionItem.setEndRow(true);
descriptionItem.setCellStyle(oddRow ? "OddRow" : "EvenRow");
fields.add(descriptionItem);
oddRow = !oddRow;
return fields;
}
private FormItem buildJVMMemoryItem(String name, String value) {
Set<MeasurementUnits> supportedUnits = new LinkedHashSet<MeasurementUnits>();
supportedUnits.add(MeasurementUnits.MEGABYTES);
supportedUnits.add(MeasurementUnits.GIGABYTES);
ValueWithUnitsItem valueItem = new ValueWithUnitsItem(name, null, supportedUnits);
if (value != null && !value.isEmpty()) {
boolean megs = value.trim().substring(value.trim().length() - 1).equalsIgnoreCase("m");
MeasurementUnits units = megs ? MeasurementUnits.MEGABYTES : MeasurementUnits.GIGABYTES;
try {
int intVal = Integer.parseInt(value.substring(0, value.toLowerCase().indexOf(megs ? "m" : "g")));
valueItem.setValue(intVal, units);
} catch (StringIndexOutOfBoundsException e) {
// do nothing
}
}
return valueItem;
}
private List<FormItem> buildHeaderItems() {
List<FormItem> fields = new ArrayList<FormItem>();
fields.add(createHeaderTextItem(MSG.view_configEdit_property()));
fields.add(createHeaderTextItem(MSG.common_title_value()));
fields.add(createHeaderTextItem(MSG.common_title_description()));
return fields;
}
private StaticTextItem createHeaderTextItem(String value) {
StaticTextItem unsetHeader = new StaticTextItem();
unsetHeader.setValue(value);
unsetHeader.setShowTitle(false);
unsetHeader.setCellStyle("configurationEditorHeaderCell");
return unsetHeader;
}
@Override
protected void onDraw() {
super.onDraw();
refresh();
}
@Override
public void refresh() {
form = new EnhancedDynamicForm();
form.setHiliteRequiredFields(true);
form.setNumCols(3);
form.setCellPadding(5);
form.setColWidths(190, 220, "*");
form.setIsGroup(true);
form.setGroupTitle(MSG.view_adminTopology_storageNodes_settings_specific());
oddRow = true;
List<FormItem> items = buildHeaderItems();
items
.addAll(buildOneFormRowWithCombobox(
FIELD_HEAP_MAX,
MSG.view_adminTopology_storageNodes_settings_heapSizeName(),
configuration.getHeapSize(),
MSG.view_adminTopology_storageNodes_settings_heapSizeDescription()));
items
.addAll(buildOneFormRowWithCombobox(
FIELD_HEAP_NEW,
MSG.view_adminTopology_storageNodes_settings_heapNewSizeName(),
configuration.getHeapNewSize(),
MSG.view_adminTopology_storageNodes_settings_heapNewSizeDescription()));
IsIntegerValidator validator = new IsIntegerValidator();
items.addAll(buildOneFormRowWithValidator(FIELD_THREAD_STACK_SIZE,
MSG.view_adminTopology_storageNodes_settings_threadStackSizeName(), configuration.getThreadStackSize(),
MSG.view_adminTopology_storageNodes_settings_threadStackSizeDescription(), validator));
validator = new IsIntegerValidator();
items.addAll(buildOneFormRowWithValidator(FIELD_JMX_PORT,
MSG.view_adminTopology_storageNodes_settings_jmxPortName(), String.valueOf(configuration.getJmxPort()),
MSG.view_adminTopology_storageNodes_settings_jmxPortDescription(), validator));
items.addAll(buildOneFormRowWithValidator(FIELD_COMMITLOG,
MSG.view_adminTopology_storageNodes_settings_commitLogLocationName(), configuration.getCommitLogLocation(),
MSG.view_adminTopology_storageNodes_settings_commitLogLocationDescription(), null));
List<String> dataLocations = configuration.getDataLocations();
if(dataLocations != null && dataLocations.size() == 1) {
// Since we don't support more than one data directory, don't show if user has overriden our defaults
items.addAll(buildOneFormRowWithValidator(FIELD_DATA,
MSG.view_adminTopology_storageNodes_settings_dataFilesLocationName(), dataLocations.get(0),
MSG.view_adminTopology_storageNodes_settings_dataFilesLocationDescription(), null));
}
items.addAll(buildOneFormRowWithValidator(FIELD_SAVED_CACHES,
MSG.view_adminTopology_storageNodes_settings_savedCachesLocationName(), configuration.getSavedCachesLocation(),
MSG.view_adminTopology_storageNodes_settings_savedCachesLocationDescription(), null));
form.setFields(items.toArray(new FormItem[items.size()]));
form.setWidth100();
form.setOverflow(Overflow.VISIBLE);
setWidth100();
LayoutSpacer spacer = new LayoutSpacer();
spacer.setWidth100();
ToolStrip toolStrip = buildToolStrip();
setMembers(form, spacer, toolStrip);
form.validate();
markForRedraw();
}
private EnhancedToolStrip buildToolStrip() {
saveButton = new EnhancedIButton(MSG.common_button_save());
saveButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent clickEvent) {
if (form.validate()) {
if (!checkNewHeapLowerThanMaxHeap()) {
Map<String, String> errors = new HashMap<String, String>(2);
errors.put(FIELD_HEAP_MAX, MSG.view_adminTopology_storageNodes_settings_validator1());
errors.put(FIELD_HEAP_NEW, MSG.view_adminTopology_storageNodes_settings_validator2());
form.setErrors(errors, true);
return;
}
final StorageNodeConfigurationComposite configuration = getConfiguration();
if (StorageNodeConfigurationEditor.this.configuration.equals(configuration)) {
SC.say("Info", MSG.view_adminTopology_storageNodes_settings_noChanges());
} else {
SC.ask(
MSG.view_adminTopology_storageNodes_settings_confirmation(),
new BooleanCallback() {
@Override
public void execute(Boolean value) {
if (value) {
save(configuration);
}
}
});
}
}
}
});
EnhancedToolStrip toolStrip = new EnhancedToolStrip();
toolStrip.setWidth100();
toolStrip.setMembersMargin(5);
toolStrip.setLayoutMargin(5);
toolStrip.addMember(saveButton);
return toolStrip;
}
private StorageNodeConfigurationComposite getConfiguration() {
StorageNodeConfigurationComposite configuration = new StorageNodeConfigurationComposite(
this.configuration.getStorageNode());
configuration.setHeapSize(getJVMMemoryString(form.getField(FIELD_HEAP_MAX).getValue().toString()));
configuration.setHeapNewSize(getJVMMemoryString(form.getField(FIELD_HEAP_NEW).getValue().toString()));
configuration.setThreadStackSize(form.getValueAsString(FIELD_THREAD_STACK_SIZE));
configuration.setJmxPort(Integer.parseInt(form.getValueAsString(FIELD_JMX_PORT)));
configuration.setCommitLogLocation(form.getValueAsString(FIELD_COMMITLOG));
configuration.setSavedCachesLocation(form.getValueAsString(FIELD_SAVED_CACHES));
List<String> newDataLocations = new LinkedList<String>();
newDataLocations.add(form.getValueAsString(FIELD_DATA));
configuration.setDataLocations(newDataLocations);
return configuration;
}
private boolean checkNewHeapLowerThanMaxHeap() {
// let's be paranoid
Object maxHeapObject = form.getField(FIELD_HEAP_MAX).getValue();
Object newHeapObject = form.getField(FIELD_HEAP_NEW).getValue();
String maxHeapString = maxHeapObject != null ? maxHeapObject.toString().trim() : "";
String newHeapString = newHeapObject != null ? newHeapObject.toString().trim() : "";
if (maxHeapString.isEmpty() || newHeapString.isEmpty()) {
return false;
}
int maxHeap = Integer.parseInt(maxHeapString.substring(0, maxHeapString.length() - 2));
int newHeap = Integer.parseInt(newHeapString.substring(0, newHeapString.length() - 2));
boolean isMaxHeapInMegs = maxHeapString.toLowerCase().indexOf("m") != -1;
boolean isNewHeapInMegs = newHeapString.toLowerCase().indexOf("m") != -1;
maxHeap = isMaxHeapInMegs ? maxHeap : maxHeap * 1024;
newHeap = isNewHeapInMegs ? newHeap : newHeap * 1024;
return newHeap < maxHeap;
}
private String getJVMMemoryString(String raw) {
if (raw == null || raw.trim().isEmpty()) {
throw new IllegalArgumentException("input string is null or empty");
}
return raw.trim().substring(0, raw.trim().length() - 1);
}
}