/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Florent Guillaume */ package org.eclipse.ecr.core.storage.sql; import java.io.Serializable; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.transaction.xa.XAException; import javax.transaction.xa.Xid; import org.eclipse.ecr.core.storage.StorageException; import org.eclipse.ecr.core.storage.sql.Invalidations.InvalidationsPair; /** * A {@link RowMapper} maps {@link Row}s to and from the database. * <p> * These are the operations that can benefit from a cache. * * @see CachingRowMapper */ public interface RowMapper { /* * ----- Batch ----- */ /** * Reads a set of rows for the given {@link RowId}s. * <p> * For each requested row, either a {@link Row} is found and returned, or a * {@link RowId} (not implementing {@link Row}) is returned to signify an * absent row. * * @param rowIds the row ids (including their table name) * @return the collection of {@link Row}s (or {@link RowId}s if the row was * absent from the database). Order is not the same as the input * {@code rowIds} * @throws StorageException */ List<? extends RowId> read(Collection<RowId> rowIds) throws StorageException; /** * A {@link Row} and a list of its keys that have to be updated. */ public static final class RowUpdate implements Serializable { private static final long serialVersionUID = 1L; public final Row row; public final Collection<String> keys; public RowUpdate(Row row, Collection<String> keys) { this.row = row; this.keys = keys; } @Override public int hashCode() { return row.hashCode(); } @Override public boolean equals(Object other) { if (other instanceof RowUpdate) { return equal((RowUpdate) other); } return false; } private boolean equal(RowUpdate other) { return other.row.equals(row); } @Override public String toString() { return getClass().getSimpleName() + '(' + row + ", keys=" + keys + ')'; } } /** * The description of a set of rows to create, update or delete. */ public static class RowBatch implements Serializable { private static final long serialVersionUID = 1L; /** * Creates are done first and are ordered. */ public final List<Row> creates; /** * Updates. */ public final Set<RowUpdate> updates; /** * Deletes are done last. */ public final Set<RowId> deletes; public RowBatch() { creates = new LinkedList<Row>(); updates = new HashSet<RowUpdate>(); deletes = new HashSet<RowId>(); } public boolean isEmpty() { return creates.isEmpty() && updates.isEmpty() && deletes.isEmpty(); } @Override public String toString() { return getClass().getSimpleName() + "(creates=" + creates + ", updates=" + updates + ", deletes=" + deletes + ')'; } } /** * Writes a set of rows. This includes creating, updating and deleting rows. * * @param batch the set of rows and the operations to do on them * @throws StorageException */ void write(RowBatch batch) throws StorageException; /* * ----- Read ----- */ /** * Gets a row for a {@link SimpleFragment} from the database, given its * table name and id. If the row doesn't exist, {@code null} is returned. * * @param rowId the row id * @return the row, or {@code null} */ Row readSimpleRow(RowId rowId) throws StorageException; /** * Gets an array for a {@link CollectionFragment} from the database, given * its table name and id. If no rows are found, an empty array is returned. * * @param rowId the row id * @return the array */ Serializable[] readCollectionRowArray(RowId rowId) throws StorageException; /** * Reads the hierarchy row for a child, given its parent id and the child * name. * * @param parentId the parent id * @param childName the child name * @param complexProp whether to get complex properties ({@code true}) or * regular children({@code false}) * @return the child hierarchy row, or {@code null} */ Row readChildHierRow(Serializable parentId, String childName, boolean complexProp) throws StorageException; /** * Reads the hierarchy rows for all the children of parent. * <p> * Depending on the boolean {@literal complexProp}, only the complex * properties or only the regular children are returned. * * @param parentId the parent id * @param complexProp whether to get complex properties ({@code true}) or * regular children({@code false}) * @return the child hierarchy rows */ List<Row> readChildHierRows(Serializable parentId, boolean complexProp) throws StorageException; /** * Gets the list of version rows for all the versions in a given version * series id. * * @param versionSeriesId the version series id * @return the list of version rows * @throws StorageException */ List<Row> getVersionRows(Serializable versionSeriesId) throws StorageException; /** * Finds proxies, maybe restricted to the children of a given parent. * * @param searchId the id to look for * @param byTarget {@code true} if the searchId is a proxy target id, * {@code false} if the searchId is a version series id * @param parentId the parent to which to restrict, if not {@code null} * @return the list of proxies rows * @throws StorageException */ List<Row> getProxyRows(Serializable searchId, boolean byTarget, Serializable parentId) throws StorageException; /* * ----- Copy ----- */ public static final class IdWithTypes implements Serializable { private static final long serialVersionUID = 1L; public final Serializable id; public final String primaryType; public final String[] mixinTypes; public IdWithTypes(Serializable id, String primaryType, String[] mixinTypes) { this.id = id; this.primaryType = primaryType; this.mixinTypes = mixinTypes; } public IdWithTypes(Node node) { this.id = node.getId(); this.primaryType = node.getPrimaryType(); this.mixinTypes = node.getMixinTypes(); } } public static final class CopyHierarchyResult implements Serializable { private static final long serialVersionUID = 1L; /** The id of the root of the copy. */ public final Serializable copyId; /** The invalidations generated by the copy. */ public final Invalidations invalidations; public CopyHierarchyResult(Serializable copyId, Invalidations invalidations) { this.copyId = copyId; this.invalidations = invalidations; } } /** * Copies the hierarchy starting from a given row to a new parent with a new * name. * <p> * If the new parent is {@code null}, then this is a version creation, which * doesn't recurse in regular children. * <p> * If {@code overwriteRow} is passed, the copy is done onto this existing * node as its root (version restore) instead of creating a new node in the * parent. * * @param source the id, primary type and mixin types of the row to copy * @param destParentId the new parent id, or {@code null} * @param destName the new name * @param overwriteRow when not {@code null}, the copy is done onto this * existing row, and the values are set in hierarchy * @return info about the copy * @throws StorageException */ CopyHierarchyResult copyHierarchy(IdWithTypes source, Serializable destParentId, String destName, Row overwriteRow) throws StorageException; /** * Processes and returns the invalidations queued for processing by the * cache (if any). * <p> * Called pre-transaction by session start or transactionless save; * * @return the invalidations (both for the mapper and the events), or * {@code null} */ InvalidationsPair receiveInvalidations() throws StorageException; /** * Post-transaction invalidations notification. * <p> * Called post-transaction by session commit/rollback or transactionless * save. * * @param invalidations the known invalidations to send to others, or * {@code null} */ void sendInvalidations(Invalidations invalidations) throws StorageException; /** * Clears the mapper's cache (if any) * <p> * Called after a rollback, or a manual clear through RepositoryStatus * MBean. */ void clearCache(); /** * Rollback the XA Resource. * <p> * This is in the {@link RowMapper} interface because on rollback the cache * must be invalidated. */ void rollback(Xid xid) throws XAException; }