001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: PersistEntityBinding.java,v 1.16.2.3 2008/01/07 15:14:20 cwl Exp $
007: */
008:
009: package com.sleepycat.persist.impl;
010:
011: import com.sleepycat.bind.EntityBinding;
012: import com.sleepycat.bind.tuple.TupleBase;
013: import com.sleepycat.je.DatabaseEntry;
014: import com.sleepycat.persist.model.EntityModel;
015: import com.sleepycat.persist.raw.RawObject;
016:
017: /**
018: * A persistence entity binding for a given entity class.
019: *
020: * @author Mark Hayes
021: */
022: public class PersistEntityBinding implements EntityBinding {
023:
024: PersistCatalog catalog;
025: Format entityFormat;
026: boolean rawAccess;
027: PersistKeyAssigner keyAssigner;
028:
029: /**
030: * Creates a key binding for a given entity class.
031: */
032: public PersistEntityBinding(PersistCatalog catalog,
033: String entityClassName, boolean rawAccess) {
034: this .catalog = catalog;
035: if (rawAccess) {
036: entityFormat = catalog.getFormat(entityClassName);
037: if (entityFormat == null || !entityFormat.isEntity()) {
038: throw new IllegalArgumentException(
039: "Not an entity class: " + entityClassName);
040: }
041: } else {
042: Class entityCls;
043: try {
044: entityCls = EntityModel.classForName(entityClassName);
045: } catch (ClassNotFoundException e) {
046: throw new IllegalArgumentException(e);
047: }
048: entityFormat = catalog.getFormat(entityCls);
049: }
050: this .rawAccess = rawAccess;
051: }
052:
053: public PersistKeyAssigner getKeyAssigner() {
054: return keyAssigner;
055: }
056:
057: public Object entryToObject(DatabaseEntry key, DatabaseEntry data) {
058: return readEntity(catalog, key, data, rawAccess);
059: }
060:
061: /**
062: * Creates the instance, reads the entity key first to track visited
063: * entities correctly, then reads the data and returns the entity.
064: *
065: * This is a special case of EntityInput.readObject for a top level entity.
066: * Special treatments are:
067: * - The formatId must be >= 0; since this is the top level instance, it
068: * cannot refer to a visited object nor be a null reference.
069: * - The resulting entity is not added to the visited object set; entities
070: * cannot be referenced by another (or the same) entity.
071: * - Reader.readPriKey must be called prior to calling Reader.readObject.
072: */
073: static Object readEntity(Catalog catalog, DatabaseEntry key,
074: DatabaseEntry data, boolean rawAccess) {
075: RecordInput keyInput = new RecordInput(catalog, rawAccess,
076: null, 0, key.getData(), key.getOffset(), key.getSize());
077: RecordInput dataInput = new RecordInput(catalog, rawAccess,
078: null, 0, data.getData(), data.getOffset(), data
079: .getSize());
080: int formatId = dataInput.readPackedInt();
081: Format format = catalog.getFormat(formatId);
082: Reader reader = format.getReader();
083: Object entity = reader.newInstance(dataInput, rawAccess);
084: reader.readPriKey(entity, keyInput, rawAccess);
085: return reader.readObject(entity, dataInput, rawAccess);
086: }
087:
088: public void objectToData(Object entity, DatabaseEntry data) {
089: Format format = getValidFormat(entity);
090: writeEntity(format, catalog, entity, data, rawAccess);
091: }
092:
093: /**
094: * Writes the formatId and object, and returns the bytes.
095: *
096: * This is a special case of EntityOutput.writeObject for a top level
097: * entity. Special treatments are:
098: * - The entity may not be null.
099: * - The entity is not added to the visited object set nor checked for
100: * existence in the visited object set; entities cannot be referenced by
101: * another (or the same) entity.
102: */
103: static void writeEntity(Format format, Catalog catalog,
104: Object entity, DatabaseEntry data, boolean rawAccess) {
105: RecordOutput output = new RecordOutput(catalog, rawAccess);
106: output.writePackedInt(format.getId());
107: format.writeObject(entity, output, rawAccess);
108: TupleBase.outputToEntry(output, data);
109: }
110:
111: public void objectToKey(Object entity, DatabaseEntry key) {
112:
113: /*
114: * Write the primary key field as a special case since the output
115: * format is for a key binding, not entity data.
116: */
117: Format format = getValidFormat(entity);
118: RecordOutput output = new RecordOutput(catalog, rawAccess);
119:
120: /* Write the primary key and return the bytes. */
121: format.writePriKey(entity, output, rawAccess);
122: TupleBase.outputToEntry(output, key);
123: }
124:
125: /**
126: * Returns the format for the given entity and validates it, throwing an
127: * exception if it is invalid for this binding.
128: */
129: private Format getValidFormat(Object entity) {
130:
131: /* A null entity is not allowed. */
132: if (entity == null) {
133: throw new IllegalArgumentException(
134: "An entity may not be null");
135: }
136:
137: /*
138: * Get the format. getFormat throws IllegalArgumentException if the
139: * class is not persistent.
140: */
141: Format format;
142: if (rawAccess) {
143: if (!(entity instanceof RawObject)) {
144: throw new IllegalArgumentException(
145: "Entity must be a RawObject");
146: }
147: format = (Format) ((RawObject) entity).getType();
148: } else {
149: format = catalog.getFormat(entity.getClass());
150: }
151:
152: /* Check that the entity class/subclass is valid for this binding. */
153: if (format.getEntityFormat() != entityFormat) {
154: throw new IllegalArgumentException(
155: "The entity class ("
156: + format.getClassName()
157: + ") must be this entity class or a subclass of it: "
158: + entityFormat.getClassName());
159: }
160:
161: return format;
162: }
163: }
|