/*
* Copyright 2010 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.optaplanner.examples.cloudbalancing.swingui;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.optaplanner.examples.cloudbalancing.domain.CloudBalance;
import org.optaplanner.examples.cloudbalancing.domain.CloudComputer;
import org.optaplanner.examples.cloudbalancing.domain.CloudProcess;
import org.optaplanner.examples.cloudbalancing.optional.realtime.AddComputerProblemFactChange;
import org.optaplanner.examples.cloudbalancing.optional.realtime.AddProcessProblemFactChange;
import org.optaplanner.examples.cloudbalancing.optional.realtime.DeleteComputerProblemFactChange;
import org.optaplanner.examples.cloudbalancing.optional.realtime.DeleteProcessProblemFactChange;
import org.optaplanner.examples.common.swingui.SolutionPanel;
import org.optaplanner.examples.common.swingui.components.LabeledComboBoxRenderer;
import org.optaplanner.swing.impl.SwingUtils;
public class CloudBalancingPanel extends SolutionPanel<CloudBalance> {
public static final String LOGO_PATH = "/org/optaplanner/examples/cloudbalancing/swingui/cloudBalancingLogo.png";
private final ImageIcon cloudComputerIcon;
private final ImageIcon addCloudComputerIcon;
private final ImageIcon deleteCloudComputerIcon;
private final ImageIcon cloudProcessIcon;
private final ImageIcon addCloudProcessIcon;
private final ImageIcon deleteCloudProcessIcon;
private JPanel computersPanel;
private CloudComputerPanel unassignedPanel;
private Map<CloudComputer, CloudComputerPanel> computerToPanelMap;
private int maximumComputerCpuPower;
private int maximumComputerMemory;
private int maximumComputerNetworkBandwidth;
public CloudBalancingPanel() {
cloudComputerIcon = new ImageIcon(getClass().getResource("cloudComputer.png"));
addCloudComputerIcon = new ImageIcon(getClass().getResource("addCloudComputer.png"));
deleteCloudComputerIcon = new ImageIcon(getClass().getResource("deleteCloudComputer.png"));
cloudProcessIcon = new ImageIcon(getClass().getResource("cloudProcess.png"));
addCloudProcessIcon = new ImageIcon(getClass().getResource("addCloudProcess.png"));
deleteCloudProcessIcon = new ImageIcon(getClass().getResource("deleteCloudProcess.png"));
GroupLayout layout = new GroupLayout(this);
setLayout(layout);
JPanel headerPanel = createHeaderPanel();
JPanel computersPanel = createComputersPanel();
layout.setHorizontalGroup(layout.createParallelGroup()
.addComponent(headerPanel).addComponent(computersPanel));
layout.setVerticalGroup(layout.createSequentialGroup()
.addComponent(headerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE)
.addComponent(computersPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE));
}
public ImageIcon getCloudComputerIcon() {
return cloudComputerIcon;
}
public ImageIcon getAddCloudComputerIcon() {
return addCloudComputerIcon;
}
public ImageIcon getDeleteCloudComputerIcon() {
return deleteCloudComputerIcon;
}
public ImageIcon getCloudProcessIcon() {
return cloudProcessIcon;
}
public ImageIcon getAddCloudProcessIcon() {
return addCloudProcessIcon;
}
public ImageIcon getDeleteCloudProcessIcon() {
return deleteCloudProcessIcon;
}
public int getMaximumComputerCpuPower() {
return maximumComputerCpuPower;
}
public int getMaximumComputerMemory() {
return maximumComputerMemory;
}
public int getMaximumComputerNetworkBandwidth() {
return maximumComputerNetworkBandwidth;
}
private JPanel createHeaderPanel() {
JPanel headerPanel = new JPanel(new GridLayout(0, 5));
JPanel addPanel = new JPanel(new GridLayout());
JButton addComputerButton = SwingUtils.makeSmallButton(new JButton(addCloudComputerIcon));
addComputerButton.setToolTipText("Add computer");
addComputerButton.addActionListener(e -> {
CloudComputer computer = new CloudComputer();
computer.setCpuPower(12);
computer.setMemory(32);
computer.setNetworkBandwidth(12);
computer.setCost(400 + 400 + 600);
addComputer(computer);
});
addPanel.add(addComputerButton);
JButton addProcessButton = SwingUtils.makeSmallButton(new JButton(addCloudProcessIcon));
addProcessButton.setToolTipText("Add process");
addProcessButton.addActionListener(e -> {
CloudProcess process = new CloudProcess();
process.setRequiredCpuPower(3);
process.setRequiredMemory(8);
process.setRequiredNetworkBandwidth(3);
addProcess(process);
});
addPanel.add(addProcessButton);
JPanel cornerPanel = new JPanel(new BorderLayout());
cornerPanel.add(addPanel, BorderLayout.EAST);
headerPanel.add(cornerPanel);
JLabel cpuPowerLabel = new JLabel("CPU power");
headerPanel.add(cpuPowerLabel);
JLabel memoryLabel = new JLabel("Memory");
headerPanel.add(memoryLabel);
JLabel networkBandwidthLabel = new JLabel("Network bandwidth");
headerPanel.add(networkBandwidthLabel);
JLabel costLabel = new JLabel("Cost");
headerPanel.add(costLabel);
return headerPanel;
}
private JPanel createComputersPanel() {
computersPanel = new JPanel(new GridLayout(0, 1));
computerToPanelMap = new LinkedHashMap<>();
return computersPanel;
}
@Override
public void resetPanel(CloudBalance cloudBalance) {
maximumComputerCpuPower = 0;
maximumComputerMemory = 0;
maximumComputerNetworkBandwidth = 0;
for (CloudComputer computer : cloudBalance.getComputerList()) {
if (computer.getCpuPower() > maximumComputerCpuPower) {
maximumComputerCpuPower = computer.getCpuPower();
}
if (computer.getMemory() > maximumComputerMemory) {
maximumComputerMemory = computer.getMemory();
}
if (computer.getNetworkBandwidth() > maximumComputerNetworkBandwidth) {
maximumComputerNetworkBandwidth = computer.getNetworkBandwidth();
}
}
for (CloudComputerPanel computerPanel : computerToPanelMap.values()) {
if (computerPanel.getComputer() != null) {
computersPanel.remove(computerPanel);
}
}
computerToPanelMap.clear();
computersPanel.removeAll();
unassignedPanel = new CloudComputerPanel(this, null);
computersPanel.add(unassignedPanel);
computerToPanelMap.put(null, unassignedPanel);
updatePanel(cloudBalance);
}
@Override
public void updatePanel(CloudBalance cloudBalance) {
Set<CloudComputer> deadCloudComputerSet = new LinkedHashSet<>(computerToPanelMap.keySet());
deadCloudComputerSet.remove(null);
for (CloudComputer computer : cloudBalance.getComputerList()) {
deadCloudComputerSet.remove(computer);
CloudComputerPanel computerPanel = computerToPanelMap.get(computer);
if (computerPanel == null) {
computerPanel = new CloudComputerPanel(this, computer);
computersPanel.add(computerPanel);
computerToPanelMap.put(computer, computerPanel);
}
computerPanel.clearProcesses();
}
unassignedPanel.clearProcesses();
for (CloudProcess process : cloudBalance.getProcessList()) {
CloudComputer computer = process.getComputer();
CloudComputerPanel computerPanel = computerToPanelMap.get(computer);
computerPanel.addProcess(process);
}
for (CloudComputer deadComputer : deadCloudComputerSet) {
CloudComputerPanel deadComputerPanel = computerToPanelMap.remove(deadComputer);
computersPanel.remove(deadComputerPanel);
}
for (CloudComputerPanel computerPanel : computerToPanelMap.values()) {
computerPanel.update();
}
// If computersPanel.add() or computersPanel.remove() was called, the component needs to be validated.
computersPanel.validate();
}
public void addComputer(final CloudComputer computer) {
logger.info("Scheduling addition of computer ({}).", computer);
doProblemFactChange(new AddComputerProblemFactChange(computer));
}
public void deleteComputer(final CloudComputer computer) {
logger.info("Scheduling delete of computer ({}).", computer);
doProblemFactChange(new DeleteComputerProblemFactChange(computer));
}
public void addProcess(final CloudProcess process) {
logger.info("Scheduling addition of process ({}).", process);
doProblemFactChange(new AddProcessProblemFactChange(process));
}
public void deleteProcess(final CloudProcess process) {
logger.info("Scheduling delete of process ({}).", process);
doProblemFactChange(new DeleteProcessProblemFactChange(process));
}
public JButton createButton(CloudProcess process) {
return SwingUtils.makeSmallButton(new JButton(new CloudProcessAction(process)));
}
private class CloudProcessAction extends AbstractAction {
private CloudProcess process;
public CloudProcessAction(CloudProcess process) {
super(process.getLabel());
this.process = process;
}
@Override
public void actionPerformed(ActionEvent e) {
JPanel listFieldsPanel = new JPanel(new GridLayout(1, 2));
listFieldsPanel.add(new JLabel("Computer:"));
List<CloudComputer> computerList = getSolution().getComputerList();
// Add 1 to array size to add null, which makes the entity unassigned
JComboBox computerListField = new JComboBox(
computerList.toArray(new Object[computerList.size() + 1]));
LabeledComboBoxRenderer.applyToComboBox(computerListField);
computerListField.setSelectedItem(process.getComputer());
listFieldsPanel.add(computerListField);
int result = JOptionPane.showConfirmDialog(CloudBalancingPanel.this.getRootPane(), listFieldsPanel,
"Select computer", JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
CloudComputer toComputer = (CloudComputer) computerListField.getSelectedItem();
if (process.getComputer() != toComputer) {
solutionBusiness.doChangeMove(process, "computer", toComputer);
}
solverAndPersistenceFrame.resetScreen();
}
}
}
}