/*
* 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.config;
import org.apache.openejb.assembler.classic.Assembler;
import org.apache.openejb.assembler.classic.OpenEjbConfiguration;
import org.apache.openejb.loader.Files;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.Archives;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* @version $Rev$ $Date$
*/
public class AutoDeployerTest {
private static final Set<File> files = new HashSet<File>();
@BeforeClass
public static void beforeClass() {
files.clear();
}
@AfterClass
public static void afterClass() throws InterruptedException {
//Give async IO a reasonable chance to catch up.
SystemInstance.reset();
Thread.sleep(3000);
//Make sure files have been deleted.
for (final File file : files) {
if (file.exists()) {
final File[] exists = file.listFiles();
assertTrue("Application files still exist in: " + file.getAbsolutePath(), (null == exists || exists.length == 0));
}
}
}
@Before
@After
public void beforeAndAfter() throws InterruptedException {
//Allow AutoDeployer scanning to complete
Thread.sleep(3000);
final AutoDeployer autoDeployer = SystemInstance.get().getComponent(AutoDeployer.class);
if (autoDeployer != null) {
autoDeployer.stop();
}
SystemInstance.reset();
}
@Test
public void test() throws Exception {
final File tmpdir = Files.tmpdir();
final File apps = Files.mkdir(tmpdir, "myapps");
final File conf = Files.mkdir(tmpdir, "conf");
files.add(apps);
final Properties properties = new Properties();
properties.setProperty("openejb.deployments.classpath", "false");
properties.setProperty("openejb.deployment.unpack.location", "false");
properties.setProperty("openejb.home", tmpdir.getAbsolutePath());
properties.setProperty("openejb.base", tmpdir.getAbsolutePath());
properties.setProperty("openejb.autodeploy.interval", "2 seconds");
SystemInstance.init(properties);
{ // Setup the configuration location
final File config = new File(conf, "openejb.xml");
IO.writeString(config, "<openejb><Deployments autoDeploy=\"true\" dir=\"myapps\"/> </openejb>");
SystemInstance.get().setProperty("openejb.configuration", config.getAbsolutePath());
}
final ConfigurationFactory configurationFactory = new ConfigurationFactory();
configurationFactory.init(properties);
final OpenEjbConfiguration configuration = configurationFactory.getOpenEjbConfiguration();
{ // Check the ContainerSystemInfo
final List<String> autoDeploy = configuration.containerSystem.autoDeploy;
assertEquals(1, autoDeploy.size());
assertEquals("myapps", autoDeploy.get(0));
}
final Assembler assembler = new Assembler();
assembler.buildContainerSystem(configuration);
/// start with the testing...
assertFalse(Yellow.deployed);
assertFalse(Orange.deployed);
final File deployed = Files.path(apps, "colors.ear");
// Hot deploy the EAR
final File ear = createEar(tmpdir, Orange.class, State.class);
IO.copy(ear, deployed);
Orange.state.waitForChange(1, TimeUnit.MINUTES);
assertFalse(Yellow.deployed);
assertTrue(Orange.deployed);
Files.delete(deployed);
Orange.state.waitForChange(1, TimeUnit.MINUTES);
assertFalse(Yellow.deployed);
assertFalse(Orange.deployed);
}
@Test
public void testOriginalAppScanning() throws Exception {
final File tmpdir = Files.tmpdir();
final File apps = Files.mkdir(tmpdir, "myapps");
final File conf = Files.mkdir(tmpdir, "conf");
files.add(apps);
final Properties properties = new Properties();
properties.setProperty("openejb.deployments.classpath", "false");
properties.setProperty("openejb.deployment.unpack.location", "false");
properties.setProperty("openejb.home", tmpdir.getAbsolutePath());
properties.setProperty("openejb.base", tmpdir.getAbsolutePath());
properties.setProperty("openejb.autodeploy.interval", "2 seconds");
SystemInstance.init(properties);
{ // Setup the configuration location
final File config = new File(conf, "openejb.xml");
IO.writeString(config, "<openejb><Deployments autoDeploy=\"true\" dir=\"myapps\"/> </openejb>");
SystemInstance.get().setProperty("openejb.configuration", config.getAbsolutePath());
}
final File deployed = Files.path(apps, "colors.ear");
final File ear = createEar(tmpdir, Orange.class, State.class);
IO.copy(ear, deployed);
final ConfigurationFactory configurationFactory = new ConfigurationFactory();
configurationFactory.init(properties);
final OpenEjbConfiguration configuration = configurationFactory.getOpenEjbConfiguration();
{ // Check the ContainerSystemInfo
final List<String> autoDeploy = configuration.containerSystem.autoDeploy;
assertEquals(1, autoDeploy.size());
assertEquals("myapps", autoDeploy.get(0));
}
final Assembler assembler = new Assembler();
assembler.buildContainerSystem(configuration);
assertTrue(Orange.deployed);
final long start = Orange.start;
assertFalse(Yellow.deployed);
assertTrue(Orange.deployed);
// wait another to ensure it doesnt redeploy again
Thread.sleep(4000);
assertEquals(start, Orange.start);
Files.delete(deployed);
Orange.state.waitForChange(1, TimeUnit.MINUTES);
assertFalse(Yellow.deployed);
assertFalse(Orange.deployed);
}
@Test
public void testSpaces() throws Exception {
final File tmpdir = new File(Files.tmpdir(), "with spaces");
final File apps = Files.mkdir(tmpdir, "my apps");
final File conf = Files.mkdir(tmpdir, "conf");
files.add(apps);
final Properties properties = new Properties();
properties.setProperty("openejb.deployments.classpath", "false");
properties.setProperty("openejb.deployment.unpack.location", "false");
properties.setProperty("openejb.home", tmpdir.getAbsolutePath());
properties.setProperty("openejb.base", tmpdir.getAbsolutePath());
SystemInstance.init(properties);
{ // Setup the configuration location
final File config = new File(conf, "openejb.xml");
IO.writeString(config, "<openejb><Deployments autoDeploy=\"true\" dir=\"my apps\"/> </openejb>");
SystemInstance.get().setProperty("openejb.configuration", config.getAbsolutePath());
}
final ConfigurationFactory configurationFactory = new ConfigurationFactory();
configurationFactory.init(properties);
final OpenEjbConfiguration configuration = configurationFactory.getOpenEjbConfiguration();
{ // Check the ContainerSystemInfo
final List<String> autoDeploy = configuration.containerSystem.autoDeploy;
assertEquals(1, autoDeploy.size());
assertEquals("my apps", autoDeploy.get(0));
}
final Assembler assembler = new Assembler();
assembler.buildContainerSystem(configuration);
/// start with the testing...
assertFalse(Yellow.deployed);
assertFalse(Orange.deployed);
final File deployed = Files.path(apps, "colors.ear");
// Hot deploy the EAR
final File ear = createEar(tmpdir, Orange.class, State.class);
IO.copy(ear, deployed);
Orange.state.waitForChange(1, TimeUnit.MINUTES);
assertFalse(Yellow.deployed);
assertTrue(Orange.deployed);
Files.delete(deployed);
Orange.state.waitForChange(1, TimeUnit.MINUTES);
assertFalse(Yellow.deployed);
assertFalse(Orange.deployed);
}
@Test
public void testAltUnpackDir() throws Exception {
final File tmpdir = Files.tmpdir();
final File apps = Files.mkdir(tmpdir, "myapps");
final File conf = Files.mkdir(tmpdir, "conf");
files.add(apps);
final Properties properties = new Properties();
properties.setProperty("openejb.deployments.classpath", "false");
properties.setProperty("tomee.unpack.dir", "work");
properties.setProperty("openejb.home", tmpdir.getAbsolutePath());
properties.setProperty("openejb.base", tmpdir.getAbsolutePath());
SystemInstance.init(properties);
{ // Setup the configuration location
final File config = new File(conf, "openejb.xml");
IO.writeString(config, "<openejb><Deployments autoDeploy=\"true\" dir=\"myapps\"/> </openejb>");
SystemInstance.get().setProperty("openejb.configuration", config.getAbsolutePath());
}
final ConfigurationFactory configurationFactory = new ConfigurationFactory();
configurationFactory.init(properties);
final OpenEjbConfiguration configuration = configurationFactory.getOpenEjbConfiguration();
{ // Check the ContainerSystemInfo
final List<String> autoDeploy = configuration.containerSystem.autoDeploy;
assertEquals(1, autoDeploy.size());
assertEquals("myapps", autoDeploy.get(0));
}
final Assembler assembler = new Assembler();
assembler.buildContainerSystem(configuration);
/// start with the testing...
assertFalse(Yellow.deployed);
assertFalse(Orange.deployed);
final File deployed = Files.path(apps, "colors.ear");
deployed.deleteOnExit();
// Hot deploy the EAR
final File ear = createEar(tmpdir, Orange.class, State.class);
ear.deleteOnExit();
IO.copy(ear, deployed);
assertTrue(deployed.exists());
Orange.state.waitForChange(1, TimeUnit.MINUTES);
assertFalse(Yellow.deployed);
assertTrue(Orange.deployed);
Files.delete(deployed);
Orange.state.waitForChange(1, TimeUnit.MINUTES);
assertFalse(Yellow.deployed);
assertFalse(Orange.deployed);
}
private File createEar(final File tmpdir, final Class<?>... aClass) throws IOException {
final File ear = new File(tmpdir, "colors.ear");
final Map<String, Object> contents = new HashMap<String, Object>();
contents.put("foo.jar", Archives.jarArchive(aClass));
Archives.jarArchive(ear, contents);
return ear;
}
public static class State {
private volatile boolean b;
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void toggle() {
lock.lock();
try {
b = !b;
condition.signal();
} finally {
lock.unlock();
}
}
public boolean get() {
return b;
}
public void waitForChange(final long time, final TimeUnit unit) {
lock.lock();
try {
condition.await(time, unit);
} catch (final InterruptedException e) {
Thread.interrupted();
} finally {
lock.unlock();
}
}
}
@Singleton
@Startup
public static class Orange {
public static volatile boolean deployed;
public static final State state = new State();
public static long start;
@PostConstruct
private void startup() {
start = System.currentTimeMillis();
deployed = true;
state.toggle();
}
@PreDestroy
private void shutdown() {
deployed = false;
state.toggle();
}
}
@Singleton
@Startup
public static class Yellow {
public static volatile boolean deployed;
@PostConstruct
private void startup() {
deployed = true;
}
@PreDestroy
private void shutdown() {
deployed = false;
}
}
}