/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.glassfish.pfl.dynamic.copyobject.impl;
import java.lang.reflect.Method ;
import java.lang.reflect.Modifier ;
import java.util.Map ;
import java.security.PrivilegedAction;
import java.security.AccessController;
import org.glassfish.pfl.basic.concurrent.WeakHashMapSafeReadLock;
import org.glassfish.pfl.dynamic.copyobject.spi.ReflectiveCopyException ;
public abstract class DefaultClassCopierFactories
{
// Note that the FastCache is NOT a weak or soft
// reference based cache, so it can hold onto
// references to classes indefinitely, pinning ClassLoader
// instances in memory. Until this is fixed, FastCache is
// for testing only.
public static final boolean USE_FAST_CACHE = false ;
private DefaultClassCopierFactories() {}
Create a ClassCopierFactory that handles arrays. This
ClassCopierFactory will return null on a get call if the
class is not an array.
/** Create a ClassCopierFactory that handles arrays. This
* ClassCopierFactory will return null on a get call if the
* class is not an array.
*/
public static ClassCopierFactory makeArrayClassCopierFactory(
ClassCopierFactory ccf )
{
return new ClassCopierFactoryArrayImpl( ccf ) ;
}
private static final Class<?>[] SAFE_TO_COPY = new Class<?>[] {
java.util.TimeZone.class,
java.lang.Throwable.class,
java.lang.reflect.Proxy.class
} ;
public static ClassCopierFactory makeOrdinaryClassCopierFactory(
final PipelineClassCopierFactory ccf )
{
return new ClassCopierFactory() {
@Override
public ClassCopier getClassCopier( Class<?> cls )
throws ReflectiveCopyException {
if (notCopyable( cls )) {
return DefaultClassCopiers.getErrorClassCopier() ;
} else {
return new ClassCopierOrdinaryImpl( ccf, cls ) ;
}
}
// Returns true if class is (specially) known to be safe
// to copy, even if notCopyable(cls) is true.
private boolean safe( Class cls )
{
for (Class klass : SAFE_TO_COPY) {
if (cls == klass) {
return true ;
}
}
return false ;
}
// Scan the methods in cls and all its superclasses (except
// Object!) to see if finalize is defined, or if there are
// any native methods. Classes with such methods are not copyable,
// except for a few known classes that ARE safe to copy,
// and cause this method to return true. If there are not
// problematic methods, return false and allow the copy
// (at this level: references to non-copyable objects will
// cause ReflectiveCopyException to be thrown where ever they
// occur).
private boolean notCopyable( Class<?> cls ) {
Class<?> current = cls ;
Method[] methods ;
while (current != Object.class) {
if (safe(current)) {
return false;
}
// Fix GLASSFISH-18310
if (System.getSecurityManager() == null) {
methods = current.getDeclaredMethods();
} else {
final Class<?> _current = current;
methods = (Method[]) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return _current.getDeclaredMethods();
}
});
}
for (Method m : methods) {
if ((m.getName().equals("finalize"))
|| Modifier.isNative(m.getModifiers())) {
return true;
}
}
current = current.getSuperclass() ;
}
return false ;
}
} ;
}
public static CachingClassCopierFactory makeCachingClassCopierFactory( )
{
return new CachingClassCopierFactory()
{
private Map<Class<?>,ClassCopier> cache = USE_FAST_CACHE ?
new FastCache<Class<?>,ClassCopier>(
new WeakHashMapSafeReadLock<Class<?>,ClassCopier>() ) :
new WeakHashMapSafeReadLock<Class<?>,ClassCopier>() ;
@Override
public void put( Class<?> cls, ClassCopier copier )
{
cache.put( cls, copier ) ;
}
@Override
public ClassCopier getClassCopier( Class<?> cls )
{
return cache.get(cls) ;
}
};
}
public static ClassCopierFactory getNullClassCopierFactory()
{
return new ClassCopierFactory()
{
@Override
public ClassCopier getClassCopier( Class cls )
{
return null ;
}
} ;
}
public static PipelineClassCopierFactory getPipelineClassCopierFactory()
{
return new ClassCopierFactoryPipelineImpl() ;
}
}