/* * JBoss, Home of Professional Open Source. * Copyright 2015, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.wsf.test; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Inet6Address; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.util.Hashtable; import java.util.Iterator; import java.util.Map.Entry; import java.util.Properties; import java.util.WeakHashMap; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.ws.Service; import javax.xml.ws.Service.Mode; import javax.xml.ws.soap.SOAPBinding; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.exporter.ZipExporter; import org.jboss.shrinkwrap.api.spec.JavaArchive; import sun.net.util.IPAddressUtil; /** * A JBossWS test helper that deals with test deployment/undeployment, etc. * * @author Thomas.Diesler@jboss.org * @author ropalka@redhat.com * @author alessio.soldano@jboss.com */ public class JBossWSTestHelper { private static final String SYSPROP_JBOSSWS_INTEGRATION_TARGET = "jbossws.integration.target"; private static final String SYSPROP_JBOSS_BIND_ADDRESS = "jboss.bind.address"; private static final String SYSPROP_JBOSS_REMOTING_PROTOCOL = "jboss.remoting.protocol"; private static final String SYSPROP_INITIAL_CONTEXT_FACTORY = "jboss.initial.context.factory"; private static final String SYSPROP_TEST_ARCHIVE_DIRECTORY = "test.archive.directory"; private static final String SYSPROP_TEST_RESOURCES_DIRECTORY = "test.resources.directory"; private static final String SYSPROP_DEFAULT_CONTAINER_QUALIFIER = "default.container.qualifier"; private static final String SYSPROP_DEFAULT_CONTAINER_GROUP_QUALIFIER = "default.container.group.qualifier"; private static final String SYSPROP_CONTAINER_PORT_OFFSET_PREFIX = "port-offset."; private static final String SYSPROP_AS_SERVER_CONN_RETRIEVAL_ATTEMPTS = "test.as.server.connection.retrieval.attempts"; private static final String TEST_USERNAME = "test.username"; private static final String TEST_PASSWORD = "test.password"; private static final int AS_SERVER_CONN_RETRIEVAL_ATTEMPTS = Integer.getInteger(SYSPROP_AS_SERVER_CONN_RETRIEVAL_ATTEMPTS, 5); private static final String testArchiveDir = System.getProperty(SYSPROP_TEST_ARCHIVE_DIRECTORY); private static final String testResourcesDir = System.getProperty(SYSPROP_TEST_RESOURCES_DIRECTORY); private static final String integrationTarget; private static final String implInfo; private static final String serverHost = System.getProperty(SYSPROP_JBOSS_BIND_ADDRESS, "localhost"); private static final String remotingProtocol = System.getProperty(SYSPROP_JBOSS_REMOTING_PROTOCOL); private static final String initialContextFactory = System.getProperty(SYSPROP_INITIAL_CONTEXT_FACTORY); private static WeakHashMap<ClassLoader, Hashtable<String, String>> containerEnvs = new WeakHashMap<ClassLoader, Hashtable<String,String>>(); static { integrationTarget = System.getProperty(SYSPROP_JBOSSWS_INTEGRATION_TARGET); if (integrationTarget == null) throw new IllegalStateException("Cannot obtain system property: " + SYSPROP_JBOSSWS_INTEGRATION_TARGET); Object obj = getImplementationObject(); implInfo = obj.getClass().getPackage().getName(); } /** Deploy the given archive to the appclient. * Archive name is always in form archive.ear#appclient.jar */ public static Process deployAppclient(final String archive, final OutputStream appclientOS, final String... appclientArgs) throws Exception { return AppclientHelper.deployAppclient(archive, appclientOS, appclientArgs); } /** Undeploy the given archive from the appclient * Archive name is always in form archive.ear#appclient.jar */ public static void undeployAppclient(final String archive, boolean awaitShutdown) throws Exception { AppclientHelper.undeployAppclient(archive, awaitShutdown); } public static boolean isTargetWildFly9() { String target = getIntegrationTarget(); return target.startsWith("wildfly9"); } public static boolean isTargetWildFly10() { String target = getIntegrationTarget(); return target.startsWith("wildfly10"); } public static boolean isIntegrationCXF() { String vendor = getImplementationInfo(); return vendor.toLowerCase().indexOf("apache") != -1; } private static String getImplementationInfo() { return implInfo; } private static Object getImplementationObject() { Service service = Service.create(new QName("dummyService")); Object obj = service.getHandlerResolver(); if (obj == null) { service.addPort(new QName("dummyPort"), SOAPBinding.SOAP11HTTP_BINDING, "http://dummy-address"); obj = service.createDispatch(new QName("dummyPort"), Source.class, Mode.PAYLOAD); } return obj; } public static String getRemotingProtocol() { return remotingProtocol; } public static String getInitialContextFactory() { return initialContextFactory; } /** * Get the JBoss server host from system property "jboss.bind.address" * This defaults to "localhost" */ public static String getServerHost() { return toIPv6URLFormat(serverHost); } public static int getServerPort() { return getServerPort(null, null); } public static int getServerPort(String groupQualifier, String containerQualifier) { return 8080 + getContainerPortOffset(groupQualifier, containerQualifier); } public static int getSecureServerPort(String groupQualifier, String containerQualifier) { return 8443 + getContainerPortOffset(groupQualifier, containerQualifier); } protected static int getContainerPortOffset(String groupQualifier, String containerQualifier) { Hashtable<String, String> env = getContainerEnvironment(); if (groupQualifier == null) { groupQualifier = env.get(SYSPROP_DEFAULT_CONTAINER_GROUP_QUALIFIER); } if (containerQualifier == null) { containerQualifier = env.get(SYSPROP_DEFAULT_CONTAINER_QUALIFIER); } String offset = env.get(SYSPROP_CONTAINER_PORT_OFFSET_PREFIX + groupQualifier + "." + containerQualifier); return offset != null ? Integer.valueOf(offset) : 0; } private static Hashtable<String, String> getContainerEnvironment() { Hashtable<String, String> env; ClassLoader tccl = Thread.currentThread().getContextClassLoader(); synchronized (containerEnvs) { env = containerEnvs.get(tccl); if (env == null) { env = new Hashtable<String, String>(); final InputStream is = tccl.getResourceAsStream("container.properties"); try { if (is != null) { final Properties props = new Properties(); props.load(is); Entry<Object, Object> entry; final Iterator<Entry<Object, Object>> entries = props.entrySet().iterator(); while (entries.hasNext()) { entry = entries.next(); env.put((String)entry.getKey(), (String)entry.getValue()); } } } catch (IOException e) { throw new RuntimeException(e); } containerEnvs.put(tccl, env); } return env; } } public static String toIPv6URLFormat(final String host) { try { if (host.startsWith("[") || host.startsWith(":")) { if (System.getProperty("java.net.preferIPv4Stack") == null) { throw new IllegalStateException("always provide java.net.preferIPv4Stack JVM property when using IPv6 address format"); } if (System.getProperty("java.net.preferIPv6Addresses") == null) { throw new IllegalStateException("always provide java.net.preferIPv6Addresses JVM property when using IPv6 address format"); } } final boolean isIPv6Address = InetAddress.getByName(host) instanceof Inet6Address; final boolean isIPv6Literal = isIPv6Address && IPAddressUtil.isIPv6LiteralAddress(host.replaceAll("^\\[(.*)\\]$","$1")); final boolean isIPv6LiteralFormattedForURI = isIPv6Literal && host.startsWith("["); return isIPv6Literal && !isIPv6LiteralFormattedForURI ? "[" + host + "]" : host; } catch (final UnknownHostException e) { throw new RuntimeException(e); } } public static MBeanServerConnection getServer() { return getServer(null, null); } public static MBeanServerConnection getServer(String groupQualifier, String containerQualifier) { int portOffset = getContainerPortOffset(groupQualifier, containerQualifier); String integrationTarget = getIntegrationTarget(); MBeanServerConnection server; if (integrationTarget.startsWith("wildfly")) { server = getServerConnection("service:jmx:http-remoting-jmx://" + getServerHost() + ":" + (9990 + portOffset)); } else { throw new IllegalStateException("Unsupported target container: " + integrationTarget); } return server; } private static MBeanServerConnection getServerConnection(String jmxServiceUrl) { final String urlString = System.getProperty("jmx.service.url", jmxServiceUrl); JMXServiceURL serviceURL = null; JMXConnector connector = null; try { serviceURL = new JMXServiceURL(urlString); } catch (MalformedURLException e1) { throw new IllegalStateException(e1); } //add more tries to get the connection. Workaround to fix some test failures caused by connection is not established in 5 seconds for (int i = 0; i < AS_SERVER_CONN_RETRIEVAL_ATTEMPTS && connector == null; i++) { try { connector = JMXConnectorFactory.connect(serviceURL, null); } catch (IOException ex) { throw new IllegalStateException("Cannot obtain MBeanServerConnection to: " + urlString, ex); } catch (RuntimeException e) { if (e.getMessage().contains("WAITING") && i < AS_SERVER_CONN_RETRIEVAL_ATTEMPTS - 1) { continue; } else { throw e; } } } try { return connector.getMBeanServerConnection(); } catch (Exception e) { throw new IllegalStateException("Cannot obtain MBeanServerConnection to: " + urlString, e); } } public static String getIntegrationTarget() { return integrationTarget; } /** Try to discover the URL for the deployment archive */ public static URL getArchiveURL(String archive) throws MalformedURLException { return getArchiveFile(archive).toURI().toURL(); } /** Try to discover the File for the deployment archive */ public static File getArchiveFile(String archive) { File file = new File(archive); if (file.exists()) return file; file = new File(getTestArchiveDir() + "/" + archive); if (file.exists()) return file; String notSet = (getTestArchiveDir() == null ? " System property '" + SYSPROP_TEST_ARCHIVE_DIRECTORY + "' not set." : ""); throw new IllegalArgumentException("Cannot obtain '" + getTestArchiveDir() + "/" + archive + "'." + notSet); } /** Try to discover the URL for the test resource */ public static URL getResourceURL(String resource) throws MalformedURLException { return getResourceFile(resource).toURI().toURL(); } /** Try to discover the File for the test resource */ public static File getResourceFile(String resource) { File file = new File(resource); if (file.exists()) return file; file = new File(getTestResourcesDir() + "/" + resource); if (file.exists()) return file; String notSet = (getTestResourcesDir() == null ? " System property '" + SYSPROP_TEST_RESOURCES_DIRECTORY + "' not set." : ""); throw new IllegalArgumentException("Cannot obtain '" + getTestResourcesDir() + "/" + resource + "'." + notSet); } public static String getTestArchiveDir() { return testArchiveDir; } public static String getTestResourcesDir() { return testResourcesDir; } public static String getTestUsername() { String prop = System.getProperty(TEST_USERNAME); if (prop == null || "".equals(prop) || ("${" + TEST_USERNAME + "}").equals(prop)) { prop = "kermit"; } return prop; } public static String getTestPassword() { String prop = System.getProperty(TEST_PASSWORD); if (prop == null || "".equals(prop) || ("${" + TEST_PASSWORD + "}").equals(prop)) { prop = "thefrog"; } return prop; } @SuppressWarnings("rawtypes") public static void writeToFile(Archive archive) { File archiveDir = assertArchiveDirExists(); File file = new File(archiveDir, archive.getName()); archive.as(ZipExporter.class).exportTo(file, true); } public static abstract class BaseDeployment<T extends org.jboss.shrinkwrap.api.Archive<T>> { protected T archive; public BaseDeployment(Class<T> clazz, String name) { archive = ShrinkWrap.create(clazz, name); } public T create() { return archive; } public T writeToFile() { File archiveDir = assertArchiveDirExists(); File file = new File(archiveDir, archive.getName()); archive.as(ZipExporter.class).exportTo(file, true); return archive; } public String getName() { return archive.getName(); } } public static File assertArchiveDirExists() { File archiveDir = new File(testArchiveDir); if (!archiveDir.exists()) { if (testArchiveDir == null) throw new IllegalArgumentException("Cannot create archive - system property '" + JBossWSTestHelper.SYSPROP_TEST_ARCHIVE_DIRECTORY + "' not set."); if (!archiveDir.mkdirs() && !archiveDir.exists()) throw new IllegalArgumentException("Cannot create archive - can not create test archive directory '" + archiveDir.getAbsolutePath() + "'"); } return archiveDir; } public static String writeToFile(BaseDeployment<?>... deps) { if (deps == null) { return ""; } StringBuilder sb = new StringBuilder(); for (BaseDeployment<?> dep : deps) { sb.append(dep.writeToFile().getName()); sb.append(" "); } return sb.toString().trim(); } public static abstract class JarDeployment extends BaseDeployment<JavaArchive> { public JarDeployment(String name) { super(JavaArchive.class, name); } } }