/*
* 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.config;
import org.apache.openejb.assembler.classic.Assembler;
import org.apache.openejb.assembler.classic.ResourceInfo;
import org.apache.openejb.assembler.classic.SecurityServiceInfo;
import org.apache.openejb.assembler.classic.TransactionServiceInfo;
import org.apache.openejb.config.sys.Openejb;
import org.apache.openejb.config.sys.Resource;
import org.apache.openejb.core.ivm.naming.InitContextFactory;
import org.apache.openejb.loader.Files;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.loader.provisining.ProvisioningResolver;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.PropertyPlaceHolderHelper;
import org.apache.xbean.asm5.ClassWriter;
import org.apache.xbean.asm5.MethodVisitor;
import org.apache.xbean.asm5.Opcodes;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import javax.naming.InitialContext;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static org.apache.xbean.asm5.Opcodes.ACC_PUBLIC;
import static org.apache.xbean.asm5.Opcodes.ACC_SUPER;
import static org.apache.xbean.asm5.Opcodes.ALOAD;
import static org.apache.xbean.asm5.Opcodes.INVOKESPECIAL;
import static org.apache.xbean.asm5.Opcodes.RETURN;
/**
* @version $Rev$ $Date$
*/
public class ServiceClasspathTest extends Assert {
@After
@Before
public void reset() {
SystemInstance.reset();
PropertyPlaceHolderHelper.reset();
}
@Test
public void test() throws Exception {
final String className = "org.superbiz.foo.Orange";
final File jar = subclass(Color.class, className);
System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
final Openejb openejb = new Openejb();
final Resource resource = new Resource();
openejb.getResource().add(resource);
resource.setClassName(className);
resource.setType(className);
resource.setId("Orange");
resource.getProperties().put("red", "FF");
resource.getProperties().put("green", "99");
resource.getProperties().put("blue", "00");
resource.setClasspath(jar.getAbsolutePath());
createEnvrt();
final ConfigurationFactory config = new ConfigurationFactory();
final Assembler assembler = new Assembler();
assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
assembler.createSecurityService(config.configureService(SecurityServiceInfo.class));
final ResourceInfo serviceInfo = config.configureService(resource, ResourceInfo.class);
// serviceInfo.classpath = new URI[]{jar.toURI()};
assembler.createResource(serviceInfo);
final InitialContext initialContext = new InitialContext();
final Color color = (Color) initialContext.lookup("openejb:Resource/Orange");
assertNotNull(color);
assertEquals("Orange.FF", color.getRed());
assertEquals("Orange.99", color.getGreen());
assertEquals("Orange.00", color.getBlue());
}
private void createEnvrt() {
new File(SystemInstance.get().getBase().getDirectory(), ProvisioningResolver.cache()).mkdirs();
}
@Test
public void testXml() throws Exception {
final String className = "org.superbiz.foo.Orange";
final File jar = subclass(Color.class, className);
final File xml = File.createTempFile("config-", ".xml");
xml.deleteOnExit();
final PrintStream out = new PrintStream(IO.write(xml));
out.println("<openejb>\n" +
" <Resource id=\"Orange\" type=\"org.superbiz.foo.Orange\" class-name=\"org.superbiz.foo.Orange\" classpath=\"" + jar.getAbsolutePath() + "\">\n" +
" red = FF\n" +
" green = 99\n" +
" blue = 00\n" +
" </Resource>\n" +
"</openejb>");
out.close();
System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
final ConfigurationFactory config = new ConfigurationFactory();
final Assembler assembler = new Assembler();
createEnvrt();
assembler.buildContainerSystem(config.getOpenEjbConfiguration(xml));
final InitialContext initialContext = new InitialContext();
final Color color = (Color) initialContext.lookup("openejb:Resource/Orange");
assertNotNull(color);
assertEquals("Orange.FF", color.getRed());
assertEquals("Orange.99", color.getGreen());
assertEquals("Orange.00", color.getBlue());
}
@Test
public void testRelativePath() throws Exception {
final String className = "org.superbiz.foo.Orange";
final File jar = subclass(Color.class, className);
final File xml = File.createTempFile("config-", ".xml");
xml.deleteOnExit();
final PrintStream out = new PrintStream(IO.write(xml));
out.println("<openejb>\n" +
" <Resource id=\"Orange\" type=\"org.superbiz.foo.Orange\"" +
" class-name=\"org.superbiz.foo.Orange\"" +
" classpath=\"${openejb.home}/" + jar.getName() + "\">\n" +
" red = FF\n" +
" green = 99\n" +
" blue = 00\n" +
" </Resource>\n" +
"</openejb>");
out.close();
new File(jar.getParentFile(), "temp").mkdirs();
System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
final Properties properties = new Properties();
properties.setProperty("openejb.home", jar.getParentFile().getAbsolutePath());
SystemInstance.init(properties);
PropertyPlaceHolderHelper.reset();
createEnvrt();
final ConfigurationFactory config = new ConfigurationFactory();
final Assembler assembler = new Assembler();
assembler.buildContainerSystem(config.getOpenEjbConfiguration(xml));
final InitialContext initialContext = new InitialContext();
final Color color = (Color) initialContext.lookup("openejb:Resource/Orange");
assertNotNull(color);
assertEquals("Orange.FF", color.getRed());
assertEquals("Orange.99", color.getGreen());
assertEquals("Orange.00", color.getBlue());
}
@Test
public void testJson() throws Exception {
final String className = "org.superbiz.foo.Orange";
final File jar = subclass(Color.class, className);
final File json = File.createTempFile("config-", ".json");
json.deleteOnExit();
final PrintStream out = new PrintStream(IO.write(json));
out.println("{\n" +
" \"resources\":{\n" +
" \"Orange\":{\n" +
" \"type\":\"org.superbiz.foo.Orange\",\n" +
" \"class-name\":\"org.superbiz.foo.Orange\",\n" +
" \"classpath\":\"" + jar.getAbsolutePath() + "\",\n" +
" \"properties\":{\n" +
" \"red\":\"FF\",\n" +
" \"green\":\"99\",\n" +
" \"blue\":\"00\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n");
out.close();
System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
final ConfigurationFactory config = new ConfigurationFactory();
final Assembler assembler = new Assembler();
createEnvrt();
assembler.buildContainerSystem(config.getOpenEjbConfiguration(json));
final InitialContext initialContext = new InitialContext();
final Color color = (Color) initialContext.lookup("openejb:Resource/Orange");
assertNotNull(color);
assertEquals("Orange.FF", color.getRed());
assertEquals("Orange.99", color.getGreen());
assertEquals("Orange.00", color.getBlue());
}
public static class Color {
private String red;
private String green;
private String blue;
public String getRed() {
return wrap(red);
}
public String getGreen() {
return wrap(green);
}
public String getBlue() {
return wrap(blue);
}
public void setRed(final String red) {
this.red = red;
}
public void setGreen(final String green) {
this.green = green;
}
public void setBlue(final String blue) {
this.blue = blue;
}
private String wrap(final String value) {
return this.getClass().getSimpleName() + "." + value;
}
}
public static File subclass(final Class<?> parent, final String subclassName) throws Exception {
final String subclassNameInternal = subclassName.replace('.', '/');
final byte[] bytes;
{
final ClassWriter cw = new ClassWriter(0);
final String parentClassNameInternal = parent.getName().replace('.', '/');
cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + ACC_SUPER, subclassNameInternal, null, parentClassNameInternal, null);
final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, parentClassNameInternal, "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
cw.visitEnd();
bytes = cw.toByteArray();
}
return Archive.archive().add(subclassNameInternal + ".class", bytes).asJar();
}
/**
* @version $Revision$ $Date$
*/
public static class Archive {
final Map<String, String> manifest = new HashMap<String, String>();
final Map<String, byte[]> entries = new HashMap<String, byte[]>();
public static Archive archive() {
return new Archive();
}
public Archive manifest(final String key, final Object value) {
manifest.put(key, value.toString());
return this;
}
public Archive manifest(final String key, final Class value) {
manifest.put(key, value.getName());
return this;
}
public Archive add(final Class<?> clazz) {
try {
final String name = clazz.getName().replace('.', '/') + ".class";
final URL resource = this.getClass().getClassLoader().getResource(name);
final InputStream from = new BufferedInputStream(resource.openStream());
final ByteArrayOutputStream to = new ByteArrayOutputStream();
final byte[] buffer = new byte[1024];
int length;
while ((length = from.read(buffer)) != -1) {
to.write(buffer, 0, length);
}
to.flush();
final byte[] bytes = to.toByteArray();
return add(name, bytes);
} catch (final IOException e) {
throw new IllegalStateException(e);
}
}
public Archive add(final String name, final byte[] bytes) {
entries.put(name, bytes);
return this;
}
public File toJar() throws IOException {
final File file = File.createTempFile("archive-", ".jar");
file.deleteOnExit();
// Create the ZIP file
final ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
for (final Map.Entry<String, byte[]> entry : entries().entrySet()) {
out.putNextEntry(new ZipEntry(entry.getKey()));
out.write(entry.getValue());
}
// Complete the ZIP file
out.close();
return file;
}
public File asJar() {
try {
return toJar();
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
public File toDir() throws IOException {
final File classpath = Files.tmpdir();
for (final Map.Entry<String, byte[]> entry : entries().entrySet()) {
final String key = entry.getKey().replace('/', File.separatorChar);
final File file = new File(classpath, key);
final File d = file.getParentFile();
if (!d.exists()) assertTrue(d.getAbsolutePath(), d.mkdirs());
final BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
out.write(entry.getValue());
out.close();
}
return classpath;
}
public File asDir() {
try {
return toDir();
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private HashMap<String, byte[]> entries() {
final HashMap<String, byte[]> entries = new HashMap<String, byte[]>(this.entries);
entries.put("META-INF/MANIFEST.MF", buildManifest().getBytes());
return entries;
}
private String buildManifest() {
return Join.join("\r\n", new Join.NameCallback<Map.Entry<String, String>>() {
@Override
public String getName(final Map.Entry<String, String> entry) {
return entry.getKey() + ": " + entry.getValue();
}
}, manifest.entrySet());
}
}
}