/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, 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.test.jbossmx.implementation.server;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.RuntimeErrorException;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jboss.mx.loading.UnifiedLoaderRepository3;
import org.jboss.mx.loading.UnifiedClassLoader3;
import org.jboss.test.jbossmx.implementation.TestCase;
/** Test of the mbean operation invocation thread context class loader. This
*test case simulates the problem originally seen in Bug#516649. Reproducing the
*steps here requires a number of contrived steps including simulated reloading
*of the mbean from different jars and the loading of the TestData class by
*the main MBeanClassLoader using Class.forName(). These are the actions that
*occur when reloading a sar that contains an ejb-jar.
*
* @author Scott.Stark@jboss.org
* @version $Revision: 81036 $
*/
public class ContextCLTestCase extends TestCase
{
private static URL dataClassURL;
private static File dataJar;
private static UnifiedLoaderRepository3 repo;
private static UnifiedClassLoader3 deployLoader;
private static UnifiedClassLoader3 noLoader;
static Object data0;
private static URL jarUrl;
public ContextCLTestCase(String name)
{
super(name);
}
public void testInvokeNeedingTCL() throws Exception
{
ClassLoader entryCL = Thread.currentThread().getContextClassLoader();
/* Install the mainLoader to simulate how the MBeanServer would be
*running under JBoss
*/
Thread.currentThread().setContextClassLoader(deployLoader);
MBeanServer server = MBeanServerFactory.createMBeanServer();
// Create the ContextCL MBean using the TestClassLoader
try
{
repo.newClassLoader(jarUrl, true);
ObjectName beanName = new ObjectName("org.jboss.test.jbossmx.implementation.server.support:test=ContextCLTestCase");
server.createMBean("org.jboss.test.jbossmx.implementation.server.support.ContextCL", beanName);
getLog().info("Created ContextCL MBean");
// Invoke the useTestData op to test the thread context class loader
server.invoke(beanName, "useTestData", null, null);
getLog().info("Invoked ContextCL.useTestData");
}
catch(RuntimeErrorException e)
{
getLog().error("NestedError", e.getTargetError());
throw e;
}
finally
{
Thread.currentThread().setContextClassLoader(entryCL);
}
MBeanServerFactory.releaseMBeanServer(server);
}
/** This creates two mbean deployment jars, testdata.jar and testdata1.jar.
*A redeployment is simulated by loading
*
* @exception Exception Description of Exception
*/
public void createTestDataJar() throws Exception
{
repo = new UnifiedLoaderRepository3();
dataJar = new File("testdata.jar");
// Find the TestData class
dataClassURL = getClass().getResource("/org/jboss/test/jbossmx/implementation/server/support/TestData.class");
if( dataClassURL == null && dataJar.exists() == false )
fail("Failed to find /org/jboss/test/jbossmx/implementation/server/support/TestData.class");
if( dataClassURL != null )
{
getLog().info("Found TestData at: " + dataClassURL);
// Build a jar file containing only the TestData.class and ContextCL mbean
FileOutputStream fos = new FileOutputStream(dataJar);
Manifest mf = new Manifest();
JarOutputStream jos = new JarOutputStream(fos, mf);
ZipEntry entry = new ZipEntry("org/jboss/test/jbossmx/implementation/server/support/TestData.class");
jos.putNextEntry(entry);
InputStream dataIS = dataClassURL.openStream();
byte[] bytes = new byte[512];
int read = 0;
while( (read = dataIS.read(bytes)) > 0 )
jos.write(bytes, 0, read);
jos.closeEntry();
dataIS.close();
URL mbeanURL = getClass().getResource("/org/jboss/test/jbossmx/implementation/server/support/ContextCL.class");
entry = new ZipEntry("org/jboss/test/jbossmx/implementation/server/support/ContextCL.class");
jos.putNextEntry(entry);
dataIS = mbeanURL.openStream();
while( (read = dataIS.read(bytes)) > 0 )
jos.write(bytes, 0, read);
jos.closeEntry();
dataIS.close();
URL imbeanURL = getClass().getResource("/org/jboss/test/jbossmx/implementation/server/support/ContextCLMBean.class");
entry = new ZipEntry("org/jboss/test/jbossmx/implementation/server/support/ContextCLMBean.class");
jos.putNextEntry(entry);
dataIS = imbeanURL.openStream();
while( (read = dataIS.read(bytes)) > 0 )
jos.write(bytes, 0, read);
jos.closeEntry();
dataIS.close();
getLog().info("Created mbean jar at: "+dataJar.getAbsolutePath());
jos.close();
// Now remote the class files from this classpath
File dataClassFile = new File(dataClassURL.getFile());
getLog().info("Removed TestData.class File: " + dataClassFile.delete());
File mbeanClassFile = new File(mbeanURL.getFile());
getLog().info("Removed ContextCL.class File: " + mbeanClassFile.delete());
File imbeanClassFile = new File(imbeanURL.getFile());
getLog().info("Removed ContextCLMBean.class File: " + imbeanClassFile.delete());
}
// Create a copy of the jar
FileInputStream fis = new FileInputStream("testdata.jar");
FileOutputStream fos = new FileOutputStream("testdata1.jar");
byte[] bytes = new byte[512];
int read = 0;
while( (read = fis.read(bytes)) > 0 )
fos.write(bytes, 0, read);
fis.close();
fos.close();
noLoader = (UnifiedClassLoader3) repo.newClassLoader(null, true);
deployLoader = (UnifiedClassLoader3) repo.newClassLoader(dataJar.toURL(), true);
Class c0 = deployLoader.loadClass("org.jboss.test.jbossmx.implementation.server.support.TestData");
getLog().info("TestData #0 ProtectionDomain: "+c0.getProtectionDomain());
Class c1 = Class.forName("org.jboss.test.jbossmx.implementation.server.support.TestData",
false, noLoader);
getLog().info("TestData #1 ProtectionDomain: "+c1.getProtectionDomain());
repo.removeClassLoader(deployLoader);
// Simulate a redeploy
File data1Jar = new File("testdata1.jar");
jarUrl = data1Jar.toURL();
deployLoader = (UnifiedClassLoader3) repo.newClassLoader(jarUrl, true);
c0 = deployLoader.loadClass("org.jboss.test.jbossmx.implementation.server.support.TestData");
getLog().info("Reloaded TestData #0 ProtectionDomain: "+c0.getProtectionDomain());
data0 = c0.newInstance();
}
/** Setup the test suite.
*/
public static Test suite()
{
TestSuite suite = new TestSuite();
/* If this is running under java5 just return as there is no guarentee
of what the class loader of the mbean is.
*/
try
{
Class annotationClass = Class.forName("java.lang.annotation.Annotation");
// Running under java5+, use an empty suite
}
catch(ClassNotFoundException e)
{
// Running under jdk1.4.x, continue
suite.addTest(new ContextCLTestCase("createTestDataJar"));
suite.addTest(new ContextCLTestCase("testInvokeNeedingTCL"));
}
return suite;
}
}