All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.CopyHelper Maven / Gradle / Ivy

/*
 * 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 com.gemstone.gemfire;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.UUID;

import com.gemstone.gemfire.internal.HeapDataOutputStream;
import com.gemstone.gemfire.internal.Version;
import com.gemstone.gemfire.internal.cache.CachedDeserializable;
import com.gemstone.gemfire.internal.cache.Token;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import com.gemstone.gemfire.pdx.PdxInstance;
import com.gemstone.gemfire.pdx.WritablePdxInstance;
import com.gemstone.gemfire.pdx.internal.PdxUnreadData;

/**
 * A static helper for optimally creating copies.  Creating copies
 * of cache values provides improved concurrency as well as isolation.
 * For transactions, creating a copy is the guaranteed way to enforce
 * "Read Committed" isolation on changes to cache
 * Entries.

 * 

Here is a simple example of how to use CopyHelper.copy *

 *    Object o = r.get("stringBuf");
 *    StringBuffer s = (StringBuffer) CopyHelper.copy(o);
 *    s.append("... and they lived happily ever after.  The End.");
 *    r.put("stringBuf", s);
 *  
* * @see Cloneable * @see Serializable * @see DataSerializer * @see com.gemstone.gemfire.cache.Cache#setCopyOnRead * @see com.gemstone.gemfire.cache.CacheTransactionManager * * @author Mitch Thomas * @since 4.0 */ public final class CopyHelper { // no instances allowed private CopyHelper() { } /** * Return true if the given object is an instance of a well known * immutable class. * The well known classes are: *
    *
  • String *
  • Byte *
  • Character *
  • Short *
  • Integer *
  • Long *
  • Float *
  • Double *
  • BigInteger *
  • BigDecimal *
  • UUID *
  • PdxInstance but not WritablePdxInstance *
* @param o the object to check * @return true if o is an instance of a well known immutable class. * @since 6.6.2 */ public static boolean isWellKnownImmutableInstance(Object o) { if (o instanceof String) { return true; } if (o instanceof Number) { if (o instanceof Integer) return true; if (o instanceof Long) return true; if (o instanceof Byte) return true; if (o instanceof Short) return true; if (o instanceof Float) return true; if (o instanceof Double) return true; // subclasses of non-final classes may be mutable if (o.getClass().equals(BigInteger.class)) return true; if (o.getClass().equals(BigDecimal.class)) return true; } if (o instanceof PdxInstance && !(o instanceof WritablePdxInstance)) { // no need to copy since it is immutable return true; } if (o instanceof Character) return true; if (o instanceof UUID) return true; return false; } /** *

Makes a copy of the specified object. The object returned is not guaranteed * to be a deep copy of the original object, as explained below. * *

Copies can only be made if the original is a Cloneable or serializable by * GemFire. * If o is a {@link #isWellKnownImmutableInstance(Object) well known immutable instance} * then it will be returned without copying it. * *

If the argument o is an instance of {@link java.lang.Cloneable}, a copy is * made by invoking clone on it. Note that not all implementations of clone * make deep copies (e.g. {@link java.util.HashMap#clone HashMap.clone}). Otherwise, if the * argument is not an instance of Cloneable, a copy is made using serialization: if * GemFire serialization is implemented, it is used; otherwise, java serialization is used. * *

The difference between this method and {@link #deepCopy(Object) deepCopy}, is that * this method uses clone if available, whereas deepCopy does not. As a * result, for Cloneable objects copied using this method, how deep a copy the * returned object is depends on its implementation of clone. * * @param o the original object that a copy is needed of * @return the new instance that is a copy of of the original * @throws CopyException if copying fails because a class could not * be found or could not be serialized. * @see #deepCopy(Object) * @since 4.0 */ @SuppressWarnings("unchecked") public static T copy(T o) { T copy = null; try { if (o == null) { return null; } else if (o instanceof Token) { return o; } else { if (isWellKnownImmutableInstance(o)) return o; if (o instanceof Cloneable) { try { // Note that Object.clone is protected so we need to use reflection // to call clone even though this guy implements Cloneable Class c = o.getClass(); // By convention, the user should make the clone method public. // But even if they don't, let's go ahead and use it. // The other problem is that if the class is private, we still // need to make the method accessible even if the method is public, // because Object.clone is protected. Method m = c.getDeclaredMethod("clone", new Class[0]); m.setAccessible(true); copy = (T)m.invoke(o, new Object[0]); return copy; } catch (NoSuchMethodException ignore) { // try using Serialization } catch (IllegalAccessException ignore) { // try using Serialization } catch (SecurityException ignore) { // try using Serialization } catch (InvocationTargetException ex) { Throwable cause = ex.getTargetException(); if (cause instanceof CloneNotSupportedException) { // try using Serialization } else { throw new CopyException(LocalizedStrings.CopyHelper_CLONE_FAILED.toLocalizedString(), cause != null ? cause : ex); } } } else if (o instanceof CachedDeserializable) { copy = (T) ((CachedDeserializable) o).getDeserializedWritableCopy(null, null); return copy; } else if (o.getClass().isArray() && o.getClass().getComponentType().isPrimitive()) { if (o instanceof byte[]) { byte[] a = (byte[])o; copy = (T) Arrays.copyOf(a, a.length); } else if (o instanceof boolean[]) { boolean[] a = (boolean[])o; copy = (T) Arrays.copyOf(a, a.length); } else if (o instanceof char[]) { char[] a = (char[])o; copy = (T) Arrays.copyOf(a, a.length); } else if (o instanceof int[]) { int[] a = (int[])o; copy = (T) Arrays.copyOf(a, a.length); } else if (o instanceof long[]) { long[] a = (long[])o; copy = (T) Arrays.copyOf(a, a.length); } else if (o instanceof short[]) { short[] a = (short[])o; copy = (T) Arrays.copyOf(a, a.length); } else if (o instanceof float[]) { float[] a = (float[])o; copy = (T) Arrays.copyOf(a, a.length); } else if (o instanceof double[]) { double[] a = (double[])o; copy = (T) Arrays.copyOf(a, a.length); } return copy; } // Copy using serialization copy = doDeepCopy(o); return copy; } } finally { if (copy != null) { PdxUnreadData.copy(o, copy); } } } /** * Makes a deep copy of the specified object o using serialization, so the object * has to be serializable by GemFire. * *

If o is a {@link #isWellKnownImmutableInstance(Object) well known immutable * instance} then it will be returned without copying it. * *

The passed in object is serialized in memory, and then deserialized into * a new instance, which is returned. If GemFire serialization is implemented * for the object, it is used; otherwise, java serialization is used. * * @param o the original object to be copied * @return the new instance that is a copy of the original * @throws CopyException if copying fails because a class could not * be found or could not be serialized * @see #copy(Object) */ public static T deepCopy(T o) { T copy = null; try { if (o == null) { return null; } else if (o instanceof Token || isWellKnownImmutableInstance(o)) { return o; } else { copy = doDeepCopy(o); return copy; } } finally { if (copy != null) { PdxUnreadData.copy(o, copy); } } } @SuppressWarnings("unchecked") private static T doDeepCopy(T o) { try { HeapDataOutputStream hdos = new HeapDataOutputStream(Version.CURRENT); DataSerializer.writeObject(o, hdos); return (T)DataSerializer.readObject(new DataInputStream(hdos.getInputStream())); } catch (ClassNotFoundException ex) { throw new CopyException(LocalizedStrings.CopyHelper_COPY_FAILED_ON_INSTANCE_OF_0.toLocalizedString(o.getClass()), ex); } catch (IOException ex) { throw new CopyException(LocalizedStrings.CopyHelper_COPY_FAILED_ON_INSTANCE_OF_0.toLocalizedString(o.getClass()), ex); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy