All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tascape.reactor.ws.driver.WebService Maven / Gradle / Ivy

/*
 * Copyright 2015 - 2016 Nebula Bay.
 *
 * 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 com.tascape.reactor.ws.driver;

import com.tascape.reactor.SystemConfiguration;
import com.tascape.reactor.comm.SshCommunication;
import com.tascape.reactor.ws.comm.WebServiceCommunication;
import com.tascape.reactor.driver.EntityDriver;
import com.tascape.reactor.ws.comm.WebServiceCommunication.HTTP_METHOD;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.comparator.LastModifiedFileComparator;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author linsong wang
 */
public abstract class WebService extends EntityDriver {
    private static final Logger LOG = LoggerFactory.getLogger(WebService.class);

    private static final File HISTORY_DIR = SystemConfiguration.HOME_PATH.resolve("ws-viewer").toFile();

    protected WebServiceCommunication wsc;

    protected SshCommunication ssh;

    public void setWebServiceCommunication(WebServiceCommunication wsc) {
        this.wsc = wsc;
    }

    public WebServiceCommunication getWebServiceCommunication() {
        return this.wsc;
    }

    public SshCommunication getSshCommunication() {
        return ssh;
    }

    public void setSshCommunication(SshCommunication ssh) {
        this.ssh = ssh;
    }

    public void interactManually() throws Exception {
        WebService.this.interactManually(30);
    }

