Index: src/main/java/org/jboss/arquillian/glassfish/embedded30/GlassFishEmbeddedContainer.java =================================================================== --- src/main/java/org/jboss/arquillian/glassfish/embedded30/GlassFishEmbeddedContainer.java (revision 4473) +++ src/main/java/org/jboss/arquillian/glassfish/embedded30/GlassFishEmbeddedContainer.java (working copy) @@ -17,12 +17,21 @@ package org.jboss.arquillian.glassfish.embedded30; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.glassfish.admin.cli.resources.AddResources; +import org.glassfish.api.ActionReport; +import org.glassfish.api.admin.CommandRunner; +import org.glassfish.api.admin.ParameterMap; import org.glassfish.api.deployment.DeployCommandParameters; import org.glassfish.api.deployment.UndeployCommandParameters; import org.glassfish.api.embedded.ContainerBuilder; -import org.glassfish.api.embedded.EmbeddedContainer; import org.glassfish.api.embedded.EmbeddedFileSystem; import org.glassfish.api.embedded.Server; import org.jboss.arquillian.protocol.servlet.ServletMethodExecutor; @@ -34,52 +43,83 @@ import org.jboss.arquillian.spi.LifecycleException; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.glassfish.api.ShrinkwrapReadableArchive; +import org.jvnet.hk2.annotations.Service; /** * GlassFishEmbeddedContainer * * @author Aslak Knutsen + * @author Dan Allen * @version $Revision: $ + * @see org.glassfish.admin.cli.resources.AddResources */ public class GlassFishEmbeddedContainer implements DeployableContainer { + public static final String HTTP_PROTOCOL = "http"; + public static final String DEFAULT_PARAM = "DEFAULT"; + + private static final Logger log = Logger.getLogger(GlassFishEmbeddedContainer.class.getName()); + private String target = "server"; private Server server; - private GlassFishConfiguration configuration; + private GlassFishConfiguration containerConfig; public GlassFishEmbeddedContainer() { } - public void setup(Context context, Configuration configuration) + public void setup(Context context, Configuration arquillianConfig) { - this.configuration = configuration.getContainerConfig(GlassFishConfiguration.class); + containerConfig = arquillianConfig.getContainerConfig(GlassFishConfiguration.class); - final Server.Builder builder = new Server.Builder(GlassFishEmbeddedContainer.class.getName()); + final Server.Builder serverBuilder = new Server.Builder(GlassFishEmbeddedContainer.class.getName()); - final EmbeddedFileSystem.Builder embeddedFsBuilder = new EmbeddedFileSystem.Builder(); - final EmbeddedFileSystem embeddedFs = embeddedFsBuilder - .instanceRoot( - new File( - this.configuration.getInstanceRoot())) - .autoDelete(this.configuration.getAutoDelete()) - .build(); - builder.embeddedFileSystem(embeddedFs); + final EmbeddedFileSystem.Builder embeddedFsBuilder = new EmbeddedFileSystem.Builder() + .instanceRoot(new File(containerConfig.getInstanceRoot())) + .autoDelete(containerConfig.isAutoDelete()); + if (containerConfig.getDomainXml() != null) + { + embeddedFsBuilder.configurationFile(new File(containerConfig.getDomainXml())); + } - server = builder.build(); + server = serverBuilder.embeddedFileSystem(embeddedFsBuilder.build()).build(); server.addContainer(ContainerBuilder.Type.all); + + if (containerConfig.getResourcesXml() != null) + { + try + { + // GlassFish's resources XML parser is hardcoded to look for the DTD in this location + File resourcesDtd = new File(server.getFileSystem().instanceRoot, "lib/dtds/sun-resources_1_4.dtd"); + if (!resourcesDtd.exists()) + { + resourcesDtd.getParentFile().mkdirs(); + copyWithClose(getClass().getClassLoader().getResourceAsStream("META-INF/sun-resources_1_4.dtd"), + new FileOutputStream(resourcesDtd)); + } + ParameterMap params = new ParameterMap(); + params.add(DEFAULT_PARAM, containerConfig.getResourcesXml()); + { + executeCommand(AddResources.class.getAnnotation(Service.class).name(), server, params); + } + } + catch (Throwable ex) + { + throw new RuntimeException(ex); + } + } } public void start(Context context) throws LifecycleException { try { - for(EmbeddedContainer contianer : server.getContainers()) { - contianer.bind(server.createPort(configuration.getBindPort()), "http"); - contianer.start(); - } + // embedded glassfish automatically binds the first port created to http + // the documentation, however, is very fuzzy + server.createPort(containerConfig.getHttpPort()); + server.start(); } catch (Exception e) { @@ -122,15 +162,15 @@ { return new ServletMethodExecutor( new URL( - "http", + HTTP_PROTOCOL, "localhost", - configuration.getBindPort(), + containerConfig.getHttpPort(), "/") ); } catch (Exception e) { - throw new RuntimeException("Could not create ContianerMethodExecutor", e); + throw new RuntimeException("Could not create ContainerMethodExecutor", e); } } @@ -153,4 +193,65 @@ { return archiveName.substring(0, archiveName.lastIndexOf(".")); } + + private void executeCommand(String command, Server server, ParameterMap params) throws Throwable + { + CommandRunner runner = server.getHabitat().getComponent(CommandRunner.class); + ActionReport report = server.getHabitat().getComponent(ActionReport.class); + CommandRunner.CommandInvocation invocation = runner.getCommandInvocation(command, report); + if (params != null) + { + invocation.parameters(params); + } + + invocation.execute(); + + if (report.hasFailures()) + { + throw report.getFailureCause(); + } + } + + /** + * Copies the contents from an InputStream to an OutputStream and closes both streams. + */ + public static void copyWithClose(InputStream input, OutputStream output) throws IOException + { + try + { + final byte[] buffer = new byte[4096]; + int read = 0; + while ((read = input.read(buffer)) != -1) + { + output.write(buffer, 0, read); + } + + output.flush(); + } + finally + { + try + { + input.close(); + } + catch (final IOException ignore) + { + if (log.isLoggable(Level.FINER)) + { + log.finer("Could not close stream due to: " + ignore.getMessage() + "; ignoring"); + } + } + try + { + output.close(); + } + catch (final IOException ignore) + { + if (log.isLoggable(Level.FINER)) + { + log.finer("Could not close stream due to: " + ignore.getMessage() + "; ignoring"); + } + } + } + } } Index: src/main/java/org/jboss/arquillian/glassfish/embedded30/GlassFishConfiguration.java =================================================================== --- src/main/java/org/jboss/arquillian/glassfish/embedded30/GlassFishConfiguration.java (revision 4473) +++ src/main/java/org/jboss/arquillian/glassfish/embedded30/GlassFishConfiguration.java (working copy) @@ -30,23 +30,25 @@ */ public class GlassFishConfiguration implements ContainerConfiguration { - private int bindPort = 8181; + private int httpPort = 8181; private String instanceRoot = "target/glassfish_" + UUID.randomUUID().toString(); private boolean autoDelete = true; + private String domainXml; + private String resourcesXml; public ContainerProfile getContainerProfile() { return ContainerProfile.CLIENT; } - public int getBindPort() + public int getHttpPort() { - return bindPort; + return httpPort; } - public void setBindPort(int bindPort) + public void setHttpPort(int httpPort) { - this.bindPort = bindPort; + this.httpPort = httpPort; } public String getInstanceRoot() @@ -59,7 +61,7 @@ this.instanceRoot = instanceRoot; } - public boolean getAutoDelete() + public boolean isAutoDelete() { return autoDelete; } @@ -68,4 +70,24 @@ { this.autoDelete = autoDelete; } + + public String getDomainXml() + { + return domainXml; + } + + public void setDomainXml(String domainXml) + { + this.domainXml = domainXml; + } + + public String getResourcesXml() + { + return resourcesXml; + } + + public void setResourcesXml(String resourcesXml) + { + this.resourcesXml = resourcesXml; + } } Index: src/main/resources/META-INF/sun-resources_1_4.dtd =================================================================== --- src/main/resources/META-INF/sun-resources_1_4.dtd (revision 0) +++ src/main/resources/META-INF/sun-resources_1_4.dtd (revision 0) @@ -0,0 +1,833 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +