blob: 884bac935d91f97439c1672e61577efa4cf84baf [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.arquillian.common;
import org.apache.openejb.loader.ProvisioningUtil;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.loader.provisining.ProvisioningResolver;
import org.apache.tomee.util.QuickServerXmlParser;
import org.codehaus.swizzle.stream.ReplaceStringsInputStream;
import org.jboss.arquillian.container.spi.client.container.LifecycleException;
import org.jboss.shrinkwrap.api.ArchivePaths;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import static java.util.Collections.emptyMap;
/**
* @version $Rev$ $Date$
*/
public class Setup {
private static final Logger LOGGER = Logger.getLogger(Setup.class.getName()); // JUL is used by arquillian so that's fine
public static final String TOMEE_BEAN_DISCOVERER_JAR = "lib" + File.separator + "xx-arquillian-tomee-bean-discoverer.jar"; // starts with xx to not be filtered
private static final String DEFAULT_MEM_CONFIG = (javaVersion() >= 1.8 ? "" : "-XX:PermSize=64m -XX:MaxPermSize=256m ")
+ "-Xmx512m -Xms256m -XX:ReservedCodeCacheSize=64m";
private static double javaVersion() {
try {
return Double.parseDouble(System.getProperty("java.version", "1.7").substring(0, 3));
} catch (final Exception nfe) {
return 1.6;
}
}
public static void exportProperties(final File tomeeHome, final TomEEConfiguration c, final boolean defaultMem) {
final int httpPort = c.getHttpPort();
System.setProperty("java.naming.provider.url", "http://" + c.getHost() + ":" + httpPort + "/tomee/ejb");
System.setProperty("connect.tries", "90");
System.setProperty("server.http.port", String.valueOf(httpPort));
System.setProperty("server.shutdown.port", String.valueOf(c.getStopPort()));
if (defaultMem) {
System.setProperty("java.opts", DEFAULT_MEM_CONFIG + " -Dtomee.httpPort=" + httpPort);
} else {
System.setProperty("java.opts", "-Dtomee.httpPort=" + httpPort);
}
System.setProperty("openejb.home", tomeeHome.getAbsolutePath());
System.setProperty("tomee.home", tomeeHome.getAbsolutePath());
}
public static void updateServerXml(final File tomeeHome, final TomEEConfiguration configuration) throws IOException {
final File serverXml = Files.path(new File(tomeeHome.getAbsolutePath()), "conf", "server.xml");
if (!serverXml.exists()) {
return;
}
final QuickServerXmlParser ports = QuickServerXmlParser.parse(serverXml);
if (configuration.getKeepServerXmlAsThis()) {
// force ports to be able to stop the server and get @ArquillianResource
configuration.setHttpPort(Integer.parseInt(ports.http()));
configuration.setStopPort(Integer.parseInt(ports.stop()));
return; // in this case we don't want to override the conf
}
final Map<String, String> replacements = new HashMap<>();
replacements.put(ports.http(), String.valueOf(configuration.getHttpPort()));
replacements.put(ports.https(), String.valueOf(configuration.getHttpsPort()));
replacements.put(ports.stop(), String.valueOf(configuration.getStopPort()));
replacements.put(ports.ajp(), String.valueOf(ajpPort(configuration)));
if (configuration.isUnpackWars()) {
replacements.put("unpackWARs=\"false\"", "unpackWARs=\"true\"");
} else {
replacements.put("unpackWARs=\"true\"", "unpackWARs=\"false\"");
}
replace(replacements, serverXml, true);
}
public static File findHome(File directory) {
directory = directory.getAbsoluteFile();
final File f = findHomeImpl(directory);
if (null == f) {
LOGGER.log(Level.INFO, "Unable to find home in: " + directory);
}
return f;
}
public static File findHomeImpl(final File directory) {
final File conf = new File(directory, "conf").getAbsoluteFile();
final File webapps = new File(directory, "webapps").getAbsoluteFile();
if (conf.exists() && conf.isDirectory() && webapps.exists() && webapps.isDirectory()) {
return directory;
}
final File[] files = directory.listFiles();
if (null != files) {
for (final File file : files) {
if (".".equals(file.getName()) || "..".equals(file.getName())) {
continue;
}
final File found = findHome(file);
if (found != null) {
return found;
}
}
}
return null;
}
public static File downloadAndUnpack(final File dir, final String artifactID, final String defaultTempDir) throws LifecycleException {
final File zipFile = downloadFile(artifactID, null, defaultTempDir);
Zips.unzip(zipFile, dir);
return findHome(dir);
}
public static File downloadFile(final String artifactName, final String altUrl, final String defaultTempDir) {
final String cache = SystemInstance.isInitialized() ?
SystemInstance.get().getOptions().get(ProvisioningResolver.OPENEJB_DEPLOYER_CACHE_FOLDER, (String) null) :
System.getProperty(ProvisioningResolver.OPENEJB_DEPLOYER_CACHE_FOLDER);
if (cache == null && defaultTempDir != null) { // let the user override it
System.setProperty(ProvisioningResolver.OPENEJB_DEPLOYER_CACHE_FOLDER, defaultTempDir);
}
try {
final File artifact = MavenCache.getArtifact(artifactName, altUrl);
if (artifact == null) {
throw new NullPointerException(String.format("No such artifact: %s", artifactName));
}
return artifact.getAbsoluteFile();
} finally {
if (cache == null) {
System.clearProperty(ProvisioningResolver.OPENEJB_DEPLOYER_CACHE_FOLDER);
}
}
}
public static boolean isRunning(final String host, final int port) {
Socket socket = null;
try {
socket = new Socket(host, port);
socket.getOutputStream().close();
return true;
} catch (final Exception e) {
return false;
} finally {
if (socket != null) {
try {
socket.close();
} catch (final IOException ignored) {
// no-op
}
}
}
}
public static void replace(final Map<String, String> replacements, final File file, final boolean escape) throws IOException {
InputStream in = IO.read(file);
if (escape) {
final Map<String, String> escaped = new HashMap<>();
for (final Map.Entry<String, String> entry : replacements.entrySet()) {
final String key = entry.getKey();
final String value = entry.getValue();
if (key.startsWith("\"") && key.endsWith("\"")) {
escaped.put(key, value);
} else {
escaped.put("\"" + key + "\"", "\"" + value + "\"");
}
}
replacements.clear();
replacements.putAll(escaped);
}
in = new ReplaceStringsInputStream(in, replacements);
final String data = IO.slurp(in);
IO.copy(data.getBytes(), file);
if (LOGGER.isLoggable(Level.FINE)) {
IO.copy(data.getBytes(), System.out);
}
}
public static void removeUselessWebapps(final File tomeeHome, final String... exceptions) {
final File webapps = new File(tomeeHome, "webapps");
if (webapps.isDirectory()) {
final File[] files = webapps.listFiles();
if (files != null) {
for (final File webapp : files) {
boolean delete = true;
if (exceptions != null) {
for (final String ignore : exceptions) {
if (webapp.getName().equals(ignore)) {
delete = false;
break;
}
}
}
if (delete) {
org.apache.openejb.loader.Files.delete(webapp);
}
}
}
}
}
public static void configureServerXml(final File tomeeHome, final TomEEConfiguration configuration) throws IOException {
if (configuration.getServerXml() != null) {
final File serverXml = new File(configuration.getServerXml());
if (!serverXml.exists()) {
LOGGER.severe("Provided server.xml doesn't exist: '" + serverXml.getPath() + "'");
} else {
// Read in the contents to memory so we can avoid re-reading for parsing
final String data = IO.slurp(serverXml);
IO.copy(data.getBytes(), Files.path(tomeeHome, "conf", "server.xml"));
}
}
updateServerXml(tomeeHome, configuration);
}
private static int ajpPort(final TomEEConfiguration config) {
try {
final Method ajbPort = config.getClass().getMethod("getAjpPort");
return (Integer) ajbPort.invoke(config);
} catch (final Exception e) {
return Integer.parseInt(QuickServerXmlParser.DEFAULT_AJP_PORT);
}
}
public static void configureSystemProperties(final File tomeeHome, final TomEEConfiguration configuration) {
final File file = Files.path(tomeeHome, "conf", "system.properties");
// Must use an actual properties object to avoid duplicate keys
final Properties properties = new Properties();
if (file.exists()) {
try {
IO.readProperties(file, properties);
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, "Can't read " + file.getAbsolutePath(), e);
}
}
if (configuration.getProperties() != null) {
try {
final InputStream bytes = IO.read(configuration.getProperties().getBytes());
IO.readProperties(bytes, properties);
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, "Can't parse <property name=\"properties\"> value '" + configuration.getProperties() + "'", e);
}
}
if (configuration.isQuickSession()) {
properties.put("openejb.session.manager", "org.apache.tomee.catalina.session.QuickSessionManager");
}
if (configuration.isUnsafeEjbd() && "*".equals(properties.getProperty("tomee.serialization.class.blacklist", "-").trim())) {
properties.remove("tomee.serialization.class.blacklist");
properties.put("tomee.serialization.class.whitelist", "*");
System.setProperty("tomee.serialization.class.blacklist", System.getProperty("tomee.serialization.class.blacklist", "-"));
reloadClientSerializationConfig();
}
try {
IO.writeProperties(file, properties);
} catch (final IOException e) {
LOGGER.log(Level.SEVERE, "Can't save system properties " + file.getAbsolutePath(), e);
}
}
public static void reloadClientSerializationConfig() {
try {
Thread.currentThread().getContextClassLoader().loadClass("org.apache.openejb.client.EjbObjectInputStream")
.getMethod("reloadResolverConfig").invoke(null);
} catch (final IllegalAccessException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException e) {
// not a pb normally
}
}
public static void synchronizeFolder(final File tomeeHome, final String src, final String dir) {
if (src != null && !src.isEmpty()) {
final File confSrc = new File(src);
if (confSrc.exists()) {
final File conf = new File(tomeeHome, dir);
final Collection<File> files = org.apache.openejb.loader.Files.collect(confSrc, TrueFilter.INSTANCE);
files.remove(confSrc);
for (final File f : files) {
if (f.equals(confSrc) || f.getName().startsWith(".")) {
continue;
}
final String relativize = relativize(f, confSrc);
if (f.isDirectory()) {
final String path = dir + '/' + relativize;
Files.mkdir(new File(tomeeHome, path));
synchronizeFolder(tomeeHome, f.getAbsolutePath(), path);
} else {
try {
final File to = new File(conf, relativize);
Files.mkdir(to.getParentFile());
org.apache.openejb.loader.IO.copy(f, to);
} catch (final Exception e) {
LOGGER.log(Level.WARNING, "Ignoring copy of " + f.getAbsolutePath(), e);
}
}
}
} else {
LOGGER.warning("Can't find " + confSrc.getAbsolutePath());
}
}
}
private static String relativize(final File f, final File base) {
return f.getAbsolutePath().substring(base.getAbsolutePath().length() + 1);
}
public static void installArquillianBeanDiscoverer(final File home) {
final File destination = new File(home, TOMEE_BEAN_DISCOVERER_JAR);
ShrinkWrap.create(JavaArchive.class, destination.getName())
.addManifest() // avoid NPE from org.apache.tomcat.util.scan.StandardJarScanner.processManifest()
.addClasses(BeanDicovererInstaller.class, TestClassDiscoverer.class, ArquillianFilterRunner.class, Discover.class)
.addAsManifestResource(new StringAsset(BeanDicovererInstaller.class.getName()), ArchivePaths.create("org.apache.openejb.extension"))
.as(ZipExporter.class).exportTo(destination, true);
}
public static void removeArquillianBeanDiscoverer(final File home) {
final File destination = new File(home, TOMEE_BEAN_DISCOVERER_JAR);
Files.delete(destination);
}
public static Map<File, String> addTomEELibraries(final File libFolder, final String additionalLibs, final boolean parseArgs) {
if (additionalLibs == null) {
return emptyMap();
}
final String libs = additionalLibs.trim();
if (libs.isEmpty()) {
return emptyMap();
}
try { // initializing the SystemInstance because we'll need it for configuration
if (!SystemInstance.isInitialized()) {
SystemInstance.init(new Properties());
}
} catch (final Exception e) {
// no-op
}
final Map<File, String> configs = new HashMap<>();
for (final String lib : libs.split("\n")) {
final String trim = lib.trim();
if (trim.isEmpty() || trim.startsWith("#")) {
continue;
}
final String args;
if (parseArgs) { // javaagent friendly
int argsIdx = trim.indexOf('=');
if (argsIdx < 0) {
argsIdx = trim.indexOf('?');
}
if (argsIdx > 0) {
args = trim.substring(argsIdx);
} else {
args = "";
}
} else {
args = null;
}
if (trim.startsWith("remove:")) { // like mvn plugin, needed to use plus but switch something like the jpa provider
final String prefix = trim.substring("remove:".length());
final File[] children = libFolder.listFiles(new FilenameFilter() {
@Override
public boolean accept(final File dir, final String name) {
return name.startsWith(prefix);
}
});
if (children != null && children.length > 0) {
for (final File child : children) {
if (!IO.delete(child) && child.getName().endsWith(".jar")) { // try to rename it to have it ignored
child.renameTo(new File(child.getParentFile(), child.getName() + "_renamed"));
}
}
}
} else {
final Set<String> locations = ProvisioningUtil.realLocation(trim);
for (final String location : locations) {
final File from = new File(location);
try {
final File to = new File(libFolder, from.getName());
org.apache.openejb.loader.IO.copy(from, to);
if (args != null) {
configs.put(to, args);
}
} catch (final IOException e) {
throw new IllegalArgumentException(e);
}
}
}
}
return configs;
}
private static class TrueFilter implements FileFilter {
private static final TrueFilter INSTANCE = new TrueFilter();
@Override
public boolean accept(final File pathname) {
return true;
}
}
}