/* * 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.io.IOException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CountDownLatch; 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; /** * Long-running asynchronous service client. * * @author Marek Potociar (marek.potociar at oracle.com) */ public class Main { /** * Main client entry point. * * @param args command-line arguments. */ public static void main(String[] args) { System.exit(runClient(args)); } /** * Client - business logic. * * @param args command-line arguments. * @return exit code of the utility. {@code 0} if everything completed without errors, {@code -1} otherwise. */ static int runClient(final String[] args) { // Parsing command-line arguments final Config config = Config.parse(args); System.out.println(String.format("\nStarting to execute %d requests:\n", config.requests)); // 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 Queue<String> errors = new ConcurrentLinkedQueue<String>(); final AtomicInteger requestCounter = new AtomicInteger(0); final long tic = System.currentTimeMillis(); for (int i = 0; i < config.requests; i++) { final int reqId = i; echoResource.resolveTemplate("echo", reqId).request().async().get(new InvocationCallback<String>() { private final AtomicInteger retries = new AtomicInteger(0); @Override public void completed(String response) { final String requestId = Integer.toString(reqId); if (requestId.equals(response)) { System.out.print("*"); requestCounter.incrementAndGet(); } else { System.out.print("!"); errors.offer(String.format("Echo response '%s' not equal to request '%s'", response, requestId)); } latch.countDown(); } @Override public void failed(Throwable error) { if (error.getCause() instanceof IOException && retries.getAndIncrement() < 3) { // resend echoResource.resolveTemplate("echo", reqId).request().async().get(this); } else { System.out.print("!"); errors.offer(String.format("Request '%d' has failed: %s", reqId, error.toString())); latch.countDown(); } } }); } try { if (!latch.await(60, TimeUnit.SECONDS)) { errors.offer("Waiting for requests to complete has timed out."); } } catch (InterruptedException e) { errors.offer("Waiting for requests to complete has been interrupted."); } final long toc = System.currentTimeMillis(); System.out.println(String.format("\n\nExecution finished in %d ms.\nSuccess rate: %6.2f %%", toc - tic, ((double) requestCounter.get() / config.requests) * 100)); if (errors.size() > 0) { System.out.println("Following errors occurred during the request execution"); for (String error : errors) { System.out.println("\t" + error); } } client.close(); return errors.size() > 0 ? -1 : 0; } static class Config { /** * Default base URI of the async echo web application. */ public static final String DEFAULT_BASE_URI = "http://localhost:8080/server-async-standalone-webapp/"; final String baseUri; final boolean sync; final int requests; Config(String baseUri, boolean sync, int requests) { this.baseUri = baseUri; this.sync = sync; this.requests = requests; } public static Config parse(String[] args) { String baseUri = DEFAULT_BASE_URI; boolean sync = false; int requests = 10; for (String arg : args) { final String[] keyValuePair = arg.trim().split("="); if ("uri".equals(keyValuePair[0])) { baseUri = keyValuePair[1]; } else if ("mode".equals(keyValuePair[0])) { sync = "sync".equals(keyValuePair[1]); } else if ("req".equals(keyValuePair[0])) { requests = Integer.parseInt(keyValuePair[1]); } else { System.out.println("WARNING: Unknown parameter: " + keyValuePair[0]); } } return new Config(baseUri, sync, requests); } @Override public String toString() { return "Config{" + "baseUri='" + baseUri + '\'' + ", sync=" + sync + ", requests=" + requests + '}'; } } }