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

org.tentackle.pdo.PersistentObject Maven / Gradle / Ivy

/*
 * Tentackle - https://tentackle.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package org.tentackle.pdo;

import org.tentackle.bind.Bindable;
import org.tentackle.common.Timestamp;
import org.tentackle.misc.IdSerialTuple;
import org.tentackle.misc.Identifiable;
import org.tentackle.misc.IdentifiableMap;
import org.tentackle.misc.Immutable;
import org.tentackle.misc.Modifiable;
import org.tentackle.misc.ScrollableResource;
import org.tentackle.misc.SerialNumbered;
import org.tentackle.misc.Snapshotable;
import org.tentackle.security.Permission;
import org.tentackle.security.SecurityResult;
import org.tentackle.session.PersistenceException;
import org.tentackle.session.Persistent;
import org.tentackle.session.SessionDependable;
import org.tentackle.validate.ScopeConfigurator;
import org.tentackle.validate.Validateable;
import org.tentackle.validate.ValidationFailedException;

import java.util.List;

/**
 * Interface for the persistent part of a PDO.
 *
 * @param  the PDO
 * @author harald
 */
public interface PersistentObject>
       extends PersistenceDelegate, PdoProvider, Snapshotable, Identifiable, Modifiable, SerialNumbered,
               Validateable, Immutable, ScopeConfigurator, DomainContextDependable, SessionDependable {

  /**
   * Gets the unique identification number.
   *
   * @return the ID, 0 if object is virgin, negative if object is deleted
   */
  @Persistent(comment = "object id")
  @Override
  @Bindable
  long getId();

  /**
   * Gets the serial number.
* Whenever the object is persisted, the serial is incremented by one. * * @return the serial number, 0 if not persisted yet */ @Persistent(comment = "object version") @Override @Bindable long getSerial(); /** * Indicates whether this entity's model provides a tableserial column. * * @return true if pdo is using the tableSerial column, false if not */ boolean isTableSerialProvided(); /** * Gets the table serial. * * @return the table serial */ @Persistent(comment = "table version") @Bindable long getTableSerial(); /** * Gets the ID string: "classId:id".
* The ID string describes the PDO by its classId and object-ID. *

* Example: {@code "1022:1258474"} * * @return the id string */ String toIdString(); /** * Returns whether this an abstract PDO.
* Abstract PDOs are real objects but cannot be persisted. * They may be used to retrieve data for the concrete implementations, however. * * @return true if abstract PDO */ boolean isAbstract(); /** * Returns whether this PDO is a composite.
* Composite PDOs consist of other component PDOs, defined via composite relations.
* Notice that a composite root entity is synonym to the aggregate root in DDD lingo. * * @return true if object is a composite, false if not. */ boolean isComposite(); /** * Returns whether this object is a root entity.
* All entities that are not a component of another entity, are considered as a root entity. * They correspond to the so-called aggregate root in DDD, * with the subtle difference that a root entity may have no components at all.
* Only root entities can be persisted! *

* Root entities maintain their own entity context in {@link DomainContext}. * * @return true if root entity */ boolean isRootEntity(); /** * Returns whether this is an embedded PDO.
* Embedded PDOs are components with their attributes embedded in the parent object's table. * * @return true if embedded entity */ boolean isEmbedded(); /** * Gets the parent PDO if this is an embedded PDO.
* Throws a {@link PersistenceException} if this is not an embedded PDO. * * @return the parent PDO, never null * @param the parent's type */ > E getEmbeddingParent(); /** * Returns whether this is a root entity of given component. * * @param the type of the component * @param component the component pdo * @return true if this is the root entity of given component */ > boolean isRootEntityOf(C component); /** * Indicates whether this entity provides a root-ID column.
* The column is added in components without a direct parent ID relation * to provide the ID of the root entity without accessing the database. * * @return true if column provided, false if not * @see #getRootId() */ boolean isRootIdProvided(); /** * Gets the ID of the root entity this component belongs to. * * @return the root id */ @Persistent(comment = "root id") @Bindable long getRootId(); /** * Indicates whether this entity's model provides a root-class-ID column.
* The column is added in components that belong to different root entity classes. * * @return true if column provided, false if not */ boolean isRootClassIdProvided(); /** * Gets the class ID of the root entity this component belongs to. * * @return the root class id */ @Persistent(comment = "root class id") @Bindable int getRootClassId(); /** * Gets the database table name for the class of this object. *

* Notice: for MULTI-inheritance entities the tablename is the * last in the inheritance chain. * * @return the table name, null if class does not map to a database table */ String getTableName(); /** * Gets the basename of the class of this object.
* The basename is the class name without the package name. * * @return the basename of the Objects class */ String getClassBaseName(); /** * Gets the unique ID of the class.
* Class IDs are provided as a replacement for FQCNs for 2 reasons: *

    *
  1. refactoring: package- and classnames may be changed. The class ID is fixed.
  2. *
  3. performance: comparing integers is faster than comparing strings (in Java and the database)
  4. *
* Notice that abstract entities (all except the leaves within an inheritance hierarchy) don't have a classid. * * @return the class id, 0 if abstract */ @Persistent(comment = "class id") @Bindable int getClassId(); /** * Creates the {@link SecurityResult} for a given permission. * * @param permission the requested permission * @return the security result (never null) */ SecurityResult getSecurityResult(Permission permission); /** * Checks if the permission for a given permission is accepted. * * @param permission the requested permission * @return true if permission is accepted */ boolean isPermissionAccepted(Permission permission); /** * Determines whether the application is allowed to write this PDO. *

* Notice that there is no {@code isReadAllowed()}, because PDOs without read permission * won't be loaded at all. * * @return true if allowed */ boolean isWriteAllowed(); /** * Determines whether the user is allowed to view this PDO.
* Can be used to determine whether object is shown to the user. * * @return true if allowed */ boolean isViewAllowed(); /** * Determines whether the user is allowed to edit this PDO.
* Can be used to determine whether object is editable by the user. * * @return true if allowed */ boolean isEditAllowed(); /** * Checks whether this object is already persistent in the database or only residing in memory.
* If an object {@code isNew()}, it means that it can be persisted (inserted). * This does not mean, that the object has never been stored in the database, * i.e. it is possible that the object just has been deleted. * * @return true if object is not in database, i.e. new (or deleted) */ boolean isNew(); /** * Reserves an ID.

* Reserved IDs are negative. * A new object with a reserved ID can be distinguished from * a deleted object by its serial. See also {@link #isVirgin}. * If the object already has an ID or is deleted (negative ID) * the ID will _not_ change. */ void reserveId(); /** * Reserves a given ID.
* It doesn't matter whether the ID is negative or positive. * Reserving 0 clears the reservation. *

* Throws a {@link PersistenceException} if the object is not new. * * @param id the ID to reserve, 0 to clear the reservation */ void reserveId(long id); /** * Checks whether object is deleted. * * @return true if object has been removed from the database */ boolean isDeleted(); /** * Returns whether the modification state is available.
* By default, PDOs are not tracked.
* This is quality measure to ensure that isModified() returns * false if and only if it hasn't been modified, i.e. the (generated) code * checks for modification properly. * * @return true if tracked, false otherwise (default) */ boolean isTracked(); /** * Determines whether this object got some of its attributes modified.
* It does not check whether some of its components are modified! * This method can also be used for non-tracked entities. * * @return true if this object */ boolean attributesModified(); /** * Returns whether any of the attributes differs from the values persisted in the database.
* This method is only applicable to fulltracked entities and returns false if not fulltracked. * * @return true if differs, false if no change or entity isn't fulltracked */ boolean differsPersisted(); /** * Determines whether this object is allowed to be stored in database.
* Notice that once a PDO is persisted, the same object reference is no more persistable * and must be reloaded. Rule: if the reference is no more used, use {@link #save()}, * otherwise use {@link #persist()} and replace the reference with the return value. * * @return true if persistable (default) * @see #persist() * @see #save() */ boolean isPersistable(); /** * Checks whether this object is referenced by other objects. *

* The method can be invoked before operations that may have an impact on the * referential integrity, for example to enable a delete button in the UI.
* The default implementation returns false. * * @return true if referenced */ boolean isReferenced(); /** * Checks whether this object can be removed. *

* Should be invoked before operations that may have an impact on the * referential integrity, for example to enable a delete button in the UI.
* The default implementation returns {@code !isNew() && !isReferenced()}. * * @return true if removable */ boolean isRemovable(); /** * Removes this object from the database. */ void delete(); /** * Sets this object's expiration flag.
* Expired objects are considered as invalid and must be reloaded before being used any further. * Used in caches. * * @param expired true if object is expired */ void setExpired(boolean expired); /** * Checks whether object has been marked expired.
* Expired objects will be reloaded from the database by * the cache when the object is retrieved again. * * @return true if object is expired (in cache) */ boolean isExpired(); /** * Gets the current modification count for the whole class.
* The count corresponds to the table serial. * * @return the modification count * @see org.tentackle.session.ModificationTracker */ long getModificationCount(); /** * Gets the expired table serials.
* A physical database query is only done if the requested range is not in the backlog. * Used to reduce roundtrips for remote sessions. * * @param oldSerial non-inclusive lower bound for tableSerial (> oldSerial) * @param maxSerial inclusive upper bound for tableSerial (≤ maxSerial) * @return pairs of longs, the first being the ID, the second the tableserial, never null */ List getExpiredTableSerials(long oldSerial, long maxSerial); /** * Determines the objects with a tableSerial starting at a given serial. * Useful to clean up caches for example. * * @param oldSerial non-inclusive lower bound for tableSerial (> oldSerial) * @return pairs of longs, the first being the ID, the second the tableserial, never null */ List selectExpiredTableSerials(long oldSerial); /** * Determines the objects with their tableSerial within a given range. * Useful to clean up caches. * * @param oldSerial non-inclusive lower bound for tableSerial (> oldSerial) * @param maxSerial inclusive upper bound for tableSerial (≤ maxSerial) * @return pairs of longs, the first being the ID, the second the tableserial, never null */ List selectExpiredTableSerials(long oldSerial, long maxSerial); /** * Selects all pdos with a tableSerial starting at a given serial.
* Useful to update expired objects in a batch. * * @param oldSerial non-inclusive lower bound for tableSerial (> oldSerial) * @return the list of objects, never null */ List selectAllWithExpiredTableSerials(long oldSerial); /** * Selects all id,serial-pairs of this class as a list of {@link IdSerialTuple}. * * @return the list of objects */ List selectAllIdSerial(); /** * Selects the serial-number for a given object id from the database. * * @param id the object id * @return the serial for that id, -1 if no such object */ long selectSerial(long id); /** * Selects the highest id. * * @return the highest id, -1 if table is empty */ long selectMaxId(); /** * Selects the highest table serial. * * @return the highest table serial, -1 if table is empty */ long selectMaxTableSerial(); /** * Gets the cache. *

* Notice that abstract classes don't provide their own cache, but * instead use the caches of their concrete classes. * * @return the cache for this PDO, null if none. */ PdoCache getCache(); /** * Gets the last cache access time. * * @return the last cache access time */ long getCacheAccessTime(); /** * Gets the cache access count. * * @return the access count */ long getCacheAccessCount(); /** * Marks the cache access.
* Increments the access counter and sets the last access time. */ void markCacheAccess(); /** * Returns whether object is cached. * * @return true if cached */ boolean isCached(); /** * Determines whether object is cacheable or not.
* The default implementation always returns true, but apps * can use this as a filter. * * @return true if object is cacheable */ boolean isCacheable(); /** * Searches for a "pattern" in this object.
* The default implementation looks for the pattern in the normtext. * * @param pattern the pattern to search for * @return true if this object "contains" the pattern */ boolean containsPattern (String pattern); /** * Checks whether this object (if saved) would violate any unique constraints. *

* The method is usually used by the presentation layer to check for duplicates. * The default implementation invokes findByUniqueDomainKey(getUniqueDomainKey()) * and throws {@link UnsupportedOperationException} if one of those methods are not implemented * (which is the default). * * @return the duplicate object, null if no duplicate */ T findDuplicate(); /** * Indicates whether this entity provides the token lock columns. * * @return true if token lock columns present, false if not. */ boolean isTokenLockProvided(); /** * Gets the expiration in milliseconds of the token lock.
* Returns a value greater 0 if {@link #isTokenLockProvided()}, else 0. * * @return the timespan in ms, 0 if no token lock */ long getTokenLockTimeout(); /** * Requests a token lock. *

* Throws a {@link LockException} if locked by another user. */ void requestTokenLock(); /** * Releases a token lock.
* Use this method if a PDO needs to be unlocked without being persisted. */ void releaseTokenLock(); /** * Checks whether this object is token locked and the lock is not expired. * * @return true if locked by any user * @see #isTokenLockedByMe() */ boolean isTokenLocked(); /** * Checks whether this object is token locked by given user. * * @param userId the user's ID * @return true locked */ boolean isTokenLockedBy(long userId); /** * Checks whether this object is token locked by the current user. * * @return true if locked */ boolean isTokenLockedByMe(); /** * Checks whether requesting a token lock for the current user is possible. * * @return true if object is not locked at all or locked by the current user */ boolean isTokenLockableByMe(); /** * Transfers the token lock to another user.
* Necessary to hand over a token without releasing it.
* Eliminates the time-gap when object is token-free.
* Allows taking over the token WITHOUT possessing it! * This method should be used with great care as it does not check * who owns the token and if there is a token at all. * The serial will be increased, so the old user gets an error * if trying to update.
* Furthermore, the current object does *NOT* get the serial increased * thus preventing any update without reloading the object again! * You have to use the returned PDO! *
* The modification table is updated because the serial is increased and thus all caches must be invalidated. *

* CAUTION: the method is provided for rare corner cases like administration tools. * Don't use it for regular locking/unlocking! * * @param userId is the new user-ID. (special 0 = free token, even if we are not the owner!) * @return the updated PDO */ T transferTokenLock(long userId); /** * Loads a PDO from the database by its unique ID.
* * @param id is the object id * * @return object if loaded, null if no such object */ T select(long id); /** * Loads a PDO from the database by its unique ID and applies a token lock.
* Same as {@link #select(long)} followed by {@link #requestTokenLock()}, but requires only a single roundtrip if remote. *

* Throws a {@link LockException}, if locked by another user. * * @param id is the object id * * @return object if loaded, null if no such object */ T selectTokenLocked(long id); /** * Loads a PDO from the database by its unique ID with a database write-lock.
* Requires that a transaction is running. * * @param id is the object id * * @return object if loaded, null if no such object */ T selectForUpdate(long id); /** * Reloads the object. * * @return the object if reloaded, null if vanished from the database */ T reload(); /** * Reloads the object and applies a token lock.
* Same as {@link #reload()} followed by {@link #requestTokenLock()}, but requires only a single roundtrip if remote. *

* Throws a {@link LockException}, if locked by another user. * * @return the object if reloaded, null if vanished from the database */ T reloadTokenLocked(); /** * Reloads the object with a database write-lock.
* Requires that a transaction is running. * * @return the object if reloaded, else null */ T reloadForUpdate(); /** * Selects all objects of this class.
* Eager relations are loaded as well, but limited to the first level to prevent join hogs. * If more than one level must be eagerly loaded, use explicit finders. * * @return the list of objects */ List selectAll(); /** * Selects all records in current context as a cursor. * * @return the cursor */ ScrollableResource selectAllAsCursor(); /** * Selects the latest PDOs.
* Returns an optionally limited list of PDOs sorted by ID descending. * * @param greaterId the lower excluding ID * @param limit the optional limit, 0 if unlimited * @return the list of objects, never null */ List selectLatest(long greaterId, int limit); /** * Gets the object via cache.
* If there is no cache, the default implementation just loads from the database. * * @param id the unique object ID * @return the object, null if no such object * @see #select(long) */ T selectCached(long id); /** * Gets the object via cache only.
* If there is no cache, the default implementation just loads from the database. * * @param id the unique object ID * @return the object, null if no such object * @see #select(long) */ T selectCachedOnly(long id); /** * Gets all objects in context via cache.
* If there is no cache, the default implementation load from the database. * * @return the list, never null * @see #selectAll() */ List selectAllCached(); /** * Selects all objects to be loaded into the cache. *

* The method is used mainly by {@link PdoCache} as an optimization to retrieve * the list of PDOs from the remote server cache. * * @return the list, never null * @throws PersistenceException if the session is not remote */ List selectAllForCache(); /** * Selects a PDO to be loaded into the cache. *

* The method is used mainly by {@link PdoCache} as an optimization to retrieve * a PDO from the remote server cache. * * @param id is the object id * * @return object if loaded, null if no such object */ T selectForCache(long id); /** * Validates this PDO.
* Invokes all field- and object validators.
* If the PDO is a composite, all components will be validated as well. * Root entities are automatically validated when save()d or persist()ed. * * @throws ValidationFailedException if validation fails */ void validate(); /** * Returns whether PDO has been successfully validated.
* A PDO is validated if not modified since the last validation * or not modified since loaded from the backend. * * @return true if validated, false if PDO needs validation before being persisted */ boolean isValidated(); /** * Save this PDO.
* If the object is new, a new ID is obtained and the object inserted. * Otherwise, the object is updated. *

* A saved object is no more persistable. * It must be {@link #reload()}-ed to make it persistable again. *

* Any token lock will be removed. * @see #persist() */ void save(); /** * Persist this PDO.
* Same as {@link #save()} but returns the persisted object.
* The returned object is persistable.
* If the session is local, {@code this} is returned. For remote sessions, * the returned reference is always another instance. * * @return the persisted object, never null * @see #save() */ T persist(); /** * Persist this PDO and renew the token lock.
* Use this method if the application continues to work with the locked PDO * after being persisted. * * @return the persisted object, never null */ T persistTokenLocked(); /** * Gets the id of the user currently editing this object. * * @return the id or 0 if not being edited currently. */ @Persistent(comment = "userId of token holder") @Bindable long getEditedBy(); /** * Gets the time since when this object is being edited. * * @return the time, null if not being edited. */ @Persistent(comment = "time since token given to user") @Bindable Timestamp getEditedSince(); /** * Gets the time since when this object is being edited. * * @return the time, null if not being edited. */ @Persistent(comment = "time when token expires") @Bindable Timestamp getEditedExpiry(); /** * Indicates whether this entity's model provides at least one normtext column. * * @return true if pdo is using the normtext column, false if not. */ boolean isNormTextProvided(); /** * Gets the normtext.
* The normtext holds the normalized text of columns and relations. * * @return the normtext * @see org.tentackle.common.StringNormalizer#normalize(String) */ @Persistent(comment = "normalized text") String getNormText(); /** * Selects all objects containing a normalized text.
* The given text will be normalized via {@link org.tentackle.common.StringNormalizer#normalize(String)} * and selected via a sql {@code LIKE} expression. * If the text begins with an exclamation mark or a minus-sign (! or -), {@code NOT LIKE} will be used. * * @param text the text to search for * @return the list of objects, never null */ List selectByNormText(String text); /** * Same as {@link #selectByNormText(String)} but returns a cursor. * * @param text the text to search for * @return the cursor */ ScrollableResource selectByNormTextAsCursor(String text); /** * Loads all components.
* The method is used to transfer a copy of an object between tiers including all * composite object relations recursively. * Furthermore, it can be used to get a map of all components. * * @param onlyLoaded true if return only already loaded components (lazy composite relations) * @return the map of all components, including this object. */ IdentifiableMap> loadComponents(boolean onlyLoaded); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy