/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.tuscany.sca.itest.oneway; import java.io.File; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; import junit.framework.Assert; import org.apache.tuscany.sca.core.invocation.NonBlockingInterceptor; import org.apache.tuscany.sca.itest.oneway.impl.OneWayClientImpl; import org.apache.tuscany.sca.itest.oneway.impl.OneWayServiceImpl; import org.apache.tuscany.sca.node.Contribution; import org.apache.tuscany.sca.node.Node; import org.apache.tuscany.sca.node.NodeFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * This test case will test invoking @OneWay operations. * * @version $Date$ $Revision$ */ public class OneWayTestCase { /** * Maximum period of time that we are prepared to wait for all the @OneWay * method calls to complete in milliseconds. */ private static final int MAX_SLEEP_TIME = 10000; private Node node; /** * Initialise the SCADomain. * * @throws Exception Failed to initialise the SCADomain */ @Before public void setUp() throws Exception { NodeFactory factory = NodeFactory.newInstance(); node = factory.createNode(new File("src/main/resources/OneWayContribution/META-INF/sca-deployables/oneWay.composite").toURI().toURL().toString(), new Contribution("TestContribution", new File("src/main/resources/OneWayContribution/META-INF/sca-deployables/").toURI().toURL().toString())); node.start(); } /** * This method will ensure that the SCADomain is shutdown. * * @throws Exception Failed to shutdown the SCADomain */ @After public void tearDown() throws Exception { node.stop(); } /** * This test will test repeatedly calling a @OneWay operation and ensure that the correct * number of @OneWay operations are run. * * @throws Exception Test failed */ @Test public void testOneWay() throws Exception { OneWayClient client = node.getService(OneWayClient.class, "OneWayClientComponent"); int count = 100; for (int i = 0; i < 10; i++) { // System.out.println("Test: doSomething " + count); // System.out.flush(); client.doSomething(count); // TUSCANY-2192 - We need to sleep to allow the @OneWay method calls to complete. // Note: This can take different periods depending on the speed and load // on the computer where the test is being run. // This loop will wait for the required number of @OneWay method calls to // have taken place or MAX_SLEEP_TIME to have passed. long startSleep = System.currentTimeMillis(); while (OneWayClientImpl.callCount != OneWayServiceImpl.CALL_COUNT.get() && System.currentTimeMillis() - startSleep < MAX_SLEEP_TIME) { Thread.sleep(100); // System.out.println("" + OneWayClientImpl.callCount + "," + OneWayServiceImpl.callCount); } System.out.println("Finished callCount = " + OneWayServiceImpl.CALL_COUNT); Assert.assertEquals(OneWayClientImpl.callCount, OneWayServiceImpl.CALL_COUNT.get()); } } /** * This method will invoke a @OneWay method that throws an exception * when invoked over a SCA Binding which uses the NonBlockingInterceptor and * ensure that the Exception is logged. * See TUSCANY-2225 */ @Test public void testOneWayUsingNonBlockingInterceptorThrowsAnException() { OneWayClient client = node.getService(OneWayClient.class, "OneWayClientComponentSCABinding"); // We need to modify the JDK Logger for the NonBlockingInterceptor so we // can check that it logs a message for the @OneWay invocation that throws // an Exception Logger nbiLogger = Logger.getLogger(NonBlockingInterceptor.class.getName()); DummyJDKHandler handler = new DummyJDKHandler(); nbiLogger.addHandler(handler); // Add a message on the console to explain the stack dump that is going to be // displayed and state that this is not a problem but expected behaviour System.out.println(); System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"); System.out.println("IMPORTANT: The error message that appears on the console"); System.out.println("below is an expected error if it is a NullPointerException"); System.out.println(" with the message of:"); System.out.println(" \"" + OneWayServiceImpl.EXCEPTION_MESSAGE + "\""); System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"); System.out.println(); System.out.flush(); // Invoke the @OneWay method that throws an exception client.doSomethingWhichThrowsException(); // The logging is done asynchronously so we will need to wait a bit before // the log message appears. long start = System.currentTimeMillis(); boolean logged = false; while (System.currentTimeMillis() - start < MAX_SLEEP_TIME && !logged) { // Has the log message been logged? if (handler.exceptionLogged.get()) { logged = true; } else { try { Thread.sleep(25); } catch (InterruptedException ex) { Assert.fail("Unexpected exception " + ex); } } } // Add a message explaining that errors beyond this point should be reported System.out.println(); System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"); System.out.println("End of expected exceptions. Any errors beyond this point are errors!"); System.out.println("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"); System.out.println(); System.out.flush(); // Remove the handler nbiLogger.removeHandler(handler); // Make sure that the exception was logged Assert.assertTrue(handler.exceptionLogged.get()); } /** * A handler that is added to the JDK Logging system to examine the log messages * generated to ensure that a @OneWay method that throws an Exception will * generate a log message. */ private class DummyJDKHandler extends Handler { /** * Used to track whether the exception has been logged. */ private AtomicBoolean exceptionLogged = new AtomicBoolean(false); /** * Constructor. */ private DummyJDKHandler() { super.setLevel(Level.ALL); } /** * {@inheritDoc} */ @Override public void close() throws SecurityException { // Nothing to do } /** * {@inheritDoc} */ @Override public void flush() { // Nothing to do } /** * Examines the LogRecord and checks whether it matches the one we are looking for. * If it matches, it will set exceptionLogged to True. * * @param record The Log Record that is being published */ @Override public void publish(LogRecord record) { // The log message we are looking for is Severe if (record.getLevel() == Level.SEVERE) { if (record.getThrown() != null && record.getThrown().toString().indexOf( OneWayServiceImpl.EXCEPTION_MESSAGE) != -1) { // We have found our Exception. exceptionLogged.set(true); } } } } }