blob: 936db3c3b5d8757190d89ac05a0bd39a8df29271 [file] [log] [blame]
/*
* 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.polygene.runtime.composite;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* JAVADOC
*/
abstract class FragmentInvocationHandler
implements InvocationHandler
{
private static final String COMPACT_TRACE = "polygene.compacttrace";
private static final CompactLevel compactLevel;
static
{
compactLevel = CompactLevel.valueOf( System.getProperty( COMPACT_TRACE, "proxy" ) );
}
protected Object fragment;
protected Method method;
void setFragment( Object fragment )
{
this.fragment = fragment;
}
public void setMethod( Method method )
{
this.method = method;
}
protected Throwable cleanStackTrace( Throwable throwable, Object proxy, Method method )
{
if( compactLevel == CompactLevel.off )
{
return throwable;
}
StackTraceElement[] trace = throwable.getStackTrace();
// Check if exception originated within Polygene or JDK - if so then skip compaction
if( trace.length == 0 || !isApplicationClass( trace[ 0 ].getClassName() ) )
{
return throwable;
}
int count = 0;
for( int i = 0; i < trace.length; i++ )
{
StackTraceElement stackTraceElement = trace[ i ];
if( !isApplicationClass( stackTraceElement.getClassName() ) )
{
// TODO: Should find stack entry outside Runtime, and compact beyond that
trace[ i ] = null;
count++;
}
else
{
boolean classOrigin = stackTraceElement.getClassName().equals( proxy.getClass().getSimpleName() );
boolean methodOrigin = stackTraceElement.getMethodName().equals( method.getName() );
if( classOrigin && methodOrigin && compactLevel == CompactLevel.proxy )
{
// Stop removing if the originating method call has been located in the stack.
// For 'semi' and 'extensive' compaction, we don't and do the entire stack instead.
trace[ i ] = new StackTraceElement( proxy.getClass()
.getInterfaces()[ 0 ].getName(), method.getName(), null, -1 );
break; // Stop compacting this trace
}
}
}
// Create new trace array
int idx = 0;
StackTraceElement[] newTrace = new StackTraceElement[ trace.length - count ];
for( StackTraceElement stackTraceElement : trace )
{
if( stackTraceElement != null )
{
newTrace[ idx++ ] = stackTraceElement;
}
}
throwable.setStackTrace( newTrace );
Throwable nested = throwable.getCause();
if( nested != null )
{
//noinspection ThrowableResultOfMethodCallIgnored
cleanStackTrace( nested, proxy, method );
}
for( Throwable suppressed : throwable.getSuppressed() )
{
//noinspection ThrowableResultOfMethodCallIgnored
cleanStackTrace( suppressed, proxy, method );
}
return throwable;
}
private boolean isApplicationClass( String className )
{
boolean jdkInternals = isJdkInternals( className );
if( compactLevel == CompactLevel.semi )
{
return !jdkInternals;
}
boolean polygeneRuntime = className.startsWith( "org.apache.polygene.runtime" );
boolean stubClass = className.endsWith( FragmentClassLoader.GENERATED_POSTFIX );
return !( stubClass ||
polygeneRuntime ||
jdkInternals );
}
private boolean isJdkInternals( String className )
{
return className.startsWith( "java.lang.reflect" )
|| className.startsWith( "reflect" )
|| className.startsWith( "com.sun.proxy" )
|| className.startsWith( "sun.reflect" );
}
}