/* * 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, false); } 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; } } }