package org.openslx.dozmod.gui.window; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.TreeSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openslx.dozmod.gui.Gui; import org.openslx.dozmod.gui.helper.I18n; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.gui.helper.TextChangeListener; import org.openslx.dozmod.gui.helper.UiFeedback; import org.openslx.dozmod.gui.window.layout.VirtConfigEditorWindowLayout; import org.openslx.dozmod.thrift.ImageDetailsActions; import org.openslx.dozmod.thrift.ImageDetailsActions.VirtConfCallback; import org.openslx.dozmod.thrift.cache.MetaDataCache; import org.openslx.util.XmlHelper; import org.openslx.virtualization.configuration.VirtualizationConfiguration; import org.openslx.virtualization.configuration.VirtualizationConfigurationException; import org.openslx.virtualization.configuration.VirtualizationConfigurationVirtualBox; import org.openslx.virtualization.configuration.VirtualizationConfigurationVmwareFileFormat; public class VirtConfigEditorWindow extends VirtConfigEditorWindowLayout implements UiFeedback { /** * Version for serialization. */ private static final long serialVersionUID = 8416526255408870346L; private final static Logger LOGGER = LogManager.getLogger(VirtConfigEditorWindow.class); public interface VirtConfigChanged { public void virtConfigChanged(String newVmx); } private final String imageVersionId; private final String originalMachineDescription; private final VirtConfigEditorWindow me = this; private final ImageDetailsActions actionHandler; private boolean configWasSaved = false; protected VirtConfigEditorWindow(Window modalParent, final ImageDetailsActions actionHandler, final String imageVersionId, final String currentMachineDescription, final String originalmachineDescription) { super(modalParent); this.actionHandler = actionHandler; this.imageVersionId = imageVersionId; // listener for the text fields pnlEditor.getDocument().addDocumentListener(new TextChangeListener() { @Override public void changed() { btnSave.setEnabled(!originalMachineDescription.equals(pnlEditor.getText())); } }); btnSave.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { saveClicked(); } }); btnCancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { safeClose(); } }); this.originalMachineDescription = originalmachineDescription; pnlEditor.setText(currentMachineDescription); pnlEditor.setCaretPosition(0); } private void saveClicked() { // we make use of the fact that we saved the BB here! final String userInput = pnlEditor.getText(); byte[] uiBytes = userInput.getBytes(StandardCharsets.ISO_8859_1); Charset cs = VirtualizationConfigurationVmwareFileFormat.getCharset(uiBytes, uiBytes.length); // VMware: cs is now either the detected encoding, or latin1 as a default // Other: Should be null, so let's go with UTF-8 if (cs == null) { cs = StandardCharsets.UTF_8; } uiBytes = userInput.getBytes(cs); // now we should have the correct bytes... VirtualizationConfiguration virtualizationConfig = null; try { virtualizationConfig = VirtualizationConfiguration.getInstance(MetaDataCache.getOperatingSystems(), uiBytes, uiBytes.length); } catch (IOException | VirtualizationConfigurationException e) { LOGGER.error("Could not get VmMetaData instance from given machine description: ", e); } if (virtualizationConfig == null) { dispose(); return; } byte[] uiBytesFiltered = virtualizationConfig.getConfigurationAsByteArray(); final String userInputFiltered; // TODO: This is ugly, why is there instanceof stuff here, add a method to VmMetaData!? if (virtualizationConfig instanceof VirtualizationConfigurationVirtualBox) { userInputFiltered = XmlHelper.getFormattedXml(new ByteArrayInputStream(uiBytesFiltered)); } else { userInputFiltered = new String(uiBytesFiltered, cs); } // So here we have: // - uiBytes is the unfiltered user input // - uiBytesFiltered is the user input filtered by VmwareMetaData TreeSet unfilteredSet = stringToTreeSet(userInput); TreeSet filteredSet = stringToTreeSet(userInputFiltered); if (!filteredSet.equals(unfilteredSet)) { unfilteredSet.removeAll(filteredSet); // not equals, means there was some invalid input String errorText = I18n.WINDOW.getString("VirtConfigEditor.Message.error.invalidInputTitle"); for (String s : unfilteredSet) { errorText += s + "\n"; } // TODO: Somehow this always triggers for vbox errorText += System.lineSeparator() + I18n.WINDOW.getString("VirtConfigEditor.Message.error.invalidInputText"); if (!Gui.showMessageBox(errorText, MessageType.ERROR_RETRY, LOGGER, null)) return; } ByteBuffer toSave; if (virtualizationConfig instanceof VirtualizationConfigurationVirtualBox) { String unformattedInput = XmlHelper.getUnformattedXml(new ByteArrayInputStream(uiBytesFiltered)); toSave = ByteBuffer.wrap(unformattedInput.getBytes(cs)); } else { toSave = ByteBuffer.wrap(uiBytesFiltered); } // we have a valid virtualization configuration or the user accepted to push the filtered input actionHandler.setVirtualizerConfig(imageVersionId, toSave, new VirtConfCallback() { @Override public void virtConfCallback(boolean success) { if (success) { configWasSaved = true; dispose(); } } }); } private TreeSet stringToTreeSet(final String s) { String[] split = s.split("[\\r\\n]+"); List splitList = new ArrayList(Arrays.asList(split)); splitList.removeAll(Arrays.asList("", null)); TreeSet set = new TreeSet(splitList); return set; } public static boolean open(Window modalParent, final ImageDetailsActions handler, final String imageVersionId, final String currentmachineDescription, final String originalMachineDescription) { VirtConfigEditorWindow win = new VirtConfigEditorWindow(modalParent, handler, imageVersionId, currentmachineDescription, originalMachineDescription); win.setVisible(true); return win.configWasSaved; } private void safeClose() { if (originalMachineDescription.equals(pnlEditor.getText()) || Gui.showMessageBox(me, I18n.WINDOW.getString("VirtConfigEditor.Message.yesNo.safeClose"), MessageType.QUESTION_YESNO, null, null)) dispose(); } @Override public boolean wantConfirmQuit() { return !originalMachineDescription.equals(pnlEditor.getText()); } @Override public void escapePressed() { safeClose(); } }