package net.raymanoz.ui;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import net.raymanoz.command.MigrateCallBack;
import net.raymanoz.config.ApplicationProperties;
import net.raymanoz.config.ApplicationPropertiesImpl;
import net.raymanoz.config.Configuration;
import net.raymanoz.config.ConfigurationImpl;
import net.raymanoz.config.ScriptStatus;
import net.raymanoz.migrate.Script;
import net.raymanoz.migrate.UMigrate;
import net.raymanoz.util.FileUtil;
import net.raymanoz.util.FileUtilImpl;
import net.raymanoz.util.PlainProperties;
import net.raymanoz.util.Properties;
import net.raymanoz.util.StreamUtilImpl;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.Toolkit;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.JTextPane;
import javax.swing.JScrollPane;
import javax.swing.SwingWorker;
import javax.swing.border.TitledBorder;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JProgressBar;
import java.awt.CardLayout;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.swing.LayoutStyle.ComponentPlacement;
import java.awt.Component;
public class GUIInteractionStrategy implements UserInteractionStrategy {
private static final Log LOG = LogFactory.getLog(GUIInteractionStrategy.class);
private String message;
private MigrateCallBack migrateCallBack;
private Configuration config;
public GUIInteractionStrategy(Configuration config, String message) {
this.message = message;
this.config = config;
}
private JFrame frame;
/**
* Launch the application.
* @throws InterruptedException
*/
static Configuration defaultConfig(){
Properties uMigrateProperties = PlainProperties.createFromResource("uMigrate.properties");
ApplicationProperties applicationProperties = new ApplicationPropertiesImpl(uMigrateProperties);
FileUtil fileUtil = new FileUtilImpl(new StreamUtilImpl());
return new ConfigurationImpl(applicationProperties, fileUtil, uMigrateProperties);
}
public static void main(String[] args) throws IOException {
//UMigrate.main(new String[]{"migrate"});
final GUIInteractionStrategy window = new GUIInteractionStrategy(defaultConfig(), "Test");
MigrateCallBack migrateCallBack = new MigrateCallBack() {
@Override
public Set<String> variablesRequiringDialogInOutstanding() {
Set<String>result = new java.util.HashSet<String>();
/*result.add("PWD_One");
result.add("PWD_Two");
result.add("PWD_Three");/**/
return result;
}
@Override
public String summary() {
return "A test Summary\nOf what needs Migrating";
}
private void fakeScript(UserInteractionStrategy userInteractionStrategy){
final int count = 5;
final int sleepMs = 100;
userInteractionStrategy.scriptOutputLine(String.format("Count %d times every %d ms", count, sleepMs));
for(int idx=0;idx<count;idx++){
userInteractionStrategy.scriptOutputLine("count: " + idx);
try {
Thread.sleep(sleepMs);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void doMigration() {
for(int idx = 0; idx < noScriptsToMigrate(); idx++){
final int scriptIdx = idx + 1;
Script script = new Script() {
@Override
public Set<String> variablesRequiringDialog() {
return null;
}
@Override
public long getPatch() {
return scriptIdx;
}
@Override
public String getFileName() {
return String.format("Script %d", scriptIdx);
}
@Override
public long getDBVersion() {
return 2;
}
@Override
public ScriptStatus execute(UserInteractionStrategy userInteractionStrategy) {
fakeScript(userInteractionStrategy);
return ScriptStatus.COMPLETED;
}
@Override
public String description() {
return String.format("Script %d", scriptIdx);
}
@Override
public String condtionStatus() {
return "OK";
}
@Override
public int compareTo(Script o) {
return 0;
}
};
window.scriptStatusMessage(idx, script, ScriptStatus.STARTED);
fakeScript(window);
window.scriptStatusMessage(idx, script, ScriptStatus.COMPLETED);
}
window.completed("Completed", false);
}
@Override
public int noScriptsToMigrate() {
return 20;
}
};
window.startUIProcess(migrateCallBack);
/**/
}
private JTextPane txtToBeApplied;
private JTextPane txtCurrentActions;
private JTextPane txtSqlOutput;
@Override
public boolean startUIProcess(final MigrateCallBack migrateCallBack) {
this.migrateCallBack = migrateCallBack;
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
initialize();
frame.setVisible(true);
frame.setTitle(config.getMigrationMessage() + " - " + message);
} catch (Exception e) {
e.printStackTrace();
}
}
});
return true;
}
final private List<String> lastScriptOutput = new ArrayList<String>();
private String lastMessage = "";
void copyToClipBoard(String text){
if (text == null||text.trim().isEmpty()) return;
StringSelection stringSelection = new StringSelection(text);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents( stringSelection, null );
}
void copyStatusScriptToClipBoard(){
StyledDocument doc = txtStatus.getStyledDocument();
try {
copyToClipBoard(doc.getText(0, doc.getLength()));
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private interface InformationPublish {
void publish();
}
private class MigrateWorker extends SwingWorker<Void, InformationPublish> {
@Override
protected Void doInBackground() throws Exception {
migrateCallBack.doMigration();
return null;
}
@Override
protected void process(List<InformationPublish> publishedItems) {
for(InformationPublish info: publishedItems){
info.publish();
}
}
@Override
public void done() {
running = false;
}
void publishInfo(InformationPublish info){
publish(info);
}
}
private MigrateWorker migrateWorker;
@Override
public void scriptStatusMessage(final int scriptIdx, final Script script, final ScriptStatus status) {
if (migrateWorker == null) return;
migrateWorker.publishInfo(new InformationPublish() {
@Override
public void publish() {
if (status == ScriptStatus.STARTED) lastScriptOutput.clear();
lastMessage = status + " " + script.description();
displayStatusMessage(lastMessage);
displayScriptLine("\n" + lastMessage + "\n", true);
}
});
}
void displayStatusMessage(String message) {
StyledDocument doc = txtCurrentActions.getStyledDocument();
try {
progressBar.setValue(progressBar.getValue() + 1);
doc.insertString(doc.getLength(), message + "\n", null);
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void errorMessage(final String message) {
if (migrateWorker == null) return;
migrateWorker.publishInfo(new InformationPublish() {
@Override
public void publish() {
JOptionPane.showMessageDialog(frame, message, "Error Applying Scripts", JOptionPane.DEFAULT_OPTION);
}
});
}
@Override
public void scriptOutputLine(final String line) {
if (migrateWorker == null) return;
migrateWorker.publishInfo(new InformationPublish() {
@Override
public void publish() {
lastScriptOutput.add(line);
displayScriptLine(line, false);
}
});
}
AttributeSet scriptAttributeSet(boolean isStatus){
if (!isStatus) return null;
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.DARK_GRAY);
aset = sc.addAttribute(aset, StyleConstants.Bold, true);
return aset;
}
private void displayScriptLine(String line, boolean isStatus){
StyledDocument doc = txtSqlOutput.getStyledDocument();
try {
doc.insertString(doc.getLength(), line + "\n", scriptAttributeSet(isStatus));
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void switchCard(String cardName){
clWizard.show(pnlWizard, cardName);
}
final static String CARD_PROGRESS = "progress";
final static String CARD_FINISHED = "finished";
private JPanel pnlWizard;
private CardLayout clWizard;
private JProgressBar progressBar;
private JTextPane txtStatus;
boolean updatePropertiesValues(String desc, Set<String> properties){
if (properties == null || properties.size() == 0) return true;
Properties uMigrateProperties = config.uMigrateProperties();
Map<String, String> map = MissingPropertyDialog.askForValues(properties, uMigrateProperties, desc);
if (map == null) return false;
for(Entry<String, String> m: map.entrySet()){
uMigrateProperties.setProperty(m.getKey(), m.getValue());
}
return true;
}
void onCreate(){
try {
Set<String> properties = config.getConnectionVariablesRequiringDialog();
if (!updatePropertiesValues("Read Current Database Script", properties)){
insertStatusMessage("User Aborted setting Values to check Database Script", true);
switchCard(CARD_FINISHED);
return;
}
txtToBeApplied.setText(migrateCallBack.summary());
if (migrateCallBack.noScriptsToMigrate() == 0){
insertStatusMessage("Nothing to Do - database is already at Script Level", false);
switchCard(CARD_FINISHED);
return;
}
}
catch(Exception e){
txtStatus.setText("Error Looking up Current version of database\n" + e);
switchCard(CARD_FINISHED);
}
}
AttributeSet attributeSet(boolean iserror){
if (!iserror) return null;
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, Color.red);
aset = sc.addAttribute(aset, StyleConstants.Bold, true);
return aset;
}
void insertStatusMessage(String message, boolean isError){
StyledDocument doc = txtStatus.getStyledDocument();
try {
doc.insertString(doc.getLength(), message + "\n", attributeSet(isError));
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
boolean running = false;
void startProcess(){
if (!updatePropertiesValues("Missing Values", migrateCallBack.variablesRequiringDialogInOutstanding())){
insertStatusMessage("User Aborted setting Values to required Migrate Database", true);
switchCard(CARD_FINISHED);
return;
}
final int noScriptsToApply = migrateCallBack.noScriptsToMigrate();
switchCard(CARD_PROGRESS);
progressBar.setMinimum(0);
progressBar.setMaximum(2 * noScriptsToApply);
progressBar.setValue(0);
migrateWorker = new MigrateWorker();
running = true;
migrateWorker.execute();
}
boolean canClose(){
if (!running) return true;
final String errorMessage = "Currently running Migration Scripts - exiting causes issues";
final String title = "Exit while Running Migration Scripts";
boolean result = JOptionPane.showConfirmDialog(frame, errorMessage, title, JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION;
if (result) LOG.info("User accepted exit while migrating");
return result;
}
void close(){
if (canClose()) {
frame.dispose();
//System.exit(0);
}
}
@Override
public void completed(final String status, final boolean successful) {
if (migrateWorker == null) return;
migrateWorker.publishInfo(new InformationPublish() {
@Override
public void publish() {
insertStatusMessage(status, !successful);
if (!successful) {
JOptionPane.showMessageDialog(frame, "Not All scripts applied successfully", "Finished", JOptionPane.ERROR_MESSAGE);
insertStatusMessage("Not All scripts applied successfully", true);
insertStatusMessage("\n" + lastMessage + "\n", true);
if (lastScriptOutput.size() > 0) insertStatusMessage("Last Script Output:", false);
for(String line: lastScriptOutput){
insertStatusMessage(line, false);
}
}
else {
JOptionPane.showMessageDialog(frame, "All scripts applied/skipped successfully");
insertStatusMessage("All scripts applied/skipped successfully", false);
}
txtStatus.setCaretPosition(0);
switchCard(CARD_FINISHED);
}
});
}
private void initialize() {
frame = new JFrame();
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent arg0) {
onCreate();
}
@Override
public void windowClosing(WindowEvent arg0) {
close();
}
});
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setBounds(100, 100, 943, 560);
JPanel panel = new JPanel();
panel.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.setBorder(new TitledBorder(null, "To be Applied", TitledBorder.LEADING, TitledBorder.TOP, null, null));
panel.setLayout(null);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(13, 25, 875, 97);
panel.add(scrollPane);
txtToBeApplied = new JTextPane();
txtToBeApplied.setEditable(false);
scrollPane.setViewportView(txtToBeApplied);
pnlWizard = new JPanel();
clWizard = new CardLayout(0, 0);
pnlWizard.setLayout(clWizard);
JPanel panel_3 = new JPanel();
FlowLayout flowLayout = (FlowLayout) panel_3.getLayout();
flowLayout.setAlignment(FlowLayout.LEFT);
pnlWizard.add(panel_3, "name_139454654370795");
final JPanel pnlProgress = new JPanel();
JButton btnApply = new JButton("Apply");
btnApply.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
startProcess();
}
});
btnApply.setHorizontalAlignment(SwingConstants.LEFT);
panel_3.add(btnApply);
JButton btnAbort = new JButton("Abort");
btnAbort.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
close();
}
});
panel_3.add(btnAbort);
pnlWizard.add(pnlProgress, CARD_PROGRESS);
GridBagLayout gbl_pnlProgress = new GridBagLayout();
gbl_pnlProgress.columnWidths = new int[]{913, 0};
gbl_pnlProgress.rowHeights = new int[] {20, 80, 0, 0};
gbl_pnlProgress.columnWeights = new double[]{1.0, Double.MIN_VALUE};
gbl_pnlProgress.rowWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE};
pnlProgress.setLayout(gbl_pnlProgress);
progressBar = new JProgressBar();
GridBagConstraints gbc_progressBar = new GridBagConstraints();
gbc_progressBar.fill = GridBagConstraints.HORIZONTAL;
gbc_progressBar.anchor = GridBagConstraints.NORTH;
gbc_progressBar.insets = new Insets(5, 5, 5, 5);
gbc_progressBar.gridx = 0;
gbc_progressBar.gridy = 0;
pnlProgress.add(progressBar, gbc_progressBar);
JPanel panel_1 = new JPanel();
panel_1.setBorder(new TitledBorder(null, "Current Action", TitledBorder.LEFT, TitledBorder.TOP, null, null));
GridBagConstraints gbc_panel_1 = new GridBagConstraints();
gbc_panel_1.fill = GridBagConstraints.BOTH;
gbc_panel_1.gridx = 0;
gbc_panel_1.gridy = 1;
pnlProgress.add(panel_1, gbc_panel_1);
GridBagLayout gbl_panel_1 = new GridBagLayout();
gbl_panel_1.columnWidths = new int[]{875, 0};
gbl_panel_1.rowHeights = new int[]{41, 0};
gbl_panel_1.columnWeights = new double[]{0.0, Double.MIN_VALUE};
gbl_panel_1.rowWeights = new double[]{0.0, Double.MIN_VALUE};
panel_1.setLayout(gbl_panel_1);
JScrollPane scrollPane_3 = new JScrollPane();
GridBagConstraints gbc_scrollPane_3 = new GridBagConstraints();
gbc_scrollPane_3.fill = GridBagConstraints.BOTH;
gbc_scrollPane_3.gridx = 0;
gbc_scrollPane_3.gridy = 0;
panel_1.add(scrollPane_3, gbc_scrollPane_3);
txtCurrentActions = new JTextPane();
scrollPane_3.setViewportView(txtCurrentActions);
JPanel panel_5 = new JPanel();
panel_5.setBorder(new TitledBorder(null, "SQL Output", TitledBorder.LEADING, TitledBorder.TOP, null, null));
GridBagConstraints gbc_panel_5 = new GridBagConstraints();
gbc_panel_5.fill = GridBagConstraints.BOTH;
gbc_panel_5.gridx = 0;
gbc_panel_5.gridy = 2;
pnlProgress.add(panel_5, gbc_panel_5);
GridBagLayout gbl_panel_5 = new GridBagLayout();
gbl_panel_5.columnWidths = new int[]{0, 0};
gbl_panel_5.rowHeights = new int[]{0, 0};
gbl_panel_5.columnWeights = new double[]{1.0, Double.MIN_VALUE};
gbl_panel_5.rowWeights = new double[]{1.0, Double.MIN_VALUE};
panel_5.setLayout(gbl_panel_5);
JScrollPane scrollPane_2 = new JScrollPane();
GridBagConstraints gbc_scrollPane_2 = new GridBagConstraints();
gbc_scrollPane_2.fill = GridBagConstraints.BOTH;
gbc_scrollPane_2.gridx = 0;
gbc_scrollPane_2.gridy = 0;
panel_5.add(scrollPane_2, gbc_scrollPane_2);
txtSqlOutput = new JTextPane();
scrollPane_2.setViewportView(txtSqlOutput);
final JPanel pnlSuccess = new JPanel();
pnlSuccess.setBorder(null);
pnlSuccess.setAlignmentY(Component.TOP_ALIGNMENT);
pnlSuccess.setAlignmentX(Component.LEFT_ALIGNMENT);
pnlWizard.add(pnlSuccess, CARD_FINISHED);
JButton btnClose = new JButton("Close");
btnClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
close();
}
});
JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBorder(new TitledBorder(null, "Status", TitledBorder.LEADING, TitledBorder.TOP, null, null));
scrollPane_1.setAlignmentY(Component.TOP_ALIGNMENT);
txtStatus = new JTextPane();
scrollPane_1.setViewportView(txtStatus);
JButton btnCopyStatus = new JButton("Copy Status");
btnCopyStatus.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
copyStatusScriptToClipBoard();
}
});
GroupLayout gl_pnlSuccess = new GroupLayout(pnlSuccess);
gl_pnlSuccess.setHorizontalGroup(
gl_pnlSuccess.createParallelGroup(Alignment.LEADING)
.addGroup(gl_pnlSuccess.createSequentialGroup()
.addComponent(btnClose)
.addGap(18)
.addComponent(btnCopyStatus)
.addContainerGap(723, Short.MAX_VALUE))
.addComponent(scrollPane_1, GroupLayout.DEFAULT_SIZE, 901, Short.MAX_VALUE)
);
gl_pnlSuccess.setVerticalGroup(
gl_pnlSuccess.createParallelGroup(Alignment.LEADING)
.addGroup(gl_pnlSuccess.createSequentialGroup()
.addGroup(gl_pnlSuccess.createParallelGroup(Alignment.BASELINE)
.addComponent(btnClose)
.addComponent(btnCopyStatus))
.addGap(5)
.addComponent(scrollPane_1, GroupLayout.DEFAULT_SIZE, 316, Short.MAX_VALUE))
);
pnlSuccess.setLayout(gl_pnlSuccess);
GroupLayout groupLayout = new GroupLayout(frame.getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.TRAILING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addComponent(pnlWizard, GroupLayout.PREFERRED_SIZE, 901, Short.MAX_VALUE)
.addGap(12))
.addGroup(groupLayout.createSequentialGroup()
.addComponent(panel, GroupLayout.DEFAULT_SIZE, 901, Short.MAX_VALUE)
.addContainerGap())))
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addGap(7)
.addComponent(panel, GroupLayout.PREFERRED_SIZE, 136, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addComponent(pnlWizard, GroupLayout.DEFAULT_SIZE, 346, Short.MAX_VALUE)
.addGap(13))
);
frame.getContentPane().setLayout(groupLayout);
}
}