blob: aa80c84ba90f835678374ba67fe72174f7cc7660 [file] [log] [blame]
/*
* 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.openejb.itest.failover;
import org.apache.openejb.client.RemoteInitialContextFactory;
import org.apache.openejb.itest.failover.ejb.Calculator;
import org.apache.openejb.loader.Files;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.Zips;
import org.apache.openejb.util.OpenEjbVersion;
import org.apache.openejb.server.control.StandaloneServer;
import org.apache.openejb.util.NetworkUtil;
import org.junit.Assert;
import org.junit.Test;
import javax.ejb.EJBException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
/**
* In some situations it can be desirable to have
* one dedicated multipoint root server which does
* no other function other than to serve as a central
* hub for making multipoint introductions.
*
* This dedicate root server will not serve applications
* and not be added to the list of servers that can
* service EJB requests.
*/
public class StickyConnectionStrategyTest {
static final Logger logger = Logger.getLogger("org.apache.openejb.client");
static {
final ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
logger.addHandler(consoleHandler);
logger.setLevel(Level.FINER);
logger.setUseParentHandlers(false);
//Set a high socket timeout for tests
System.setProperty("openejb.client.connection.socket.timeout", System.getProperty("openejb.client.connection.socket.timeout", "5000"));
}
@Test
public void test() throws Exception {
// To run in an IDE, uncomment and update this line
System.setProperty("version", OpenEjbVersion.get().getVersion());
final File zip = Repository.getArtifact("org.apache.tomee", "openejb-standalone", "zip");
final File app = Repository.getArtifact("org.apache.openejb.itests", "failover-ejb", "jar");
final File dir = Files.tmpdir();
final StandaloneServer root;
{
final StandaloneServer root1;
final String name = "root";
final File home = new File(dir, name);
Files.mkdir(home);
Zips.unzip(zip, home, true);
root1 = new StandaloneServer(home, home);
root1.killOnExit();
root1.ignoreOut();
root1.getJvmOpts().add("-Dopenejb.classloader.forced-load=org.apache.openejb");
root1.setProperty("name", name);
root1.setProperty("openejb.extract.configuration", "false");
final StandaloneServer.ServerService multipoint = root1.getServerService("multipoint");
multipoint.setBind("localhost");
multipoint.setPort(getAvailablePort());
multipoint.setDisabled(false);
multipoint.set("discoveryName", name);
root = root1;
logger.info("Starting Root server");
root.start();
}
final Map<String, StandaloneServer> servers = new HashMap<String, StandaloneServer>();
for (final String name : new String[]{"red", "green", "blue"}) {
final File home = new File(dir, name);
Files.mkdir(home);
Zips.unzip(zip, home, true);
final StandaloneServer server = new StandaloneServer(home, home);
server.killOnExit();
server.ignoreOut();
server.getJvmOpts().add("-Dopenejb.classloader.forced-load=org.apache.openejb");
server.setProperty("name", name);
server.setProperty("openejb.extract.configuration", "false");
IO.copy(app, Files.path(home, "apps", "itest.jar"));
IO.copy(IO.read("<openejb><Deployments dir=\"apps/\"/></openejb>"), Files.path(home, "conf", "openejb.xml"));
final StandaloneServer.ServerService ejbd = server.getServerService("ejbd");
ejbd.setBind("localhost");
ejbd.setDisabled(false);
ejbd.setPort(getAvailablePort());
ejbd.setThreads(5);
ejbd.set("discovery", "ejb:ejbd://{bind}:{port}/" + name);
final StandaloneServer.ServerService multipoint = server.getServerService("multipoint");
multipoint.setPort(getAvailablePort());
multipoint.setDisabled(false);
multipoint.set("discoveryName", name);
multipoint.set("initialServers", "localhost:" + root.getServerService("multipoint").getPort());
servers.put(name, server);
logger.info(String.format("Starting %s server", name));
server.start(1, TimeUnit.MINUTES);
invoke(name, server);
}
System.setProperty("openejb.client.requestretry", "true");
logger.info("Beginning Test");
final Properties environment = new Properties();
environment.put(Context.INITIAL_CONTEXT_FACTORY, RemoteInitialContextFactory.class.getName());
environment.put(Context.PROVIDER_URL, "ejbd://localhost:" + servers.values().iterator().next().getServerService("ejbd").getPort() + "/provider");
final InitialContext context = new InitialContext(environment);
final Calculator bean = (Calculator) context.lookup("CalculatorBeanRemote");
String previous = null;
for (final StandaloneServer ignored : servers.values()) {
logger.info("Looping");
// What server are we talking to now?
final String name = bean.name();
logger.info("Sticky request to " + name);
// The root should not be serving apps
assertFalse("root".equals(name));
// Should not be the same server we were talking with previously (we killed that server)
if (previous != null) assertFalse(name.equals(previous));
previous = name;
final int i = 1000;
logger.info(String.format("Performing %s invocations, expecting %s to be used for each invocation.", i, name));
// Should be the same server for the next N calls
invoke(bean, i, name);
logger.info("Shutting down " + name);
// Now let's kill that server
servers.get(name).kill();
}
logger.info("All Servers Shutdown");
try {
logger.info("Making one last request, expecting complete failover");
final String name = bean.name();
Assert.fail("Server should be destroyed: " + name);
} catch (final EJBException e) {
logger.info(String.format("Pass. Request resulted in %s: %s", e.getCause().getClass().getSimpleName(), e.getMessage()));
// good
}
// Let's start a server again and invocations should now succeed
final Iterator<StandaloneServer> iterator = servers.values().iterator();
iterator.next();
final StandaloneServer server = iterator.next();
logger.info(String.format("Starting %s server", server.getProperties().get("name")));
server.start(1, TimeUnit.MINUTES);
logger.info("Performing one more invocation");
assertEquals(5, bean.sum(2, 3));
}
private void invoke(final String name, final StandaloneServer server) throws NamingException {
final Properties environment = new Properties();
environment.put(Context.INITIAL_CONTEXT_FACTORY, RemoteInitialContextFactory.class.getName());
environment.put(Context.PROVIDER_URL, "ejbd://localhost:" + server.getServerService("ejbd").getPort() + "/" + name);
final InitialContext context = new InitialContext(environment);
final Calculator bean = (Calculator) context.lookup("CalculatorBeanRemote");
assertEquals(name, bean.name());
}
private long invoke(final Calculator bean, final int max, final String expectedName) {
long total = 0;
for (int i = 0; i < max; i++) {
final long start = System.nanoTime();
final String name = bean.name();
Assert.assertEquals(expectedName, name);
total += System.nanoTime() - start;
}
return TimeUnit.NANOSECONDS.toMicros(total / max);
}
private long invoke(final Calculator bean, final int max) {
long total = 0;
for (int i = 0; i < max; i++) {
final long start = System.nanoTime();
Assert.assertEquals(3, bean.sum(1, 2));
total += System.nanoTime() - start;
}
return TimeUnit.NANOSECONDS.toMicros(total / max);
}
private int getAvailablePort() {
return NetworkUtil.getNextAvailablePort();
}
}