| /* |
| * 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.ignite; |
| |
| import java.sql.Timestamp; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.Map; |
| import java.util.TreeMap; |
| import java.util.UUID; |
| import org.apache.ignite.binary.BinaryObject; |
| import org.apache.ignite.binary.BinaryObjectBuilder; |
| import org.apache.ignite.binary.BinaryObjectException; |
| import org.apache.ignite.binary.BinaryType; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * Defines binary objects functionality. With binary objects you are able to: |
| * <ul> |
| * <li>Seamlessly interoperate between Java, .NET, and C++.</li> |
| * <li>Make any object binary with zero code change to your existing code.</li> |
| * <li>Nest binary objects within each other.</li> |
| * <li>Automatically handle {@code circular} or {@code null} references.</li> |
| * <li>Automatically convert collections and maps between Java, .NET, and C++.</li> |
| * <li> |
| * Optionally avoid deserialization of objects on the server side |
| * (objects are stored in {@link org.apache.ignite.binary.BinaryObject} format). |
| * </li> |
| * <li>Avoid need to have concrete class definitions on the server side.</li> |
| * <li>Dynamically change structure of the classes without having to restart the cluster.</li> |
| * <li>Index into binary objects for querying purposes.</li> |
| * </ul> |
| * <h1 class="header">Working With Binaries Directly</h1> |
| * Once an object is defined as binary, |
| * Ignite will always store it in memory in the binary (i.e. binary) format. |
| * User can choose to work either with the binary format or with the deserialized form |
| * (assuming that class definitions are present in the classpath). |
| * <p> |
| * To work with the binary format directly, user should create a special cache projection |
| * using IgniteCache.withKeepBinary() method and then retrieve individual fields as needed: |
| * <pre name=code class=java> |
| * IgniteCache<BinaryObject, BinaryObject> prj = cache.withKeepBinary(); |
| * |
| * // Convert instance of MyKey to binary format. |
| * // We could also use BinaryBuilder to create the key in binary format directly. |
| * BinaryObject key = grid.binary().toBinary(new MyKey()); |
| * |
| * BinaryObject val = prj.get(key); |
| * |
| * String field = val.field("myFieldName"); |
| * </pre> |
| * Alternatively, if we have class definitions in the classpath, we may choose to work with deserialized |
| * typed objects at all times. |
| * <pre name=code class=java> |
| * IgniteCache<MyKey.class, MyValue.class> cache = grid.cache(null); |
| * |
| * MyValue val = cache.get(new MyKey()); |
| * |
| * // Normal java getter. |
| * String fieldVal = val.getMyFieldName(); |
| * </pre> |
| * If we used, for example, one of the automatically handled binary types for a key, like integer, |
| * and still wanted to work with binary binary format for values, then we would declare cache projection |
| * as follows: |
| * <pre name=code class=java> |
| * IgniteCache<Integer.class, BinaryObject> prj = cache.withKeepBinary(); |
| * </pre> |
| * <h1 class="header">Automatic Binary Types</h1> |
| * Note that only binary classes are converted to {@link org.apache.ignite.binary.BinaryObject} format. Following |
| * classes are never converted (e.g., {@link #toBinary(Object)} method will return original |
| * object, and instances of these classes will be stored in cache without changes): |
| * <ul> |
| * <li>All primitives (byte, int, ...) and there boxed versions (Byte, Integer, ...)</li> |
| * <li>Arrays of primitives (byte[], int[], ...)</li> |
| * <li>{@link String} and array of {@link String}s</li> |
| * <li>{@link UUID} and array of {@link UUID}s</li> |
| * <li>{@link Date} and array of {@link Date}s</li> |
| * <li>{@link Timestamp} and array of {@link Timestamp}s</li> |
| * <li>Enums and array of enums</li> |
| * <li> |
| * Maps, collections and array of objects (but objects inside |
| * them will still be converted if they are binary) |
| * </li> |
| * </ul> |
| * <h1 class="header">Working With Maps and Collections</h1> |
| * All maps and collections in the binary objects are serialized automatically. When working |
| * with different platforms, e.g. C++ or .NET, Ignite will automatically pick the most |
| * adequate collection or map in either language. For example, {@link ArrayList} in Java will become |
| * {@code List} in C#, {@link LinkedList} in Java is {@link LinkedList} in C#, {@link HashMap} |
| * in Java is {@code Dictionary} in C#, and {@link TreeMap} in Java becomes {@code SortedDictionary} |
| * in C#, etc. |
| * <h1 class="header">Building Binary Objects</h1> |
| * Ignite comes with {@link org.apache.ignite.binary.BinaryObjectBuilder} which allows to build binary objects dynamically: |
| * <pre name=code class=java> |
| * BinaryBuilder builder = Ignition.ignite().binary().builder(); |
| * |
| * builder.typeId("MyObject"); |
| * |
| * builder.stringField("fieldA", "A"); |
| * build.intField("fieldB", "B"); |
| * |
| * BinaryObject binaryObj = builder.build(); |
| * </pre> |
| * For the cases when class definition is present |
| * in the class path, it is also possible to populate a standard POJO and then |
| * convert it to binary format, like so: |
| * <pre name=code class=java> |
| * MyObject obj = new MyObject(); |
| * |
| * obj.setFieldA("A"); |
| * obj.setFieldB(123); |
| * |
| * BinaryObject binaryObj = Ignition.ignite().binary().toBinary(obj); |
| * </pre> |
| * NOTE: you don't need to convert typed objects to binary format before storing |
| * them in cache, Ignite will do that automatically. |
| * <h1 class="header">Binary Metadata</h1> |
| * Even though Ignite binary protocol only works with hash codes for type and field names |
| * to achieve better performance, Ignite provides metadata for all binary types which |
| * can be queried ar runtime via any of the {@link IgniteBinary#type(Class)} |
| * methods. Having metadata also allows for proper formatting of {@code BinaryObject#toString()} method, |
| * even when binary objects are kept in binary format only, which may be necessary for audit reasons. |
| * <h1 class="header">Dynamic Structure Changes</h1> |
| * Since objects are always cached in the binary binary format, server does not need to |
| * be aware of the class definitions. Moreover, if class definitions are not present or not |
| * used on the server, then clients can continuously change the structure of the binary |
| * objects without having to restart the cluster. For example, if one client stores a |
| * certain class with fields A and B, and another client stores the same class with |
| * fields B and C, then the server-side binary object will have the fields A, B, and C. |
| * As the structure of a binary object changes, the new fields become available for SQL queries |
| * automatically. |
| * <h1 class="header">Configuration</h1> |
| * By default all your objects are considered as binary and no specific configuration is needed. |
| * The only requirement Ignite imposes is that your object has an empty |
| * constructor. Note, that since server side does not have to know the class definition, |
| * you only need to list binary objects in configuration on the client side. However, if you |
| * list them on the server side as well, then you get the ability to deserialize binary objects |
| * into concrete types on the server as well as on the client. |
| * <p> |
| * Here is an example of binary configuration (note that star (*) notation is supported): |
| * <pre name=code class=xml> |
| * ... |
| * <!-- Explicit binary objects configuration. --> |
| * <property name="marshaller"> |
| * <bean class="org.apache.ignite.marshaller.binary.BinaryMarshaller"> |
| * <property name="classNames"> |
| * <list> |
| * <value>my.package.for.binary.objects.*</value> |
| * <value>org.apache.ignite.examples.client.binary.Employee</value> |
| * </list> |
| * </property> |
| * </bean> |
| * </property> |
| * ... |
| * </pre> |
| * or from code: |
| * <pre name=code class=java> |
| * IgniteConfiguration cfg = new IgniteConfiguration(); |
| * |
| * BinaryMarshaller marsh = new BinaryMarshaller(); |
| * |
| * marsh.setClassNames(Arrays.asList( |
| * Employee.class.getName(), |
| * Address.class.getName()) |
| * ); |
| * |
| * cfg.setMarshaller(marsh); |
| * </pre> |
| * You can also specify class name for a binary object via {@link org.apache.ignite.binary.BinaryTypeConfiguration}. |
| * Do it in case if you need to override other configuration properties on per-type level, like |
| * ID-mapper, or serializer. |
| * <h1 class="header">Custom Affinity Keys</h1> |
| * Often you need to specify an alternate key (not the cache key) for affinity routing whenever |
| * storing objects in cache. For example, if you are caching {@code Employee} object with |
| * {@code Organization}, and want to colocate employees with organization they work for, |
| * so you can process them together, you need to specify an alternate affinity key. |
| * With binary objects you would have to do it as following: |
| * <pre name=code class=xml> |
| * <property name="marshaller"> |
| * <bean class="org.gridgain.grid.marshaller.binary.BinaryMarshaller"> |
| * ... |
| * <property name="typeConfigurations"> |
| * <list> |
| * <bean class="org.apache.ignite.binary.BinaryTypeConfiguration"> |
| * <property name="className" value="org.apache.ignite.examples.client.binary.EmployeeKey"/> |
| * <property name="affinityKeyFieldName" value="organizationId"/> |
| * </bean> |
| * </list> |
| * </property> |
| * ... |
| * </bean> |
| * </property> |
| * </pre> |
| * <h1 class="header">Serialization</h1> |
| * Serialization and deserialization works out-of-the-box in Ignite. However, you can provide your own custom |
| * serialization logic by optionally implementing {@link org.apache.ignite.binary.Binarylizable} interface, like so: |
| * <pre name=code class=java> |
| * public class Address implements BinaryMarshalAware { |
| * private String street; |
| * private int zip; |
| * |
| * // Empty constructor required for binary deserialization. |
| * public Address() {} |
| * |
| * @Override public void writeBinary(BinaryWriter writer) throws BinaryException { |
| * writer.writeString("street", street); |
| * writer.writeInt("zip", zip); |
| * } |
| * |
| * @Override public void readBinary(BinaryReader reader) throws BinaryException { |
| * street = reader.readString("street"); |
| * zip = reader.readInt("zip"); |
| * } |
| * } |
| * </pre> |
| * Alternatively, if you cannot change class definitions, you can provide custom serialization |
| * logic in {@link org.apache.ignite.binary.BinarySerializer} either globally in |
| * {@link org.apache.ignite.configuration.BinaryConfiguration} or |
| * for a specific type via {@link org.apache.ignite.binary.BinaryTypeConfiguration} instance. |
| * <p> |
| * Similar to java serialization you can use {@code writeReplace()} and {@code readResolve()} methods. |
| * <ul> |
| * <li> |
| * {@code readResolve} is defined as follows: {@code ANY-ACCESS-MODIFIER Object readResolve()}. |
| * It may be used to replace the de-serialized object by another one of your choice. |
| * </li> |
| * <li> |
| * {@code writeReplace} is defined as follows: {@code ANY-ACCESS-MODIFIER Object writeReplace()}. This method |
| * allows the developer to provide a replacement object that will be serialized instead of the original one. |
| * </li> |
| * </ul> |
| * |
| * <h1 class="header">Custom ID Mappers</h1> |
| * Ignite implementation uses name hash codes to generate IDs for class names or field names |
| * internally. However, in cases when you want to provide your own ID mapping schema, |
| * you can provide your own {@link org.apache.ignite.binary.BinaryIdMapper} implementation. |
| * <p> |
| * ID-mapper may be provided either globally in {@link org.apache.ignite.configuration.BinaryConfiguration}, |
| * or for a specific type via {@link org.apache.ignite.binary.BinaryTypeConfiguration} instance. |
| * <h1 class="header">Query Indexing</h1> |
| * Binary objects can be indexed for querying by specifying index fields in |
| * {@link org.apache.ignite.cache.QueryEntity} inside of specific |
| * {@link org.apache.ignite.configuration.CacheConfiguration} instance, |
| * like so: |
| * <pre name=code class=xml> |
| * ... |
| * <bean class="org.apache.ignite.cache.CacheConfiguration"> |
| * ... |
| * <property name="queryEntities"> |
| * <list> |
| * <bean class="QueryEntity"> |
| * <property name="type" value="Employee"/> |
| * |
| * <!-- Fields available from query. --> |
| * <property name="fields"> |
| * <map> |
| * <entry key="name" value="java.lang.String"/> |
| * |
| * <!-- Nested binary objects can also be indexed. --> |
| * <entry key="address.zip" value="java.lang.Integer" /> |
| * </map> |
| * </property> |
| * |
| * <!-- Aliases for full property name in dot notation. --> |
| * <property name="fields"> |
| * <map> |
| * <entry key="address.zip" value="zip" /> |
| * </map> |
| * </property> |
| * |
| * <!-- Indexes configuration. --> |
| * <property name="indexes"> |
| * <list> |
| * <bean class="org.apache.ignite.cache.QueryIndex"> |
| * <property name="fields"> |
| * <map> |
| * <!-- The boolean value is the acceding flag. --> |
| * <entry key="name" value="true"/> |
| * </map> |
| * </property> |
| * </bean> |
| * </list> |
| * </property> |
| * </bean> |
| * </list> |
| * </property> |
| * </bean> |
| * </pre> |
| */ |
| public interface IgniteBinary { |
| /** |
| * Gets type ID for given type name. |
| * If no user defined {@link org.apache.ignite.binary.BinaryIdMapper} is configured |
| * via {@link org.apache.ignite.configuration.BinaryConfiguration}, then system mapper will be used. |
| * |
| * |
| * @param typeName Type name. |
| * @return Type ID which a type would have had if it has been registered in Ignite. |
| */ |
| public int typeId(@NotNull String typeName); |
| |
| /** |
| * Converts provided object to instance of {@link org.apache.ignite.binary.BinaryObject}. |
| * |
| * @param obj Object to convert. |
| * @return Converted object or {@code null} if obj is null. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public <T> T toBinary(@Nullable Object obj) throws BinaryObjectException; |
| |
| /** |
| * Creates new binary builder. |
| * |
| * @param typeName Type name. |
| * @return Newly binary builder. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public BinaryObjectBuilder builder(String typeName) throws BinaryObjectException; |
| |
| /** |
| * Creates binary builder initialized by existing binary object. |
| * |
| * @param binaryObj Binary object to initialize builder. |
| * @return Binary builder. |
| */ |
| public BinaryObjectBuilder builder(BinaryObject binaryObj) throws BinaryObjectException; |
| |
| /** |
| * Gets metadata for provided class. |
| * |
| * @param cls Class. |
| * @return Metadata. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public BinaryType type(Class<?> cls) throws BinaryObjectException; |
| |
| /** |
| * Gets metadata for provided class name. |
| * |
| * @param typeName Type name. |
| * @return Metadata. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public BinaryType type(String typeName) throws BinaryObjectException; |
| |
| /** |
| * Gets metadata for provided type ID. |
| * |
| * @param typeId Type ID. |
| * @return Metadata. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public BinaryType type(int typeId) throws BinaryObjectException; |
| |
| /** |
| * Gets metadata for all known types. |
| * |
| * @return Metadata. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public Collection<BinaryType> types() throws BinaryObjectException; |
| |
| /** |
| * Create enum object using value. |
| * |
| * @param typeName Type name. |
| * @param ord Ordinal. |
| * @return Enum object. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public BinaryObject buildEnum(String typeName, int ord) throws BinaryObjectException; |
| |
| /** |
| * Create enum object using name. |
| * |
| * @param typeName Type name. |
| * @param name Name. |
| * @return Enum object. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public BinaryObject buildEnum(String typeName, String name) throws BinaryObjectException; |
| |
| /** |
| * Register enum type. |
| * |
| * @param typeName Type name. |
| * @param vals Mapping of enum constant names to ordinals. |
| * @return Binary type for registered enum. |
| * @throws org.apache.ignite.binary.BinaryObjectException In case of error. |
| */ |
| public BinaryType registerEnum(String typeName, Map<String, Integer> vals) throws BinaryObjectException; |
| } |