    /**
     * The method starts a GUI to let an user send requests to web service manually.
     * Please make sure to set timeout long enough for manual interaction.
     *
     * @param timeoutMinutes timeout in minutes to fail the manual steps
     *
     * @throws Exception if case of error
     */
    public void interactManually(int timeoutMinutes) throws Exception {
        LOG.info("Start UI to interact manually");
        String info = wsc.getHttpHost().toString();
        long end = System.currentTimeMillis() + timeoutMinutes * 60000L;

        AtomicBoolean visible = new AtomicBoolean(true);
        AtomicBoolean pass = new AtomicBoolean(false);
        String tName = Thread.currentThread().getName() + "m";
        SwingUtilities.invokeLater(() -> {
            JDialog jd = new JDialog((Frame) null, "Manual Web Service Interaction");
            jd.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

            JPanel jpContent = new JPanel(new BorderLayout());
            jd.setContentPane(jpContent);
            jpContent.setPreferredSize(new Dimension(1088, 828));
            jpContent.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

            JComboBox jcbMethods = new JComboBox<>(HTTP_METHOD.values());
            JTextField jtfEndpoint = new JTextField();
            JTextField jtfParameters = new JTextField();

            JTextArea jtaRequest = new JTextArea();
            Font font = jtaRequest.getFont();
            jtaRequest.setFont(new Font("Courier New", font.getStyle(), font.getSize()));

            JTextArea jtaResponse = new JTextArea();
            font = jtaResponse.getFont();
            jtaResponse.setFont(new Font("Courier New", font.getStyle(), font.getSize()));

            DefaultListModel historyModel = this.loadHistoryModel();
            JList jlHistory = new JList<>(historyModel);
            jlHistory.setCellRenderer(new DefaultListCellRenderer() {
                @Override
                public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                    boolean cellHasFocus) {
                    setBackground(list.getBackground());
                    JSONObject json = (JSONObject) value;
                    setText(json.getString("endpoint"));
                    setToolTipText(json.getString("endpoint"));
                    if (isSelected) {
                        setFont(getFont().deriveFont(Font.BOLD));
                    } else {
                        setFont(getFont().deriveFont(Font.PLAIN));
                    }
                    return this;
                }
            });
            jlHistory.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            jlHistory.clearSelection();
            jlHistory.getSelectionModel().addListSelectionListener(event -> {
                ListSelectionModel lsm = (ListSelectionModel) event.getSource();
                if (event.getValueIsAdjusting()) {
                    return;
                }
                JSONObject json = historyModel.get(lsm.getMinSelectionIndex());
                jcbMethods.setSelectedItem(HTTP_METHOD.valueOf(json.getString("method")));
                jtfEndpoint.setText(json.getString("endpoint"));
                jtfParameters.setText(json.getString("parameters"));
                jtaRequest.setText(json.getString("req-body"));
                jtaResponse.setText(json.getString("res-body"));
            });

            JPanel jpInfo = new JPanel();
            jpContent.add(jpInfo, BorderLayout.PAGE_START);
            jpInfo.setLayout(new BorderLayout());
            {
                JButton jb = new JButton("PASS");
                jb.setForeground(Color.green.darker());
                jb.setFont(jb.getFont().deriveFont(Font.BOLD));
                jpInfo.add(jb, BorderLayout.LINE_START);
                jb.addActionListener(event -> {
                    pass.set(true);
                    jd.dispose();
                    visible.set(false);
                });
            }
            {
                JButton jb = new JButton("FAIL");
                jb.setForeground(Color.red);
                jb.setFont(jb.getFont().deriveFont(Font.BOLD));
                jpInfo.add(jb, BorderLayout.LINE_END);
                jb.addActionListener(event -> {
                    pass.set(false);
                    jd.dispose();
                    visible.set(false);
                });
            }
            JLabel jlTimeout = new JLabel("1200 seconds left", SwingConstants.CENTER);
            jpInfo.add(jlTimeout, BorderLayout.CENTER);
            new SwingWorker() {
                @Override
                protected Long doInBackground() throws Exception {
                    while (System.currentTimeMillis() < end) {
                        Thread.sleep(1000);
                        long left = (end - System.currentTimeMillis()) / 1000;
                        this.publish(left);
                    }
                    return 0L;
                }

                @Override
                protected void process(List chunks) {
                    Long l = chunks.get(chunks.size() - 1);
                    jlTimeout.setText(l + " seconds left");
                    if (l < 850) {
                        jlTimeout.setForeground(Color.red);
                    }
                }
            }.execute();

            JPanel jpRequest = new JPanel(new BorderLayout());
            {
                JPanel jpHttp = new JPanel();
                jpHttp.setLayout(new BoxLayout(jpHttp, BoxLayout.PAGE_AXIS));
                jpRequest.add(jpHttp, BorderLayout.PAGE_START);

                JPanel jpHttp1 = new JPanel();
                jpHttp1.setLayout(new BoxLayout(jpHttp1, BoxLayout.LINE_AXIS));
                jpHttp.add(jpHttp1);

                jpHttp1.add(jcbMethods);
                jpHttp1.add(Box.createHorizontalStrut(18));
                jpHttp1.add(new JLabel(info, SwingConstants.CENTER), BorderLayout.CENTER);
                jpHttp1.add(Box.createHorizontalStrut(8));
                jpHttp1.add(new JLabel("endpoint: "));
                jpHttp1.add(Box.createHorizontalStrut(5));
                jpHttp1.add(jtfEndpoint);
                jpHttp1.add(Box.createHorizontalStrut(8));
                JButton jbHeaders = new JButton("Headers");
                jpHttp1.add(jbHeaders);
                jbHeaders.addActionListener((ActionEvent event) -> {
                    Thread t = new Thread(tName) {
                        @Override
                        public void run() {
                            JPanel jpHeaders = new JPanel(new BorderLayout());
                            jpHeaders.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

                            DefaultTableModel tm = new DefaultTableModel(1, 2);
                            tm.setColumnIdentifiers(new String[]{"Name", "Value"});
                            wsc.getHeaders().entrySet().forEach(es -> {
                                tm.insertRow(0, new String[]{es.getKey(), es.getValue()});
                            });
                            tm.addRow(new String[]{"", ""});

                            JTable jt = new JTable(tm);
                            jpHeaders.add(new JScrollPane(jt), BorderLayout.CENTER);

                            JPanel jp = new JPanel();
                            jpHeaders.add(jp, BorderLayout.PAGE_END);
                            jp.setLayout(new BoxLayout(jp, BoxLayout.LINE_AXIS));
                            JButton apply = new JButton("Apply");
                            jp.add(Box.createHorizontalGlue());
                            jp.add(apply);
                            apply.setEnabled(false);
                            apply.setToolTipText("disabled for now, coming soon...");

                            JDialog jd0 = new JDialog(jd, "HTTP Headers");
                            jd0.setContentPane(jpHeaders);
                            jd0.setModal(true);
                            jd0.pack();
                            jd0.setLocationRelativeTo(jd);
                            jd0.setVisible(true);
                        }
                    };
                    t.start();
                });

                JPanel jpHttp2 = new JPanel();
                jpHttp2.setLayout(new BoxLayout(jpHttp2, BoxLayout.LINE_AXIS));
                jpHttp.add(jpHttp2);

                jpHttp2.add(new JLabel("parameters: "));
                jpHttp2.add(Box.createHorizontalStrut(8));
                jpHttp2.add(jtfParameters);
                jpHttp.add(Box.createHorizontalStrut(18));
                JButton jbSend = new JButton("Send Request");
                jpHttp2.add(jbSend);

                String error = "Cannot send request";
                jbSend.addActionListener((ActionEvent event) -> {
                    Thread t = new Thread(tName) {
                        @Override
                        public void run() {
                            LOG.debug("\n\n");
                            String ep = jtfEndpoint.getText();
                            if (StringUtils.isBlank(ep)) {
                                return;
                            }

                            String pm = jtfParameters.getText();
                            String ct = jtaRequest.getText();
                            String requestId = UUID.randomUUID().toString();
                            HTTP_METHOD method = (HTTP_METHOD) jcbMethods.getSelectedItem();
                            String res;
                            JSONObject json;

                            jtaResponse.setText("");
                            try {
                                switch (method) {
                                    case GET:
                                        res = wsc.get(ep, pm, requestId);
                                        jtaResponse.setText(res);
                                        break;
                                    case GET_JSONObject:
                                        json = wsc.getJsonObject(ep, pm, requestId);
                                        jtaResponse.setText(json.toString(2));
                                        break;
                                    case GET_JSONArray:
                                        JSONArray jarr = wsc.getJsonArray(ep, pm, requestId);
                                        jtaResponse.setText(jarr.toString(2));
                                        break;
                                    case POST:
                                        res = wsc.post(ep, pm, ct, requestId);
                                        jtaResponse.setText(res);
                                        break;
                                    case POST_JSONObject:
                                        res = wsc.postJson(ep, pm, new JSONObject(ct), requestId);
                                        jtaResponse.setText(res);
                                        break;
                                    case PUT:
                                        res = wsc.put(ep, pm, ct, requestId);
                                        jtaResponse.setText(res);
                                        break;
                                    case PUT_JSONObject:
                                        res = wsc.putJson(ep, pm, new JSONObject(ct), requestId);
                                        jtaResponse.setText(res);
                                        break;
                                    case DELETE:
                                        if (StringUtils.isBlank(ct)) {
                                            res = wsc.delete(ep, pm, requestId);
                                        } else {
                                            res = wsc.delete(ep, pm, ct, requestId);
                                        }
                                        jtaResponse.setText(res);
                                        break;
                                    case DELETE_JSONObject:
                                        res = wsc.deleteJson(ep, pm, new JSONObject(ct), requestId);
                                        jtaResponse.setText(res);
                                        break;
                                    case HEAD:
                                        for (Header h : wsc.head(ep, pm, requestId)) {
                                            jtaResponse.append(h.getName() + ": " + h.getValue() + "\n");
                                        }
                                        break;
                                }
                            } catch (IOException | JSONException ex) {
                                LOG.error(error, ex);
                                StringWriter sw = new StringWriter();
                                ex.printStackTrace(new PrintWriter(sw));
                                jtaResponse.append(sw.toString());
                                jtaResponse.append("\n");
                            }
                            long time = wsc.getResponseTime(requestId);
                            jtaResponse.append("\n\nresponse time (ms) " + time);
                            LOG.debug("\n\n");

                            JSONObject j = new JSONObject()
                                .put("method", method.name())
                                .put("endpoint", ep)
                                .put("parameters", pm)
                                .put("req-body", ct)
                                .put("res-body", jtaResponse.getText());
                            historyModel.insertElementAt(j, 0);
                            try {
                                FileUtils.writeStringToFile(new File(HISTORY_DIR, "ws-" + System.currentTimeMillis()
                                    + ".json"), j.toString(2), Charset.defaultCharset());
                            } catch (IOException ex) {
                                LOG.warn("Cannot save history {}", ex.getMessage());
                            }
                        }
                    };
                    t.start();

                    try {
                        t.join();
                    } catch (InterruptedException ex) {
                        LOG.error(error, ex);
                    }
                });

                jtaRequest.setTabSize(4);
                JScrollPane jsp = new JScrollPane(jtaRequest);
                jsp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5, 10, 5, 5),
                    UIManager.getBorder("TextField.border")));
                jpRequest.add(new JLabel("request
body: "), BorderLayout.LINE_START); jpRequest.add(jsp, BorderLayout.CENTER); } JPanel jpResponse = new JPanel(new BorderLayout()); { JScrollPane jsp = new JScrollPane(jtaResponse); jsp.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5, 10, 5, 5), UIManager.getBorder("TextField.border"))); jpResponse.add(jsp, BorderLayout.CENTER); jpResponse.add(new JLabel("response: "), BorderLayout.LINE_START); } JPanel jpLog = new JPanel(); jpLog.setLayout(new BoxLayout(jpLog, BoxLayout.LINE_AXIS)); jpResponse.add(jpLog, BorderLayout.PAGE_END); { JTextField jtMsg = new JTextField(10); jpLog.add(jtMsg); JButton jbLogMsg = new JButton("Log Message"); jpLog.add(jbLogMsg); jtMsg.addFocusListener(new FocusListener() { @Override public void focusLost(final FocusEvent pE) { } @Override public void focusGained(final FocusEvent pE) { jtMsg.selectAll(); } }); jbLogMsg.addActionListener(event -> { Thread t = new Thread(tName) { @Override public void run() { String msg = jtMsg.getText(); if (StringUtils.isNotBlank(msg)) { LOG.info("{}", msg); } } }; t.start(); try { t.join(); } catch (InterruptedException ex) { LOG.error("", ex); } jtMsg.requestFocus(); }); } JSplitPane jSplitPaneReqRes = new JSplitPane(JSplitPane.VERTICAL_SPLIT, jpRequest, jpResponse); jSplitPaneReqRes.setResizeWeight(0.28); jSplitPaneReqRes.setBorder(BorderFactory.createEtchedBorder()); JPanel jpHistory = new JPanel(new BorderLayout()); { jpHistory.setBorder(BorderFactory.createEtchedBorder()); jpHistory.add(new JScrollPane(jlHistory), BorderLayout.CENTER); } JSplitPane jSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jpHistory, jSplitPaneReqRes); jSplitPane.setResizeWeight(0.18); jSplitPane.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0)); jpContent.add(jSplitPane, BorderLayout.CENTER); jd.pack(); jd.setLocationRelativeTo(null); jd.setVisible(true); jSplitPane.setDividerLocation(0.12); }); while (visible.get()) { if (System.currentTimeMillis() > end) { LOG.error("Manual interaction timeout"); break; } Thread.sleep(500); } if (pass.get()) { LOG.info("Manual Interaction returns PASS"); } else { Assert.fail("Manual Interaction returns FAIL"); } } private DefaultListModel loadHistoryModel() { HISTORY_DIR.mkdirs(); File[] files = HISTORY_DIR.listFiles(); Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE); int number = Math.min(200, files.length); DefaultListModel m = new DefaultListModel<>(); for (int i = 0; i < number; i++) { try { m.addElement(new JSONObject(FileUtils.readFileToString(files[i], Charset.defaultCharset()))); } catch (IOException ex) { LOG.warn("cannot load json {}", ex.getMessage()); } } for (int i = number; i < files.length; i++) { files[i].delete(); } return m; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy