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

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

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * 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. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire;

import com.gemstone.gemfire.internal.InternalInstantiator;
import com.gemstone.gemfire.internal.cache.EventID;
import com.gemstone.gemfire.internal.cache.tier.sockets.ClientProxyMembershipID;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;

/**
 * Instantiator allows classes that implement {@link
 * DataSerializable} to be registered with the data serialization
 * framework.  Knowledge of DataSerializable classes
 * allows the framework to optimize how instances of those classes are
 * data serialized.
 *
 * 

* * Ordinarily, when a DataSerializable object is written * using {@link DataSerializer#writeObject(Object, java.io.DataOutput)}, a special marker class id * is written to the stream followed by the class name of the * DataSerializable object. After the marker class id is * read by {@link DataSerializer#readObject} it performs the following * operations, * *

    * *
  1. The class name is read
  2. * *
  3. The class is loaded using {@link Class#forName(java.lang.String)}
  4. * *
  5. An instance of the class is created using reflection
  6. * *
  7. {@link DataSerializable#fromData} is invoked on the * newly-created object
  8. * *
* * However, if a DataSerializable class is {@linkplain * #register(Instantiator) registered} with the data serialization framework and * assigned a unique class id, an important optimization can be * performed that avoid the expense of using reflection to instantiate * the DataSerializable class. When the object is * written using {@link DataSerializer#writeObject(Object, java.io.DataOutput)}, the object's * registered class id is written to the stream. Consequently, when * the data is read from the stream, the {@link #newInstance} method * of the appropriate Instantiator instance is invoked to * create an "empty" instance of the DataSerializable * instead of using reflection to create the new instance. * *

* * Commonly, a DataSerializable class will register * itself with the Instantiator in a static initializer * as shown in the below example code. * * * *

public class User implements DataSerializable {
  private String name;
  private int userId;

  static {
    Instantiator.register(new Instantiator(User.class, 45) {
        public DataSerializable newInstance() {
          return new User();
        }
      });
  }

  public User(String name, int userId) {
    this.name = name;
    this.userId = userId;
  }

  /**
   * Creates an "empty" User whose contents are filled in by
   * invoking its toData() method
   */
  private User() {

  }

  public void toData(DataOutput out) throws IOException {
    out.writeUTF(this.name);
    out.writeInt(this.userId);
  }

  public void fromData(DataInput in)
    throws IOException, ClassNotFoundException {
    this.name = in.readUTF();
    this.userId = in.readInt();
  }
}
 * 
* * Instantiators may be distributed to other members of * the distributed system when they are registered. Consider the * following scenario in which VM1 and VM2 are members of the same * distributed system. Both VMs define the sameRegion and VM2's * region replicates the contents of VM1's using replication. * VM1 puts an instance of the above User class into the * region. The act of instantiating User will load the * User class and invoke its static initializer, thus * registering the Instantiator with the data * serialization framework. Because the region is a replicate, the * User will be data serialized and sent to VM2. * However, when VM2 attempts to data deserialize the * User, its Instantiator will not * necessarily be registered because User's static * initializer may not have been invoked yet. As a result, an * exception would be logged while deserializing the User * and the replicate would not appear to have the new value. So, in * order to ensure that the Instantiator is registered in * VM2, the data serialization framework distributes a message to each * member when an Instantiator is {@linkplain #register(Instantiator) * registered}.

Note that the framework does not require that an * Instantiator be {@link java.io.Serializable}, but it * does require that it provide * a {@linkplain #Instantiator(Class, int) * two-argument constructor}. * * @see #register(Instantiator) * @see #newInstance * * @author David Whitlock * @since 3.5 */ public abstract class Instantiator { /** The class associated with this instantiator. Used mainly for * debugging purposes and error messages. */ private Class clazz; /** The id of this Instantiator */ private int id; /** The eventId of this Instantiator */ private EventID eventId; /** The originator of this Instantiator */ private ClientProxyMembershipID context; /////////////////////// Static Methods /////////////////////// /** * Registers a DataSerializable class with the data * serialization framework. This method is usually invoked from the * static initializer of a class that implements * DataSerializable. * * @param instantiator * An Instantiator whose {@link #newInstance} * method is invoked when an object is data deserialized. * * @throws IllegalStateException * If class c is * already registered with a different class id, or another * class has already been registered with id * classId * @throws NullPointerException * If instantiator is null. */ public static synchronized void register(Instantiator instantiator) { InternalInstantiator.register(instantiator, true); } /** * Registers a DataSerializable class with the data * serialization framework. This method is usually invoked from the * static initializer of a class that implements * DataSerializable. * * @param instantiator * An Instantiator whose {@link #newInstance} * method is invoked when an object is data deserialized. * * @param distribute * True if the registered DataSerializer has to be * distributed to other members of the distributed system. * * @throws IllegalArgumentException * If class c is * already registered with a different class id, or another * class has already been registered with id * classId * @throws NullPointerException * If instantiator is null. */ public static synchronized void register(Instantiator instantiator, boolean distribute) { InternalInstantiator.register(instantiator, distribute); } //////////////////////// Constructors //////////////////////// /** * Creates a new Instantiator that instantiates a given * class. * * @param c * The DataSerializable class to register. This * class must have a static initializer that registers this * Instantiator. * @param classId * A unique id for class c. The * classId must not be zero. * This has been an int since dsPhase1. * * @throws IllegalArgumentException * If c does not implement * DataSerializable, classId is * less than or equal to zero. * @throws NullPointerException * If c is null */ public Instantiator(Class c, int classId) { if (c == null) { throw new NullPointerException(LocalizedStrings.Instantiator_CANNOT_REGISTER_A_NULL_CLASS.toLocalizedString()); } if (!DataSerializable.class.isAssignableFrom(c)) { throw new IllegalArgumentException(LocalizedStrings.Instantiator_CLASS_0_DOES_NOT_IMPLEMENT_DATASERIALIZABLE.toLocalizedString(c.getName())); } if (classId == 0) { throw new IllegalArgumentException(LocalizedStrings.Instantiator_CLASS_ID_0_MUST_NOT_BE_0.toLocalizedString(Integer.valueOf(classId))); } this.clazz = c; this.id = classId; } ////////////////////// Instance Methods ////////////////////// /** * Creates a new "empty" instance of a DataSerializable * class whose state will be filled in by invoking its {@link * DataSerializable#fromData fromData} method. * * @see DataSerializer#readObject */ public abstract DataSerializable newInstance(); /** * Returns the DataSerializable class that is * instantiated by this Instantiator. */ public final Class getInstantiatedClass() { return this.clazz; } /** * Returns the unique id of this * Instantiator. */ public final int getId() { return this.id; } /** * sets the unique eventId of this * Instantiator. For internal use only. */ public final void setEventId(Object/*EventID*/ eventId) { this.eventId = (EventID)eventId; } /** * Returns the unique eventId of this * Instantiator. For internal use only. */ public final Object/*EventID*/ getEventId() { return this.eventId; } /** * sets the context of this * Instantiator. For internal use only. */ public final void setContext(Object/*ClientProxyMembershipID*/ context) { this.context = (ClientProxyMembershipID)context; } /** * Returns the context of this * Instantiator. For internal use only. */ public final Object/*ClientProxyMembershipID*/ getContext() { return this.context; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy