Skip to content

Commit

Permalink
Implemented FORGE-1109 - CLAC should convert exception types (preserv…
Browse files Browse the repository at this point in the history
…ing stack traces) wherever possible.
  • Loading branch information
lincolnthree committed Aug 17, 2013
1 parent 5bc8f28 commit c114c4f
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.jboss.forge.classloader.mock.exceptions;

/**
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*
*/
public class ExceptionFactory
{

public void throwException() throws MockException
{
throw new MockException("A message.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.jboss.forge.classloader.mock.exceptions;

/**
* @author <a href="mailto:lincolnbaxter@gmail.com">Lincoln Baxter, III</a>
*
*/
public class MockException extends RuntimeException
{
private static final long serialVersionUID = 5266075954460779189L;

public MockException()
{
super();
}

public MockException(String message, Throwable cause)
{
super(message, cause);
}

public MockException(String message)
{
super(message);
}

public MockException(Throwable cause)
{
super(cause);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class ClassLoaderAdapterEnumCollisionsTest
public class ClassLoaderAdapterEnumTranslationTest
{
@Deployment(order = 3)
public static ForgeArchive getDeployment()
Expand All @@ -32,7 +32,7 @@ public static ForgeArchive getDeployment()
.create(ForgeArchive.class)
.addBeansXML()
.addClasses(SimpleEnum.class, SimpleEnumFactory.class)
.addAsLocalServices(ClassLoaderAdapterEnumCollisionsTest.class);
.addAsLocalServices(ClassLoaderAdapterEnumTranslationTest.class);

return archive;
}
Expand All @@ -52,7 +52,7 @@ public void testSimpleEnumCollision() throws Exception
{
AddonRegistry registry = LocalServices.getFurnace(getClass().getClassLoader())
.getAddonRegistry();
ClassLoader thisLoader = ClassLoaderAdapterEnumCollisionsTest.class.getClassLoader();
ClassLoader thisLoader = ClassLoaderAdapterEnumTranslationTest.class.getClassLoader();
ClassLoader dep1Loader = registry.getAddon(AddonId.from("dep", "1")).getClassLoader();

Class<?> foreignType = dep1Loader.loadClass(SimpleEnumFactory.class.getName());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Eclipse Public License version 1.0, available at
* http://www.eclipse.org/legal/epl-v10.html
*/

package org.jboss.forge.classloader;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.forge.arquillian.archive.ForgeArchive;
import org.jboss.forge.arquillian.services.LocalServices;
import org.jboss.forge.classloader.mock.exceptions.ExceptionFactory;
import org.jboss.forge.classloader.mock.exceptions.MockException;
import org.jboss.forge.furnace.addons.AddonId;
import org.jboss.forge.furnace.addons.AddonRegistry;
import org.jboss.forge.furnace.proxy.ClassLoaderAdapterBuilder;
import org.jboss.forge.furnace.proxy.Proxies;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(Arquillian.class)
public class ClassLoaderAdapterExceptionProxyTest
{
@Deployment(order = 3)
public static ForgeArchive getDeployment()
{
ForgeArchive archive = ShrinkWrap
.create(ForgeArchive.class)
.addClasses(MockException.class, ExceptionFactory.class)
.addAsLocalServices(ClassLoaderAdapterExceptionProxyTest.class);

return archive;
}

@Deployment(name = "dep,1", testable = false, order = 2)
public static ForgeArchive getDeploymentDep1()
{
ForgeArchive archive = ShrinkWrap.create(ForgeArchive.class)
.addClasses(MockException.class, ExceptionFactory.class)
.addBeansXML();

return archive;
}

@Test
public void testSharedImplementationTypeIncludedInProxy() throws Exception
{
AddonRegistry registry = LocalServices.getFurnace(getClass().getClassLoader())
.getAddonRegistry();
ClassLoader thisLoader = ClassLoaderAdapterExceptionProxyTest.class.getClassLoader();
ClassLoader dep1Loader = registry.getAddon(AddonId.from("dep", "1")).getClassLoader();

Class<?> foreignType = dep1Loader.loadClass(ExceptionFactory.class.getName());
try
{
ExceptionFactory factory = (ExceptionFactory) foreignType.newInstance();

Assert.fail("Should have received a " + ClassCastException.class.getName() + " but got a real object ["
+ factory + "]");
}
catch (ClassCastException e)
{
}
catch (Exception e)
{
Assert.fail("Should have received a " + ClassCastException.class.getName() + " but was: " + e);
}

Object delegate = foreignType.newInstance();
ExceptionFactory enhancedFactory = (ExceptionFactory) ClassLoaderAdapterBuilder.callingLoader(thisLoader)
.delegateLoader(dep1Loader).enhance(delegate);

Assert.assertTrue(Proxies.isForgeProxy(enhancedFactory));

try
{
enhancedFactory.throwException();
}
catch (MockException e)
{
Assert.assertTrue(Proxies.isForgeProxy(e));
}
catch (Exception e)
{
Assert.fail("Exception was not of proper type.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ public Object call() throws Exception
catch (InvocationTargetException e)
{
if (e.getCause() instanceof Exception)
throw (Exception) e.getCause();
throw e;
throw enhanceException(delegateMethod, (Exception) e.getCause());
throw enhanceException(delegateMethod, e);
}

}
Expand Down Expand Up @@ -197,6 +197,47 @@ private Object enhanceResult(final Method method, Object result)
return result;
}

private Exception enhanceException(final Method method, Exception exception)
{
try
{
if (exception != null)
{
Exception unwrappedException = Proxies.unwrap(exception);
Class<?> unwrappedExceptionType = unwrappedException.getClass();

ClassLoader exceptionLoader = delegateLoader;
if (!ClassLoaders.containsClass(delegateLoader, unwrappedExceptionType))
{
exceptionLoader = Proxies.unwrapProxyTypes(unwrappedExceptionType, callingLoader, delegateLoader,
unwrappedExceptionType.getClassLoader()).getClassLoader();
if (exceptionLoader == null)
{
exceptionLoader = getClass().getClassLoader();
}
}

if (exceptionNeedsEnhancement(exception))
{
Class<?>[] exceptionHierarchy = ProxyTypeInspector.getCompatibleClassHierarchy(callingLoader,
Proxies.unwrapProxyTypes(exception.getClass(), callingLoader, delegateLoader, exceptionLoader));

if (!Modifier.isFinal(unwrappedExceptionType.getModifiers()))
{
exception = enhance(callingLoader, exceptionLoader, method, exception, exceptionHierarchy);
}
}
}
}
catch (Exception e)
{
throw new ContainerException("Failed to enhance exception type: [" + exception.getClass().getName()
+ "] during proxied invocation of [" + method.getDeclaringClass().getName() + "." + method.getName()
+ "]. \n\nOriginal exception was: ", e);
}
return exception;
}

@SuppressWarnings({ "unchecked", "rawtypes" })
private Object enhanceEnum(ClassLoader loader, Object instance)
{
Expand Down Expand Up @@ -238,6 +279,29 @@ else if (left.length == 0 || left[0].isInterface())
return left;
}

@SuppressWarnings("unchecked")
private boolean exceptionNeedsEnhancement(Exception exception)
{
Class<? extends Exception> exceptionType = exception.getClass();
Class<? extends Exception> unwrappedExceptionType =
(Class<? extends Exception>) Proxies.unwrap(exception).getClass();

if (Proxies.isPassthroughType(unwrappedExceptionType))
{
return false;
}

if (unwrappedExceptionType.getClassLoader() != null
&& !exceptionType.getClassLoader().equals(callingLoader))
{
if (ClassLoaders.containsClass(callingLoader, exceptionType))
{
return false;
}
}
return true;
}

private boolean returnTypeNeedsEnhancement(Class<?> methodReturnType, Object returnValue,
Class<?> unwrappedReturnValueType)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,20 @@ public Archive<?> generateDeployment(TestDeployment testDeployment, Collection<P
Collection<Archive<?>> auxiliaryArchives = testDeployment.getAuxiliaryArchives();
for (Archive<?> archive : auxiliaryArchives)
{
Map<ArchivePath, Node> content = archive.getContent(new Filter<ArchivePath>()
{
@Override
public boolean include(ArchivePath path)
{
return path.toString().matches("org/jboss/shrinkwrap/descriptor/api/.*");
}
});

System.out.println(archive.toString(true));

System.out.println(archive.getName() + ": " + content.size());

for (Entry<ArchivePath, Node> entry : content.entrySet())
{
ArchivePath key = entry.getKey();
System.out.println("Deleting from " + archive.getName() + ": " + key);
archive.delete(key);
}
// Map<ArchivePath, Node> content = archive.getContent(new Filter<ArchivePath>()
// {
// @Override
// public boolean include(ArchivePath path)
// {
// return path.toString().matches("org/jboss/shrinkwrap/descriptor/api/.*");
// }
// });
//
// for (Entry<ArchivePath, Node> entry : content.entrySet())
// {
// ArchivePath key = entry.getKey();
// archive.delete(key);
// }

deployment.addAsLibrary(archive);
}
Expand Down

0 comments on commit c114c4f

Please sign in to comment.