/* * Copyright 2006 Amazon Technologies, Inc. or its affiliates. * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks * of Amazon Technologies, Inc. or its affiliates. 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. */ package com.amazon.carbonado; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Map; /** * A data access object in a {@link Repository}. User defined storables must * either extend or implement this interface via an interface or abstract * class. Abstract bean properties defined in the storable are persisted into * the repository. At least one property must be annotated as the {@link * PrimaryKey}. At most one property may be annotated as being the {@link * Version} property. * *
Storable instances are mutable, but they must be thread-safe. Although
* race conditions are possible if multiple threads are mutating the Storable,
* the Storable instance will not get into a corrupt state.
*
* @author Brian S O'Neill
* @author Don Schneider
*
* @see com.amazon.carbonado.Alias
* @see com.amazon.carbonado.Indexes
* @see com.amazon.carbonado.Join
* @see com.amazon.carbonado.Nullable
* @see com.amazon.carbonado.PrimaryKey
* @see com.amazon.carbonado.Version
*/
public interface Storable> {
/**
* Loads or reloads this object from the storage layer by a primary or
* alternate key. All properties of a key must be initialized for it to be
* chosen. The primary key is examined first, and if not fully initialized,
* alternate keys are examined in turn.
*
*
If load is successful, altering the primary key is no longer allowed * unless a call to delete succeeds. Attempting to alter the primary key in * this state results in an {@link IllegalStateException}. Alternate keys * may always be modified, however. * *
Note: This method differs from {@link #tryLoad} only in that it * throws an exception if no matching record was found, instead of returning * false. This may indicate that the underlying record was deleted between * a load and reload. When a FetchNoneException is thrown, this object's * state will be the same as if the delete method was called on it. * * @throws FetchNoneException if no matching record found * @throws FetchException if storage layer throws an exception * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified */ void load() throws FetchNoneException, FetchException; /** * Loads or reloads this object from the storage layer by a primary or * alternate key. All properties of a key must be initialized for it to be * chosen. The primary key is examined first, and if not fully initialized, * alternate keys are examined in turn. * *
If load is successful, altering the primary key is no longer allowed * unless a call to delete succeeds. Attempting to alter the primary key in * this state results in an {@link IllegalStateException}. Alternate keys * may always be modified, however. * *
Note: This method differs from {@link #load} only in that it returns * false if no matching record was found, instead of throwing an exception. * This may indicate that the underlying record was deleted between a load * and reload. When false is returned, this object's state will be the same * as if the delete method was called on it. * * @return true if found and loaded, false otherwise * @throws FetchException if storage layer throws an exception * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified */ boolean tryLoad() throws FetchException; /** * Inserts a new persistent value for this object. If successful, altering * the primary key is no longer allowed unless a call to delete succeeds. * Attempting to alter the primary key in this state results in an {@link * IllegalStateException}. Alternate keys may always be modified, however. * *
Insert requires that all primary key properties be specified. If not, * an {@link IllegalStateException} is thrown. Also, repository * implementations usually require that properties which are not {@link * Nullable} also be specified. Otherwise, a {@link ConstraintException} * may be thrown. * *
Note: This method differs from {@link #tryInsert} only in that it may * throw a UniqueConstraintException, instead of returning false. * * @throws UniqueConstraintException if it is absolutely known that a key * of inserted object matches an existing one * @throws ConstraintException if any required properties are unspecified * @throws PersistException if storage layer throws an exception * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified */ void insert() throws PersistException; /** * Inserts a new persistent value for this object. If successful, altering * the primary key is no longer allowed unless a call to delete succeeds. * Attempting to alter the primary key in this state results in an {@link * IllegalStateException}. Alternate keys may always be modified, however. * *
Insert requires that all primary key properties be specified. If not, * an {@link IllegalStateException} is thrown. Also, repository * implementations usually require that properties which are not {@link * Nullable} also be specified. Otherwise, a {@link ConstraintException} * may be thrown. * *
Note: This method differs from {@link #insert} only in that it * returns false, instead of throwing a UniqueConstraintException. * * @return false if it is absolutely known that a key of inserted object * matches an existing one * @throws ConstraintException if any required properties are unspecified * @throws PersistException if storage layer throws an exception * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified */ boolean tryInsert() throws PersistException; /** * Updates the persistent value of this object, regardless of whether this * object has actually been loaded or not. If successful, altering the * primary key is no longer allowed unless a call to delete succeeds. * Attempting to alter the primary key in this state results in an {@link * IllegalStateException}. Alternate keys may always be modified, however. * *
If this object has a {@link Version version} property defined, then * the update logic is a bit more strict. Updates of any storable require * that the primary keys be specified; if a version is present, the version * must be specified as well. If any of the primary key or version * properties are unspecified, an {@link IllegalStateException} will be * thrown; if they are fully specified and the version doesn't match the * current record, an {@link OptimisticLockException} is thrown. * *
Not all properties need to be set on this object when calling * update. Setting a subset results in a partial update. After a successful * update, all properties are set to the actual values in the storage * layer. Put another way, the object is automatically reloaded after a * successful update. * *
If PersistNoneException is thrown, this indicates that the underlying * record was deleted. When this happens, this object's state will be the * same as if the delete method was called on it. * * @throws PersistNoneException if record is missing and no update occurred * @throws PersistException if storage layer throws an exception * @throws OptimisticLockException if a version property exists and the * optimistic lock failed * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified, or if a version property is unspecified */ void update() throws PersistException; /** * Updates the persistent value of this object, regardless of whether this * object has actually been loaded or not. If successful, altering the * primary key is no longer allowed unless a call to delete succeeds. * Attempting to alter the primary key in this state results in an {@link * IllegalStateException}. Alternate keys may always be modified, however. * *
If this object has a {@link Version version} property defined, then * the update logic is a bit more strict. Updates of any storable require * that the primary keys be specified; if a version is present, the version * must be specified as well. If any of the primary key or version * properties are unspecified, an {@link IllegalStateException} will be * thrown; if they are fully specified and the version doesn't match the * current record, an {@link OptimisticLockException} is thrown. * *
Not all properties need to be set on this object when calling * update. Setting a subset results in a partial update. After a successful * update, all properties are set to the actual values in the storage * layer. Put another way, the object is automatically reloaded after a * successful update. * *
A return value of false indicates that the underlying record was * deleted. When this happens, this object's state will be the same as if * the delete method was called on it. * * @return true if record likely exists and was updated, or false if record * absolutely no longer exists and no update occurred * @throws PersistException if storage layer throws an exception * @throws OptimisticLockException if a version property exists and the * optimistic lock failed * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified, or if a version property is unspecified */ boolean tryUpdate() throws PersistException; /** * Deletes this object from the storage layer by its primary key, * regardless of whether this object has actually been loaded or not. * Calling delete does not prevent this object from being used again. All * property values are still valid, including the primary key. Once * deleted, the insert operation is permitted again. * *
Note: This method differs from {@link #tryDelete} only in that it may * throw a PersistNoneException, instead of returning false. * * @throws PersistNoneException if record is missing and nothing was * deleted * @throws PersistException if storage layer throws an exception * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified */ void delete() throws PersistException; /** * Deletes this object from the storage layer by its primary key, * regardless of whether this object has actually been loaded or not. * Calling delete does not prevent this object from being used again. All * property values are still valid, including the primary key. Once * deleted, the insert operation is permitted again. * *
Note: This method differs from {@link #delete} only in that it * returns false, instead of throwing a PersistNoneException. * * @return true if record likely existed and was deleted, or false if record * absolutely no longer exists and no delete was necessary * @throws PersistException if storage layer throws an exception * @throws IllegalStateException if the state of this instance suggests * that any primary keys are unspecified */ boolean tryDelete() throws PersistException; /** * Returns the class or interface from which this storable was * generated. This represents the data class for the storable. * *
Design note: the name "getStorableType" is avoided, so as not to
* conflict with a user defined property of "storableType"
*/
Class The encoding used by this method is much simpler than what is
* provided by standard object serialization. It does not encode class info
* or property names, which is why it is not suitable for long term
* storage.
*
* @throws IOException if exception from stream
* @throws SupportException if Storable cannot be serialized
* @since 1.2
*/
void writeTo(OutputStream out) throws IOException, SupportException;
/**
* Restores property values and states as encoded by {@link #writeTo}.
* Derived properties are not directly modified, but all other properties
* not restored are reset to their initial state.
*
* @throws IOException if exception from stream
* @throws SupportException if Storable cannot be serialized
* @since 1.2
*/
void readFrom(InputStream in) throws IOException, SupportException;
int hashCode();
/**
* True if all properties and fields are equal, but ignoring the state.
*
* @param obj object to compare to for equality
*/
boolean equals(Object obj);
/**
* True if the supported properties which participate in the primary key
* are equal. This is useful to cheaply investigate if two storables refer
* to the same entity, regardless of the state of object (specifically the
* non-key properties). Unsupported {@link Independent independent}
* properties in this or the target are not compared.
*
* @param obj object to compare to for equality
*/
boolean equalPrimaryKeys(Object obj);
/**
* True if all supported properties for this object are equal. Unsupported
* {@link Independent independent} properties in this or the target are not
* compared.
*
* @param obj object to compare to for equality
*/
boolean equalProperties(Object obj);
/**
* Returns a string for debugging purposes that contains all supported
* property names and values for this object. Uninitialized and unsupported
* {@link Independent independent} properties are not included.
*/
String toString();
/**
* Returns a string for debugging purposes that contains supported key
* property names and values for this object. Uninitialized and unsupported
* {@link Independent independent} properties are not included.
*/
String toStringKeyOnly();
}
storableType();
/**
* Copies all supported properties, skipping any that are uninitialized.
* Specifically, calls {@literal "target.set