/* Copyright 2011 Massimo Gengarelli <gengarel@cs.unibo.it>
* This file is part of Floz Configurator.
* Floz Configurator 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, either version 3 of the License, or
* (at your option) any later version.
*
* Floz Configurator 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 Floz Configurator. If not, see http://www.gnu.org/licenses/.
*/
package it.unibo.cs.v2.client;
import it.unibo.cs.v2.servlets.CreateMachine;
import it.unibo.cs.v2.servlets.CreateMachineAsync;
import it.unibo.cs.v2.servlets.GetIsoList;
import it.unibo.cs.v2.servlets.GetIsoListAsync;
import it.unibo.cs.v2.shared.MachineInfo;
import java.util.HashMap;
import java.util.LinkedList;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextBox;
public class NewMachineWizard extends HTMLPanel implements AsyncCallback<LinkedList<HashMap<String, String>>>, ClickHandler, Wizard {
private final GetIsoListAsync getIsoListProxy = (GetIsoListAsync) GWT.create(GetIsoList.class);
private final CreateMachineAsync createMachineProxy = (CreateMachineAsync) GWT.create(CreateMachine.class);
private final ListBox isoListBox = new ListBox();
private final Button submitButton = new Button("Create");
private final DisclosurePanel description = new DisclosurePanel("Image Description");
private final HTML descriptionLabel = new HTML();
private final HTML errorLabel = new HTML();
private LinkedList<HashMap<String, String>> isos;
/* stuff for the new machine */
private final TextBox name = new TextBox();
private final TextBox descriptionVM = new TextBox();
/* buttons for the two disks */
private final String rb1group = "rb1group";
private final String rb2group = "rb2group";
private final RadioButton rb12 = new RadioButton(rb1group, "2GB");
private final RadioButton rb14 = new RadioButton(rb1group, "4GB");
private final RadioButton rb18 = new RadioButton(rb1group, "8GB");
private final RadioButton rb116 = new RadioButton(rb1group, "16GB");
private final RadioButton[] rb1 = new RadioButton[] {rb12, rb14, rb18, rb116};
private final TextBox disk2name = new TextBox();
private final CheckBox secondDisk = new CheckBox("Enable the second disk");
private final RadioButton rb22 = new RadioButton(rb2group, "2GB");
private final RadioButton rb24 = new RadioButton(rb2group, "4GB");
private final RadioButton rb28 = new RadioButton(rb2group, "8GB");
private final RadioButton rb216 = new RadioButton(rb2group, "16GB");
private final RadioButton[] rb2 = new RadioButton[] {rb22, rb24, rb28, rb216};
/* networking stuff */
private final CheckBox virtuaCluster = new CheckBox("Connect to the VirtuaCluster");
private final CheckBox addNetworkIf = new CheckBox("Create a secondary network interface");
private final TextBox socketName = new TextBox();
private final TextBox secondMacAddr = new TextBox();
private boolean finished = false;
public NewMachineWizard() {
super("<h2>New machine wizard</h2>");
getIsoListProxy.getIsoList(this);
submitButton.addClickHandler(this);
description.setContent(descriptionLabel);
description.setAnimationEnabled(true);
/**
* Show a description of the selected ISO.
*/
isoListBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
String imageName = isoListBox.getValue(isoListBox.getSelectedIndex());
for (HashMap<String, String> h : isos) {
if (!h.get("name").equals(imageName))
continue;
else
descriptionLabel.setHTML("<b>" + h.get("name") + " " + h.get("version") + "</b><br />" +
h.get("description") + "<br />" +
"<a href=\"" + h.get("web") + "\">Visit the official website</a>" + "<br />" +
"The file is located at: " + h.get("iso"));
}
}
});
/***
* Basic stuff (iso image, name and description)
*/
add(new HTML("<h3>Basic settings</h3>"));
FlexTable table = new FlexTable();
table.setWidget(0, 0, new HTML("Select the installation disc for your VM: "));
table.setWidget(0, 1, isoListBox);
add(table);
add(description);
table = new FlexTable();
table.setWidget(0, 0, new HTML("Choose a name for your new VM: "));
table.setWidget(0, 1, name);
table.setWidget(1, 0, new HTML("Enter a one-line description of it: "));
table.setWidget(1, 1, descriptionVM);
add(table);
/***
* Storage (hard disks)
*/
add(new HTML("<h3>Storage settings</h3>"));
add(secondDisk);
table = new FlexTable();
table.setWidget(1, 0, new HTML("Choose a size for the primary disk: "));
HorizontalPanel tempHP = new HorizontalPanel();
tempHP.add(rb12);
tempHP.add(rb14);
tempHP.add(rb18);
tempHP.add(rb116);
table.setWidget(1, 1, tempHP);
table.setWidget(3, 0, new HTML("Choose a size for the secondary disk<span style=\"color: pink;\">*</span>: "));
tempHP = new HorizontalPanel();
tempHP.add(rb22);
tempHP.add(rb24);
tempHP.add(rb28);
tempHP.add(rb216);
table.setWidget(3, 1, tempHP);
add(table);
secondDisk.setValue(false);
/**
* by default, the secondary disk is not enabled
*/
disk2name.setEnabled(false);
rb22.setEnabled(false);
rb24.setEnabled(false);
rb28.setEnabled(false);
rb216.setEnabled(false);
rb18.setValue(true);
rb28.setValue(true);
secondDisk.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
disk2name.setEnabled(secondDisk.getValue());
rb22.setEnabled(secondDisk.getValue());
rb24.setEnabled(secondDisk.getValue());
rb28.setEnabled(secondDisk.getValue());
rb216.setEnabled(secondDisk.getValue());
}
});
table = new FlexTable();
add(new HTML("<h3>Networking</h3>"));
table = new FlexTable();
table.setWidget(0, 0, virtuaCluster);
table.setWidget(1, 0, addNetworkIf);
table.setWidget(2, 0, new HTML("Macaddress for the network interface<span style=\"color: red;\">*</span>: "));
table.setWidget(2, 1, secondMacAddr);
table.setWidget(3, 0, new HTML("Relative path for the new socket<span style=\"color: blue;\">*</span>: "));
table.setWidget(3, 1, socketName);
virtuaCluster.setValue(true);
addNetworkIf.setValue(false);
secondMacAddr.setEnabled(false);
socketName.setEnabled(false);
addNetworkIf.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
secondMacAddr.setEnabled(addNetworkIf.getValue());
socketName.setEnabled(addNetworkIf.getValue());
}
});
add(table);
add(new HTML("<h3>Notes</h3>"));
add(new HTML("<span style=\"color: red;\">* </span>Leave blank to use the QEMU's default one."));
add(new HTML("<span style=\"color: blue;\">* </span>Will be created in your home."));
add(new HTML("<span style=\"color: pink;\">* </span>Extension '.img' will be automatically added."));
add(errorLabel);
add(submitButton);
}
public void updateList() {
getIsoListProxy.getIsoList(this);
}
@Override
public void onFailure(Throwable caught) {
DialogBox errorDialog = new DialogBox();
errorDialog.setAnimationEnabled(true);
errorDialog.setWidget(new HTML("An error occured while querying the RPC server, please refresh the page."));
errorDialog.show();
}
@Override
public void onSuccess(LinkedList<HashMap<String, String>> result) {
this.isos = result;
isoListBox.clear();
// No isos found on the server.
if (result == null) {
descriptionLabel.setHTML("No images found on the server.");
submitButton.setEnabled(false);
return;
}
// Everything seems ok.
for (HashMap<String, String> h : result)
isoListBox.addItem(h.get("name"));
descriptionLabel.setHTML("Select an image to show its description!");
submitButton.setEnabled(true);
}
private void showSuccess(String msg) {
errorLabel.getElement().getStyle().setColor("green");
errorLabel.getElement().getStyle().setFontSize(1.4, Unit.EM);
errorLabel.setHTML(msg);
errorLabel.setVisible(true);
}
private void showError(String error) {
errorLabel.getElement().getStyle().setColor("red");
errorLabel.getElement().getStyle().setFontSize(1.4, Unit.EM);
errorLabel.setHTML(error);
errorLabel.setVisible(true);
}
private void hideError() {
errorLabel.setVisible(false);
}
@Override
public void onClick(ClickEvent event) {
final MachineInfo machineInfo = new MachineInfo();
hideError();
if (RegExp.compile("[^A-z0-9]").test(name.getText())) {
showError("Machine name may only contain letters or digits (e.g. MyFirstMachine01)");
return;
}
if (name.getText().equals("")) {
showError("Machine name can't be blank");
return;
}
machineInfo.setName(name.getText());
machineInfo.setDescription(descriptionVM.getText());
for (HashMap<String, String> hm : isos) {
if (hm.get("name").equals(isoListBox.getValue(isoListBox.getSelectedIndex()))) {
machineInfo.setIso(hm.get("iso"));
break;
}
}
//
// if (!disk1name.getText().equals(name.getText())) {
// showError("Primary disk name must match the machine's name.");
// return;
// }
//
machineInfo.setHda(name.getText());
for (RadioButton b : rb1) {
if (!b.getValue())
continue;
machineInfo.setHdaSize(b.getText());
}
// if (disk2name.isEnabled() && disk2name.getText().equals((""))) {
// showError("Disk name can't be blank");
// return;
// }
machineInfo.setHdbEnabled(disk2name.isEnabled());
if (disk2name.isEnabled()) {
machineInfo.setHdb(name.getText() + "-secondary");
for (RadioButton b: rb2) {
if (!b.getValue())
continue;
machineInfo.setHdbSize(b.getText());
}
}
machineInfo.setVirtuacluster(virtuaCluster.getValue());
machineInfo.setSecondNetwork(addNetworkIf.getValue());
if (addNetworkIf.getValue() && socketName.getText().equals("")) {
showError("Socket name can't be blank");
return;
}
machineInfo.setSocketPath(socketName.getText());
machineInfo.setMacAddress(secondMacAddr.getText());
createMachineProxy.createMachine(machineInfo, new AsyncCallback<Boolean>() {
@Override
public void onFailure(Throwable caught) {
Window.alert(caught.getMessage());
}
@Override
public void onSuccess(Boolean result) {
clear();
add(errorLabel);
if (result) {
showSuccess("Machine successfully created");
finished = true;
MainPanel.getInstance().refresh();
}
else
showError("Error while creating the machine. This is programmers' fault, not yours. " +
"Please reload the page and retry.");
}
});
}
public boolean hasFinished() {
return finished;
}
}