/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., 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.as.test.integration.naming;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ALLOW_RESOURCE_SERVICE_RESTART;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OPERATION_HEADERS;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOVE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.BINDING;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.BINDING_TYPE;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.CLASS;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.ENVIRONMENT;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.MODULE;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.OBJECT_FACTORY;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.spi.ObjectFactory;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.as.arquillian.api.ServerSetup;
import org.jboss.as.arquillian.api.ServerSetupTask;
import org.jboss.as.arquillian.container.ManagementClient;
import org.jboss.as.naming.subsystem.NamingExtension;
import org.jboss.dmr.ModelNode;
import org.jboss.logging.Logger;
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 org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xnio.IoUtils;
/**
* Test case for binding of {@link ObjectFactory} with environment properties (see AS7-4575). The test case deploys a module,
* containing the object factory class, and then uses the {@link ManagementClient} to bind it. The factory, when invoked to
* retrieve an instance, verifies that the env properties are the ones used in the binding management operation.
*
* @author Eduardo Martins
*/
@RunWith(Arquillian.class)
@ServerSetup(ObjectFactoryWithEnvironmentBindingTestCase.ObjectFactoryWithEnvironmentBindingTestCaseServerSetup.class)
public class ObjectFactoryWithEnvironmentBindingTestCase {
private static Logger LOGGER = Logger.getLogger(ObjectFactoryWithEnvironmentBindingTestCase.class);
// caution, must match module.xml
private static final String MODULE_NAME = "objectFactoryWithEnvironmentBindingModule";
private static final String MODULE_JAR_NAME = "objectFactoryWithEnvironmentBinding.jar";
// the environment properties used in the binding operation
private static final Map<String, String> ENVIRONMENT_PROPERTIES = getEnvironmentProperties();
private static Map<String, String> getEnvironmentProperties() {
final Map<String, String> map = new HashMap<String, String>();
map.put("p1", "v1");
map.put("p2", "v2");
return Collections.unmodifiableMap(map);
}
public static void validateEnvironmentProperties(Hashtable<?, ?> environment) throws IllegalArgumentException {
for (Map.Entry<String, String> property : ENVIRONMENT_PROPERTIES.entrySet()) {
String value = (String) environment.get(property.getKey());
if (value == null || !value.equals(property.getValue())) {
throw new IllegalArgumentException("Unexpected value for environment property named " + property.getKey()
+ ": " + value);
}
}
}
static class ObjectFactoryWithEnvironmentBindingTestCaseServerSetup implements ServerSetupTask {
@Override
public void setup(final ManagementClient managementClient, final String containerId) throws Exception {
deployModule();
// bind the object factory
final ModelNode address = createAddress();
final ModelNode bindingAdd = new ModelNode();
bindingAdd.get(OP).set(ADD);
bindingAdd.get(OP_ADDR).set(address);
bindingAdd.get(BINDING_TYPE).set(OBJECT_FACTORY);
bindingAdd.get(MODULE).set(MODULE_NAME);
bindingAdd.get(CLASS).set(ObjectFactoryWithEnvironmentBinding.class.getName());
final ModelNode environment = new ModelNode();
for (Map.Entry<String, String> property : ENVIRONMENT_PROPERTIES.entrySet()) {
environment.add(property.getKey(), property.getValue());
}
bindingAdd.get(ENVIRONMENT).set(environment);
final ModelNode addResult = managementClient.getControllerClient().execute(bindingAdd);
Assert.assertFalse(addResult.get(FAILURE_DESCRIPTION).toString(), addResult.get(FAILURE_DESCRIPTION).isDefined());
LOGGER.trace("Object factory bound.");
}
private ModelNode createAddress() {
final ModelNode address = new ModelNode();
address.add(SUBSYSTEM, NamingExtension.SUBSYSTEM_NAME);
address.add(BINDING, "java:global/b");
return address;
}
@Override
public void tearDown(final ManagementClient managementClient, final String containerId) throws Exception {
try {
// unbind the object factory
final ModelNode bindingRemove = new ModelNode();
bindingRemove.get(OP).set(REMOVE);
bindingRemove.get(OP_ADDR).set(createAddress());
bindingRemove.get(OPERATION_HEADERS, ALLOW_RESOURCE_SERVICE_RESTART).set(true);
final ModelNode removeResult = managementClient.getControllerClient().execute(bindingRemove);
Assert.assertFalse(removeResult.get(FAILURE_DESCRIPTION).toString(), removeResult.get(FAILURE_DESCRIPTION)
.isDefined());
LOGGER.trace("Object factory unbound.");
} finally {
undeployModule();
LOGGER.trace("Module undeployed.");
}
}
}
@Deployment
public static JavaArchive deploy() {
return ShrinkWrap.create(JavaArchive.class, "ObjectFactoryWithEnvironmentBindingTestCase.jar")
.addClass(ObjectFactoryWithEnvironmentBindingTestCase.class);
}
@Test
public void testBindingWithEnvironment() throws Exception {
InitialContext context = new InitialContext();
Assert.assertEquals("v1", context.lookup("java:global/b"));
}
private static void deployModule() throws IOException {
File testModuleRoot = new File(getModulesHome(), MODULE_NAME);
if (testModuleRoot.exists()) {
throw new IllegalArgumentException(testModuleRoot + " already exists");
}
File testModuleMainDir = new File(testModuleRoot, "main");
if (!testModuleMainDir.mkdirs()) {
throw new IllegalArgumentException("Could not create " + testModuleMainDir);
}
Archive<?> moduleJar = ShrinkWrap.create(JavaArchive.class, MODULE_JAR_NAME)
.addClass(ObjectFactoryWithEnvironmentBinding.class)
.addClass(ObjectFactoryWithEnvironmentBindingTestCase.class);
final InputStream moduleJarInputStream = moduleJar.as(ZipExporter.class).exportAsInputStream();
try {
copyFile(new File(testModuleMainDir, MODULE_JAR_NAME), moduleJarInputStream);
} finally {
IoUtils.safeClose(moduleJarInputStream);
}
URL moduleXmlURL = ObjectFactoryWithEnvironmentBindingTestCase.class.getResource(
ObjectFactoryWithEnvironmentBindingTestCase.class.getSimpleName() + "-module.xml");
if (moduleXmlURL == null) {
throw new IllegalStateException("Could not find module.xml");
}
copyFile(new File(testModuleMainDir, "module.xml"), moduleXmlURL.openStream());
}
private static void undeployModule() {
File testModuleRoot = new File(getModulesHome(), MODULE_NAME);
deleteRecursively(testModuleRoot);
}
private static File getModulesHome() {
String modulePath = System.getProperty("module.path", null);
if (modulePath == null) {
String jbossHome = System.getProperty("jboss.home", null);
if (jbossHome == null) {
throw new IllegalStateException("Neither -Dmodule.path nor -Djboss.home were set");
}
modulePath = jbossHome + File.separatorChar + "modules";
} else {
modulePath = modulePath.split(File.pathSeparator)[0];
}
File moduleDir = new File(modulePath);
if (!moduleDir.exists()) {
throw new IllegalStateException("Determined module path does not exist");
}
if (!moduleDir.isDirectory()) {
throw new IllegalStateException("Determined module path is not a dir");
}
return moduleDir;
}
private static void copyFile(File target, InputStream src) throws IOException {
final BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(target));
try {
int i = src.read();
while (i != -1) {
out.write(i);
i = src.read();
}
} finally {
IoUtils.safeClose(out);
}
}
private static void deleteRecursively(File file) {
if (file.exists()) {
if (file.isDirectory()) {
for (String name : file.list()) {
deleteRecursively(new File(file, name));
}
}
file.delete();
}
}
}