Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.drools.camel.component.FastCloner Maven / Gradle / Ivy
Go to download
Drools integration for Camel that provides an integration framework based on known Enterprise Integration Pattern.
/*
* Copyright 2010 JBoss Inc
*
* Licensed 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.drools.camel.component;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
/**
*
* 21 May 2009
*/
/**
* Cloner: deep clone objects.
*
* This class is thread safe. One instance can be used by multiple threads on the same time.
*
*
* 18 Sep 2008
*/
public class FastCloner {
public interface IFastCloner {
Object clone(Object t,
FastCloner cloner,
Map clones) throws IllegalAccessException;
}
private final Set> ignored = new HashSet>();
private final Set> nullInstead = new HashSet>();
private final Map, IFastCloner> fastCloners = new HashMap, IFastCloner>();
private final Map ignoredInstances = new IdentityHashMap();
private final ConcurrentHashMap, List> fieldsCache = new ConcurrentHashMap, List>();
private boolean dumpClonedClasses;
private boolean cloningEnabled = true;
private boolean nullTransient;
public FastCloner() {
init();
}
private void init() {
registerKnownJdkImmutableClasses();
registerKnownConstants();
registerFastCloners();
}
public boolean isNullTransient() {
return this.nullTransient;
}
/**
* this makes the cloner to set a transient field to null upon cloning.
*
* NOTE: primitive types can't be nulled. Their value will be set to default, i.e. 0 for int
*
* @param nullTransient
* true for transient fields to be nulled
*/
public void setNullTransient(final boolean nullTransient) {
this.nullTransient = nullTransient;
}
/**
* registers a std set of fast cloners.
*/
protected void registerFastCloners() {
this.fastCloners.put( GregorianCalendar.class,
new FastClonerCalendar() );
this.fastCloners.put( ArrayList.class,
new FastClonerArrayList() );
this.fastCloners.put( Arrays.asList( new Object[]{""} ).getClass(),
new FastClonerArrayList() );
this.fastCloners.put( LinkedList.class,
new FastClonerLinkedList() );
this.fastCloners.put( HashSet.class,
new FastClonerHashSet() );
this.fastCloners.put( HashMap.class,
new FastClonerHashMap() );
this.fastCloners.put( TreeMap.class,
new FastClonerTreeMap() );
}
protected Object fastClone(final Object o,
final Map clones) throws IllegalAccessException {
final Class< ? extends Object> c = o.getClass();
final IFastCloner fastCloner = this.fastCloners.get( c );
if ( fastCloner != null ) {
return fastCloner.clone( o,
this,
clones );
}
return null;
}
public void registerConstant(final Object o) {
this.ignoredInstances.put( o,
true );
}
public void registerConstant(final Class< ? > c,
final String privateFieldName) {
try {
final Field field = c.getDeclaredField( privateFieldName );
field.setAccessible( true );
final Object v = field.get( null );
this.ignoredInstances.put( v,
true );
} catch ( final SecurityException e ) {
throw new RuntimeException( e );
} catch ( final NoSuchFieldException e ) {
throw new RuntimeException( e );
} catch ( final IllegalArgumentException e ) {
throw new RuntimeException( e );
} catch ( final IllegalAccessException e ) {
throw new RuntimeException( e );
}
}
/**
* registers some known JDK immutable classes. Override this to register your own list of jdk's immutable classes
*/
protected void registerKnownJdkImmutableClasses() {
registerImmutable( String.class );
registerImmutable( Integer.class );
registerImmutable( Long.class );
registerImmutable( Boolean.class );
registerImmutable( Class.class );
registerImmutable( Float.class );
registerImmutable( Double.class );
registerImmutable( Character.class );
registerImmutable( Byte.class );
registerImmutable( Short.class );
registerImmutable( Void.class );
registerImmutable( BigDecimal.class );
registerImmutable( BigInteger.class );
registerImmutable( URI.class );
registerImmutable( URL.class );
registerImmutable( UUID.class );
registerImmutable( Pattern.class );
}
protected void registerKnownConstants() {
// registering known constants of the jdk.
registerStaticFields( TreeSet.class,
HashSet.class,
HashMap.class,
TreeMap.class );
}
/**
* registers all static fields of these classes. Those static fields won't be cloned when an instance of the class is cloned.
*
* This is useful i.e. when a static field object is added into maps or sets. At that point, there is no way for the cloner to know that it was
* static except if it is registered.
*
* @param classes
* array of classes
*/
public void registerStaticFields(final Class< ? >... classes) {
for ( final Class< ? > c : classes ) {
final List fields = allFields( c );
for ( final Field field : fields ) {
final int mods = field.getModifiers();
if ( Modifier.isStatic( mods ) && !field.getType().isPrimitive() ) {
// System.out.println(c + " . " + field.getName());
registerConstant( c,
field.getName() );
}
}
}
}
/**
* spring framework friendly version of registerStaticFields
*
* @param set
* a set of classes which will be scanned for static fields
*/
public void setExtraStaticFields(final Set> set) {
registerStaticFields( (Class< ? >[]) set.toArray() );
}
/**
* instances of classes that shouldn't be cloned can be registered using this method.
*
* @param c
* The class that shouldn't be cloned. That is, whenever a deep clone for an object is created and c is encountered, the object
* instance of c will be added to the clone.
*/
public void dontClone(final Class< ? >... c) {
for ( final Class< ? > cl : c ) {
this.ignored.add( cl );
}
}
/**
* instead of cloning these classes will set the field to null
*
* @param c
* the classes to nullify during cloning
*/
public void nullInsteadOfClone(final Class< ? >... c) {
for ( final Class< ? > cl : c ) {
this.nullInstead.add( cl );
}
}
/**
* spring framework friendly version of nullInsteadOfClone
*/
public void setExtraNullInsteadOfClone(final Set> set) {
this.nullInstead.addAll( set );
}
/**
* registers an immutable class. Immutable classes are not cloned.
*
* @param c
* the immutable class
*/
public void registerImmutable(final Class< ? >... c) {
for ( final Class< ? > cl : c ) {
this.ignored.add( cl );
}
}
/**
* spring framework friendly version of registerImmutable
*/
public void setExtraImmutables(final Set> set) {
this.ignored.addAll( set );
}
public void registerFastCloner(final Class< ? > c,
final IFastCloner fastCloner) {
this.fastCloners.put( c,
fastCloner );
}
@SuppressWarnings("unchecked")
public T fastCloneOrNewInstance(final Class c) {
try {
final T fastClone = (T) fastClone( c,
null );
if ( fastClone != null ) {
return fastClone;
}
} catch ( final IllegalAccessException e ) {
throw new RuntimeException( e );
}
try {
return c.newInstance();
} catch ( Exception e ) {
throw new RuntimeException( "Unable To instantiate object from class " + c.getName(),
e );
}
}
/**
* deep clones "o".
*
* @param
* the type of "o"
* @param o
* the object to be deep-cloned
* @return a deep-clone of "o".
*/
public T deepClone(final T o) {
if ( o == null ) {
return null;
}
if ( !this.cloningEnabled ) {
return o;
}
if ( this.dumpClonedClasses ) {
System.out.println( "start>" + o.getClass() );
}
final Map clones = new IdentityHashMap( 16 );
try {
return cloneInternal( o,
clones );
} catch ( final IllegalAccessException e ) {
throw new RuntimeException( "error during cloning of " + o,
e );
}
}
/**
* shallow clones "o". This means that if c=shallowClone(o) then c!=o. Any change to c won't affect o.
*
* @param
* the type of o
* @param o
* the object to be shallow-cloned
* @return a shallow clone of "o"
*/
public T shallowClone(final T o) {
if ( o == null ) {
return null;
}
if ( !this.cloningEnabled ) {
return o;
}
try {
return cloneInternal( o,
null );
} catch ( final IllegalAccessException e ) {
throw new RuntimeException( "error during cloning of " + o,
e );
}
}
/**
* PLEASE DONT CALL THIS METHOD The only reason for been public is because IFastCloner must invoke it
*/
@SuppressWarnings("unchecked")
protected T cloneInternal(final T o,
final Map clones) throws IllegalAccessException {
if ( o == null ) {
return null;
}
if ( o == this ) {
return null;
}
if ( this.ignoredInstances.containsKey( o ) ) {
return o;
}
final Class clz = (Class) o.getClass();
if ( clz.isEnum() ) {
return o;
}
// skip cloning ignored classes
if ( this.nullInstead.contains( clz ) ) {
return null;
}
if ( this.ignored.contains( clz ) ) {
return o;
}
final Object clonedPreviously = clones != null ? clones.get( o ) : null;
if ( clonedPreviously != null ) {
return (T) clonedPreviously;
}
final Object fastClone = fastClone( o,
clones );
if ( fastClone != null ) {
if ( clones != null ) {
clones.put( o,
fastClone );
}
return (T) fastClone;
}
if ( this.dumpClonedClasses ) {
System.out.println( "clone>" + clz );
}
if ( clz.isArray() ) {
final int length = Array.getLength( o );
final T newInstance = (T) Array.newInstance( clz.getComponentType(),
length );
clones.put( o,
newInstance );
for ( int i = 0; i < length; i++ ) {
final Object v = Array.get( o,
i );
final Object clone = clones != null ? cloneInternal( v,
clones ) : v;
Array.set( newInstance,
i,
clone );
}
return newInstance;
}
T newInstance = null;
try {
newInstance = clz.newInstance();
} catch ( Exception e ) {
throw new RuntimeException( "Unable To instantiate object from class " + clz.getName(),
e );
}
if ( clones != null ) {
clones.put( o,
newInstance );
}
final List fields = allFields( clz );
for ( final Field field : fields ) {
if ( !Modifier.isStatic( field.getModifiers() ) ) {
if ( this.nullTransient && Modifier.isTransient( field.getModifiers() ) ) {
// request by Jonathan : transient fields can be null-ed
final Class< ? > type = field.getType();
if ( !type.isPrimitive() ) {
field.set( newInstance,
null );
}
} else {
final Object fieldObject = field.get( o );
final Object fieldObjectClone = clones != null ? cloneInternal( fieldObject,
clones ) : fieldObject;
field.set( newInstance,
fieldObjectClone );
if ( this.dumpClonedClasses && (fieldObjectClone != fieldObject) ) {
System.out.println( "cloned field>" + field + " -- of class " + o.getClass() );
}
}
}
}
return newInstance;
}
/**
* copies all properties from src to dest. Src and dest can be of different class, provided they contain same field names
*
* @param src
* the source object
* @param dest
* the destination object which must contain as minimul all the fields of src
*/
public void copyPropertiesOfInheritedClass(final T src,
final E dest) {
if ( src == null ) {
throw new IllegalArgumentException( "src can't be null" );
}
if ( dest == null ) {
throw new IllegalArgumentException( "dest can't be null" );
}
final Class< ? extends Object> srcClz = src.getClass();
final Class< ? extends Object> destClz = dest.getClass();
if ( srcClz.isArray() ) {
if ( !destClz.isArray() ) {
throw new IllegalArgumentException( "can't copy from array to non-array class " + destClz );
}
final int length = Array.getLength( src );
for ( int i = 0; i < length; i++ ) {
final Object v = Array.get( src,
i );
Array.set( dest,
i,
v );
}
return;
}
final List fields = allFields( srcClz );
for ( final Field field : fields ) {
if ( !Modifier.isStatic( field.getModifiers() ) ) {
try {
final Object fieldObject = field.get( src );
field.set( dest,
fieldObject );
} catch ( final IllegalArgumentException e ) {
throw new RuntimeException( e );
} catch ( final IllegalAccessException e ) {
throw new RuntimeException( e );
}
}
}
}
/**
* reflection utils
*/
private void addAll(final List l,
final Field[] fields) {
for ( final Field field : fields ) {
field.setAccessible( true );
l.add( field );
}
}
/**
* reflection utils
*/
private List allFields(final Class< ? > c) {
List l = this.fieldsCache.get( c );
if ( l == null ) {
l = new LinkedList();
final Field[] fields = c.getDeclaredFields();
addAll( l,
fields );
Class< ? > sc = c;
while ( ((sc = sc.getSuperclass()) != Object.class) && (sc != null) ) {
addAll( l,
sc.getDeclaredFields() );
}
this.fieldsCache.putIfAbsent( c,
l );
}
return l;
}
public boolean isDumpClonedClasses() {
return this.dumpClonedClasses;
}
/**
* will println() all cloned classes. Useful for debugging only.
*
* @param dumpClonedClasses
* true to enable printing all cloned classes
*/
public void setDumpClonedClasses(final boolean dumpClonedClasses) {
this.dumpClonedClasses = dumpClonedClasses;
}
public boolean isCloningEnabled() {
return this.cloningEnabled;
}
public void setCloningEnabled(final boolean cloningEnabled) {
this.cloningEnabled = cloningEnabled;
}
public static class FastClonerTreeMap
implements
IFastCloner {
@SuppressWarnings("unchecked")
public Object clone(final Object t,
final FastCloner cloner,
final Map clones) throws IllegalAccessException {
final TreeMap m = (TreeMap) t;
final TreeMap result = new TreeMap();
for ( final Map.Entry e : m.entrySet() ) {
final Object key = cloner.cloneInternal( e.getKey(),
clones );
final Object value = cloner.cloneInternal( e.getValue(),
clones );
result.put( key,
value );
}
return result;
}
}
public static class FastClonerArrayList
implements
IFastCloner {
@SuppressWarnings("unchecked")
public Object clone(final Object t,
final FastCloner cloner,
final Map clones) throws IllegalAccessException {
final Collection al = (Collection) t;
final ArrayList l = new ArrayList();
for ( final Object o : al ) {
final Object cloneInternal = cloner.cloneInternal( o,
clones );
l.add( cloneInternal );
}
return l;
}
}
public static class FastClonerCalendar
implements
IFastCloner {
public Object clone(final Object t,
final FastCloner cloner,
final Map clones) {
final GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis( ((GregorianCalendar) t).getTimeInMillis() );
return gc;
}
}
public static class FastClonerLinkedList
implements
IFastCloner {
@SuppressWarnings("unchecked")
public Object clone(final Object t,
final FastCloner cloner,
final Map clones) throws IllegalAccessException {
final LinkedList al = (LinkedList) t;
final LinkedList l = new LinkedList();
for ( final Object o : al ) {
final Object cloneInternal = cloner.cloneInternal( o,
clones );
l.add( cloneInternal );
}
return l;
}
}
@SuppressWarnings("unchecked")
public abstract static class FastClonerCustomCollection
implements
IFastCloner {
public abstract T getInstance();
public Object clone(final Object t,
final FastCloner cloner,
final Map clones) throws IllegalAccessException {
final T c = getInstance();
final T l = (T) t;
for ( final Object o : l ) {
final Object cloneInternal = cloner.cloneInternal( o,
clones );
c.add( cloneInternal );
}
return c;
}
}
public static class FastClonerHashSet
implements
IFastCloner {
@SuppressWarnings("unchecked")
public Object clone(final Object t,
final FastCloner cloner,
final Map clones) throws IllegalAccessException {
final HashSet al = (HashSet) t;
final HashSet l = new HashSet();
for ( final Object o : al ) {
final Object cloneInternal = cloner.cloneInternal( o,
clones );
l.add( cloneInternal );
}
return l;
}
}
public static class FastClonerHashMap
implements
IFastCloner {
@SuppressWarnings("unchecked")
public Object clone(final Object t,
final FastCloner cloner,
final Map clones) throws IllegalAccessException {
final HashMap m = (HashMap) t;
final HashMap result = new HashMap();
for ( final Map.Entry e : m.entrySet() ) {
final Object key = cloner.cloneInternal( e.getKey(),
clones );
final Object value = cloner.cloneInternal( e.getValue(),
clones );
result.put( key,
value );
}
return result;
}
}
}