/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2012-2015 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License"). You * may not use this file except in compliance with the License. You can * obtain a copy of the License at * http://glassfish.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt. See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license." If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above. However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */ package org.glassfish.jersey.examples.server.async; import java.awt.Color; import java.awt.EventQueue; import java.awt.FlowLayout; import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.InvocationCallback; import javax.ws.rs.client.WebTarget; import javax.swing.JLabel; /** * @author Marek Potociar (marek.potociar at oracle.com) */ public class MainWindow extends javax.swing.JFrame { /** * Creates new form MainWindow */ public MainWindow() { initComponents(); uriField.setText(Main.Config.DEFAULT_BASE_URI); ((FlowLayout) messagePanel.getLayout()).setAlignment(FlowLayout.LEADING); messagePanel.removeAll(); messagePanel.revalidate(); } /** * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { syncAsyncSwitchGroup = new javax.swing.ButtonGroup(); jPanel1 = new javax.swing.JPanel(); jLabel1 = new javax.swing.JLabel(); requestCountField = new javax.swing.JTextField(); syncRadio = new javax.swing.JRadioButton(); asyncRadio = new javax.swing.JRadioButton(); uriField = new javax.swing.JTextField(); jLabel2 = new javax.swing.JLabel(); runButton = new javax.swing.JButton(); messagePanel = new javax.swing.JPanel(); jLabel3 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); jPanel2 = new javax.swing.JPanel(); finishStatusLabel = new javax.swing.JLabel(); successRateStatusLabel = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setMaximumSize(new java.awt.Dimension(480, 600)); setMinimumSize(new java.awt.Dimension(480, 600)); setResizable(false); jLabel1.setText("Number of requests"); requestCountField.setHorizontalAlignment(javax.swing.JTextField.RIGHT); requestCountField.setText("10"); syncAsyncSwitchGroup.add(syncRadio); syncRadio.setText("sync"); syncAsyncSwitchGroup.add(asyncRadio); asyncRadio.setSelected(true); asyncRadio.setText("async"); uriField.setText("jTextField2"); jLabel2.setText("Base web app URL"); runButton.setText("Run"); runButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { runButtonActionPerformed(evt); } }); org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel1Layout.createSequentialGroup() .addContainerGap() .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jLabel1) .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabel2)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel1Layout.createSequentialGroup() .add(requestCountField) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(syncRadio) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(asyncRadio) .add(24, 24, 24) .add(runButton)) .add(jPanel1Layout.createSequentialGroup() .add(uriField) .addContainerGap()))) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(uriField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(jLabel2)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(requestCountField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(jLabel1) .add(syncRadio) .add(asyncRadio) .add(runButton))) ); messagePanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); jLabel3.setBackground(new java.awt.Color(255, 255, 0)); jLabel3.setText(" "); jLabel3.setToolTipText("Running..."); jLabel3.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); jLabel3.setOpaque(true); messagePanel.add(jLabel3); jLabel4.setBackground(new java.awt.Color(255, 255, 0)); jLabel4.setText(" "); jLabel4.setToolTipText("Running..."); jLabel4.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); jLabel4.setOpaque(true); messagePanel.add(jLabel4); finishStatusLabel.setText(" "); successRateStatusLabel.setText(" "); org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel2Layout.createSequentialGroup() .addContainerGap() .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(finishStatusLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(successRateStatusLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(jPanel2Layout.createSequentialGroup() .addContainerGap() .add(finishStatusLabel) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(successRateStatusLabel) .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) .add(jPanel2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(org.jdesktop.layout.GroupLayout.LEADING, jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(messagePanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 468, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(jPanel2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(messagePanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 456, Short.MAX_VALUE) .addContainerGap()) ); pack(); }// </editor-fold>//GEN-END:initComponents private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_runButtonActionPerformed final Main.Config config = new Main.Config(uriField.getText(), syncRadio.isSelected(), Integer.parseInt(requestCountField.getText())); runButton.setEnabled(false); finishStatusLabel.setText(" "); successRateStatusLabel.setText(" "); messagePanel.removeAll(); messagePanel.revalidate(); messagePanel.repaint(); Executors.newSingleThreadExecutor().submit(new Runnable() { @Override public void run() { sendMessages(config); } }); }//GEN-LAST:event_runButtonActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ // try { // for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { // if ("Nimbus".equals(info.getName())) { // javax.swing.UIManager.setLookAndFeel(info.getClassName()); // break; // } // } // } catch (ClassNotFoundException ex) { // java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); // } catch (InstantiationException ex) { // java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); // } catch (IllegalAccessException ex) { // java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); // } catch (javax.swing.UnsupportedLookAndFeelException ex) { // java.util.logging.Logger.getLogger(MainWindow.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); // } //</editor-fold> /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { final MainWindow mainWindow = new MainWindow(); mainWindow.setLocationRelativeTo(null); mainWindow.setVisible(true); } }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JRadioButton asyncRadio; private javax.swing.JLabel finishStatusLabel; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JPanel messagePanel; private javax.swing.JTextField requestCountField; private javax.swing.JButton runButton; private javax.swing.JLabel successRateStatusLabel; private javax.swing.ButtonGroup syncAsyncSwitchGroup; private javax.swing.JRadioButton syncRadio; private javax.swing.JTextField uriField; // End of variables declaration//GEN-END:variables private final Color PROGRESS_COLOR = new Color(255, 255, 0); private final Color ERROR_COLOR = new Color(255, 0, 0); private final Color SUCCESS_COLOR = new Color(0, 255, 0); private JLabel createRequestStatusLabel() { final JLabel label = new JLabel(" "); invokeAndWait(new Runnable() { @Override public void run() { label.setBackground(PROGRESS_COLOR); label.setToolTipText("Running..."); label.setBorder(javax.swing.BorderFactory.createLineBorder(new Color(0, 0, 0))); label.setOpaque(true); messagePanel.add(label); messagePanel.revalidate(); } }); return label; } private void invokeAndWait(Runnable event) { try { EventQueue.invokeAndWait(event); } catch (Exception e) { throw new RuntimeException(e); } } private void sendMessages(final Main.Config config) { // Creating JAX-RS client final Client client = ClientBuilder.newClient(); // Targeting echo resource at URI "<baseUri>/long-running/(sync|async)/{echo}" final WebTarget echoResource = client.target(config.baseUri).path("long-running/{mode}/{echo}") .resolveTemplate("mode", (config.sync) ? "sync" : "async"); final CountDownLatch latch = new CountDownLatch(config.requests); final AtomicInteger requestCounter = new AtomicInteger(0); final long tic = System.currentTimeMillis(); for (int i = 0; i < config.requests; i++) { final int reqId = i; final JLabel requestStatusLabel = createRequestStatusLabel(); echoResource.resolveTemplate("echo", reqId).request().async().get(new InvocationCallback<String>() { private final AtomicInteger retries = new AtomicInteger(0); @Override public void completed(final String response) { invokeAndWait(new Runnable() { @Override public void run() { final String requestId = Integer.toString(reqId); if (requestId.equals(response)) { requestStatusLabel.setBackground(SUCCESS_COLOR); requestStatusLabel.setToolTipText(requestId); requestCounter.incrementAndGet(); } else { requestStatusLabel.setBackground(ERROR_COLOR); requestStatusLabel.setToolTipText(String.format("Echo response '%s' not equal to request '%s'", response, requestId)); } latch.countDown(); } }); } @Override public void failed(final Throwable error) { if (error.getCause() instanceof IOException && retries.getAndIncrement() < 3) { // resend echoResource.resolveTemplate("echo", reqId).request().async().get(this); } else { invokeAndWait(new Runnable() { @Override public void run() { requestStatusLabel.setBackground(ERROR_COLOR); requestStatusLabel.setToolTipText(String.format("Request '%d' has failed: %s", reqId, error.toString())); latch.countDown(); } }); } } }); } try { if (!latch.await(60, TimeUnit.SECONDS)) { System.out.println("Waiting for requests to complete has timed out."); } } catch (InterruptedException e) { System.out.println("Waiting for requests to complete has been interrupted."); } final long toc = System.currentTimeMillis(); invokeAndWait(new Runnable() { @Override public void run() { finishStatusLabel.setText(String.format("Execution finished in %d ms.", toc - tic)); successRateStatusLabel.setText(String.format("Success rate: %6.2f %%", ((double) requestCounter.get() / config.requests) * 100)); } }); client.close(); EventQueue.invokeLater(new Runnable() { @Override public void run() { runButton.setEnabled(true); } }); } }