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

com.microsoft.azure.storage.table.TableServiceEntity Maven / Gradle / Ivy

/**
 * Copyright Microsoft Corporation
 * 
 * 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 com.microsoft.azure.storage.table;

import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import com.microsoft.azure.storage.Constants;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.StorageErrorCodeStrings;
import com.microsoft.azure.storage.StorageException;
import com.microsoft.azure.storage.core.SR;

/**
 * The {@link TableServiceEntity} class represents the base object type for a table entity in the Storage service.
 * {@link TableServiceEntity} provides a base implementation for the {@link TableEntity} interface that provides
 * readEntity and writeEntity methods that by default serialize and deserialize all properties
 * via reflection. A table entity class may extend this class and override the readEntity and
 * writeEntity methods to provide customized or more performant serialization logic.
 * 

* The use of reflection allows subclasses of {@link TableServiceEntity} to be serialized and deserialized without * having to implement the serialization code themselves. When both a getter method and setter method are found for a * given property name and data type, then the appropriate method is invoked automatically to serialize or deserialize * the data. To take advantage of the automatic serialization code, your table entity classes should provide getter and * setter methods for each property in the corresponding table entity in Microsoft Azure table storage. The reflection * code looks for getter and setter methods in pairs of the form *

* public type getPropertyName() { ... } *

* and *

* public void setPropertyName(type parameter) { ... } *

* where PropertyName is a property name for the table entity, and type is a Java type compatible with * the EDM data type of the property. See the table below for a map of property types to their Java equivalents. The * {@link StoreAs} annotation may be applied with a name attribute to specify a property name for * reflection on getter and setter methods that do not follow the property name convention. Method names and the * name attribute of {@link StoreAs} annotations are case sensitive for matching property names with * reflection. Use the {@link Ignore} annotation to prevent methods from being used by reflection for automatic * serialization and deserialization. Note that the names "PartitionKey", "RowKey", "Timestamp", and "Etag" are reserved * and will be ignored if set with the {@link StoreAs} annotation in a subclass. *

* The following table shows the supported property data types in Microsoft Azure storage and the corresponding Java * types when deserialized. *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Supported property data types in Microsoft Azure storage
Storage TypeEdmType ValueJava TypeDescription
Edm.Binary{@link EdmType#BINARY}byte[], Byte[]An array of bytes up to 64 KB in size.
Edm.Boolean{@link EdmType#BOOLEAN}boolean, BooleanA Boolean value.
Edm.DateTime{@link EdmType#DATE_TIME}java.util.DateA 64-bit value expressed as Coordinated Universal Time (UTC). The supported range begins from 12:00 midnight, * January 1, 1601 A.D. (C.E.), UTC. The range ends at December 31, 9999.
Edm.Double{@link EdmType#DOUBLE}double, DoubleA 64-bit double-precision floating point value.
Edm.Guid{@link EdmType#GUID}UUIDA 128-bit globally unique identifier.
Edm.Int32{@link EdmType#INT32}int, IntegerA 32-bit integer value.
Edm.Int64{@link EdmType#INT64}long, LongA 64-bit integer value.
Edm.String{@link EdmType#STRING}StringA UTF-16-encoded value. String values may be up to 64 KB in size.
*

* See the MSDN topic Understanding the Table Service * Data Model for an overview of tables, entities, and properties as used in the Microsoft Azure Storage service. *

* For an overview of the available EDM primitive data types and names, see the * * Primitive Data Types section of * the OData Protocol Overview. *

* * @see EdmType */ public class TableServiceEntity implements TableEntity { /** * Deserializes the table entity property map into the specified object instance using reflection. *

* This static method takes an object instance that represents a table entity type and uses reflection on its class * type to find methods to deserialize the data from the property map into the instance. *

* Each property name and data type in the properties map is compared with the methods in the class type for a pair * of getter and setter methods to use for serialization and deserialization. The class is scanned for methods with * names that match the property name with "get" and "set" prepended, or with the {@link StoreAs} annotation set * with the property name. The methods must have return types or parameter data types that match the data type of * the corresponding {@link EntityProperty} value. If such a pair is found, the data is copied into the instance * object by invoking the setter method on the instance. Properties that do not match a method pair by name and data * type are not copied. * * @param instance * An Object reference to an instance of a class implementing {@link TableEntity} to * deserialize the table entity * data into. * @param properties * A java.util.HashMap object which maps String property names to * {@link EntityProperty} objects containing typed data * values to deserialize into the instance parameter object. * @param opContext * An {@link OperationContext} object that represents the context for the current operation. * * @throws IllegalArgumentException * if the table entity response received is invalid or improperly formatted. * @throws IllegalAccessException * if the table entity threw an exception during deserialization. * @throws InvocationTargetException * if a method invoked on the instance parameter threw an exception during deserialization. */ public static void readEntityWithReflection(final Object instance, final HashMap properties, final OperationContext opContext) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { final HashMap props = PropertyPair.generatePropertyPairs(instance.getClass()); for (final Entry p : properties.entrySet()) { if (props.containsKey(p.getKey())) { props.get(p.getKey()).consumeEntityProperty(p.getValue(), instance); } } } /** * Serializes the property data from a table entity instance into a property map using reflection. *

* This static method takes an object instance that represents a table entity type and uses reflection on its class * type to find methods to serialize the data from the instance into the property map. *

* Each property name and data type in the properties map is compared with the methods in the class type for a pair * of getter and setter methods to use for serialization and deserialization. The class is scanned for methods with * names that match the property name with "get" and "set" prepended, or with the {@link StoreAs} annotation set * with the property name. The methods must have return types or parameter data types that match the data type of * the corresponding {@link EntityProperty} value. If such a pair is found, the data is copied from the instance * object by invoking the getter method on the instance. Properties that do not have a method pair with matching * name and data type are not copied. * * @param instance * An Object reference to an instance of a class implementing {@link TableEntity} to * serialize the table entity * data from. * @return * A java.util.HashMap object which maps String property names to * {@link EntityProperty} objects containing typed data values serialized from the instance parameter * object. * * @throws IllegalArgumentException * if the table entity is invalid or improperly formatted. * @throws IllegalAccessException * if the table entity threw an exception during serialization. * @throws InvocationTargetException * if a method invoked on the instance parameter threw an exception during serialization. */ public static HashMap writeEntityWithReflection(final Object instance) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { final HashMap props = PropertyPair.generatePropertyPairs(instance.getClass()); final HashMap retVal = new HashMap(); for (final Entry p : props.entrySet()) { retVal.put(p.getValue().effectiveName, p.getValue().generateEntityProperty(instance)); } return retVal; } /** * The default to multiply the number of CPU's by to get the number of threads to allow in the * ReflectedEntityCache */ private static final int DEFAULT_CONCURRENCY_MULTIPLIER = 4; /** * The default load factor for the ReflectedEntityCache */ private static final float DEFAULT_LOAD_FACTOR = (float) .75; /** * The default initial capacity for the ReflectedEntityCache */ private static final int DEFAULT_INITIAL_CAPACITY = 31; /** * The reflected entity cache stores known entity types and their respective reflected entity dictionaries. Rather * than using reflection on a known entity type, the values from the dictionary are used instead. */ private static boolean disableReflectedEntityCache = false; /** * Reserved for internal use. The value of the partition key in the entity. */ protected String partitionKey = null; /** * Reserved for internal use. The value of the row key in the entity. */ protected String rowKey = null; /** * Reserved for internal use. The value of the ETag for the entity. */ protected String etag = null; /** * Reserved for internal use. The value of the Timestamp in the entity. */ protected Date timeStamp = new Date(); /** * Initializes an empty {@link TableServiceEntity} instance. */ public TableServiceEntity() { // Empty ctor } /** * Initializes a new instance of the {@link TableServiceEntity} class with the specified partition key and row key. * * @param partitionKey * A String which represents the partition key of the {@link TableServiceEntity} to be * initialized. * @param rowKey * A String which represents the row key of the {@link TableServiceEntity} to be * initialized. */ public TableServiceEntity(String partitionKey, String rowKey) { this.partitionKey = partitionKey; this.rowKey = rowKey; } /** * Gets the ETag value to verify for the entity. This value is used to determine if the table entity has changed * since it was last read from Microsoft Azure storage. The client cannot update this value on the service. * * @return * A String containing the ETag for the entity. */ @Override public String getEtag() { return this.etag; } /** * Gets the PartitionKey value for the entity. * * @return * A String containing the PartitionKey value for the entity. */ @Override public String getPartitionKey() { return this.partitionKey; } /** * Gets the RowKey value for the entity. * * @return * A String containing the RowKey value for the entity. */ @Override public String getRowKey() { return this.rowKey; } /** * Gets the Timestamp for the entity. The server manages the value of Timestamp, which cannot be modified. * * @return * A java.util.Date object which represents the Timestamp value for the entity. */ @Override public Date getTimestamp() { return this.timeStamp; } /** * Gets a value indicating whether or not the reflected entity cache is disabled. For most scenarios, disabling * the reflected entity cache is not recommended due to its effect on performance. * * The reflected entity cache stores known entity types and their respective reflected entity dictionaries. Rather * than using reflection on a known entity type, the values from the dictionary are used instead. * * @return * true if the reflected entity cache is disabled; otherwise, false. */ public static boolean isReflectedEntityCacheDisabled() { return TableServiceEntity.disableReflectedEntityCache; } /** * Sets a boolean representing whether or not the reflected entity cache is disabled. For most scenarios, disabling * the reflected entity cache is not recommended due to its effect on performance. * * The reflected entity cache stores known entity types and their respective reflected entity dictionaries. Rather * than using reflection on a known entity type, the values from the dictionary are used instead. * * @param disableReflectedEntityCache * true to disable the reflected entity cache; otherwise, false. */ public static void setReflectedEntityCacheDisabled(boolean disableReflectedEntityCache) { if (TableServiceEntity.reflectedEntityCache != null && disableReflectedEntityCache) { TableServiceEntity.reflectedEntityCache.clear(); } TableServiceEntity.disableReflectedEntityCache = disableReflectedEntityCache; } /** * Populates this table entity instance using the map of property names to {@link EntityProperty} data typed values. *

* This method invokes {@link TableServiceEntity#readEntityWithReflection} to populate the table entity instance the * method is called on using reflection. Table entity classes that extend {@link TableServiceEntity} can take * advantage of this behavior by implementing getter and setter methods for the particular properties of the table * entity in Microsoft Azure storage the class represents. *

* Override this method in classes that extend {@link TableServiceEntity} to invoke custom serialization code. * * @param properties * The java.util.HashMap of String property names to {@link EntityProperty} * data values to deserialize and store in this table entity instance. * @param opContext * An {@link OperationContext} object used to track the execution of the operation. * @throws StorageException * if an error occurs during the deserialization. */ @Override public void readEntity(final HashMap properties, final OperationContext opContext) throws StorageException { try { readEntityWithReflection(this, properties, opContext); } catch (IllegalArgumentException e) { throw new StorageException(StorageErrorCodeStrings.INVALID_DOCUMENT, SR.RESPONSE_RECEIVED_IS_INVALID, Constants.HeaderConstants.HTTP_UNUSED_306, null, e); } catch (IllegalAccessException e) { throw new StorageException(StorageErrorCodeStrings.INVALID_DOCUMENT, SR.EXCEPTION_THROWN_DURING_DESERIALIZATION, Constants.HeaderConstants.HTTP_UNUSED_306, null, e); } catch (InvocationTargetException e) { throw new StorageException(StorageErrorCodeStrings.INTERNAL_ERROR, SR.EXCEPTION_THROWN_DURING_DESERIALIZATION, Constants.HeaderConstants.HTTP_UNUSED_306, null, e); } } /** * Sets the ETag value to verify for the entity. This value is used to determine if the table entity has changed * since it was last read from Microsoft Azure storage. The client cannot update this value on the service. * * @param etag * A String containing the ETag for the entity. */ @Override public void setEtag(final String etag) { this.etag = etag; } /** * Sets the PartitionKey value for the entity. * * @param partitionKey * A String containing the PartitionKey value for the entity. */ @Override public void setPartitionKey(final String partitionKey) { this.partitionKey = partitionKey; } /** * Sets the RowKey value for the entity. * * @param rowKey * A String containing the RowKey value for the entity. */ @Override public void setRowKey(final String rowKey) { this.rowKey = rowKey; } /** * Sets the timeStamp value for the entity. Note that the timestamp property is a read-only property, * set by the service only. * * @param timeStamp * A java.util.Date containing the timeStamp value for the entity. */ @Override public void setTimestamp(final Date timeStamp) { this.timeStamp = timeStamp; } /** * Returns a map of property names to {@link EntityProperty} data typed values created by serializing this table * entity instance. *

* This method invokes {@link #writeEntityWithReflection} to serialize the table entity instance the method is * called on using reflection. Table entity classes that extend {@link TableServiceEntity} can take advantage of * this behavior by implementing getter and setter methods for the particular properties of the table entity in * Microsoft Azure storage the class represents. Note that the property names "PartitionKey", "RowKey", and * "Timestamp" are reserved and will be ignored if set on other methods with the {@link StoreAs} annotation. *

* Override this method in classes that extend {@link TableServiceEntity} to invoke custom serialization code. * * @param opContext * An {@link OperationContext} object used to track the execution of the operation. * @return * A java.util.HashMap of String property names to {@link EntityProperty} data * typed values representing the properties serialized from this table entity instance. * @throws StorageException * if an error occurs during the serialization. */ @Override public HashMap writeEntity(final OperationContext opContext) throws StorageException { try { return writeEntityWithReflection(this); } catch (final IllegalAccessException e) { throw new StorageException(StorageErrorCodeStrings.INTERNAL_ERROR, SR.ATTEMPTED_TO_SERIALIZE_INACCESSIBLE_PROPERTY, Constants.HeaderConstants.HTTP_UNUSED_306, null, e); } catch (final InvocationTargetException e) { throw new StorageException(StorageErrorCodeStrings.INTERNAL_ERROR, SR.EXCEPTION_THROWN_DURING_SERIALIZATION, Constants.HeaderConstants.HTTP_UNUSED_306, null, e); } } /** * The reflected entity cache caches known entity types and their respective reflected entity dictionaries when * entities are deserialized and the payload does not include JSON metadata. */ private static ConcurrentHashMap, HashMap> reflectedEntityCache = initialize(); private static ConcurrentHashMap, HashMap> initialize() { Runtime runtime = Runtime.getRuntime(); int numberOfProcessors = runtime.availableProcessors(); return new ConcurrentHashMap, HashMap>(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, numberOfProcessors * DEFAULT_CONCURRENCY_MULTIPLIER); } /** * The reflected entity cache caches known entity types and their respective reflected entity dictionaries when * entities are deserialized and the payload does not include JSON metadata. * * @return * The ConcurrentHashMap<Class<?>, HashMap<String, PropertyPair>> representing * the known entity types and their reflected entity dictionaries */ protected static ConcurrentHashMap, HashMap> getReflectedEntityCache() { return TableServiceEntity.reflectedEntityCache; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy