001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: PersistKeyCreator.java,v 1.16.2.2 2008/01/07 15:14:20 cwl Exp $
007: */
008:
009: package com.sleepycat.persist.impl;
010:
011: import java.util.Collection;
012: import java.util.Set;
013:
014: import com.sleepycat.bind.tuple.TupleBase;
015: import com.sleepycat.je.DatabaseEntry;
016: import com.sleepycat.je.DatabaseException;
017: import com.sleepycat.je.ForeignMultiKeyNullifier;
018: import com.sleepycat.je.SecondaryDatabase;
019: import com.sleepycat.je.SecondaryKeyCreator;
020: import com.sleepycat.je.SecondaryMultiKeyCreator;
021: import com.sleepycat.persist.model.EntityMetadata;
022: import com.sleepycat.persist.model.Relationship;
023: import com.sleepycat.persist.model.SecondaryKeyMetadata;
024: import com.sleepycat.persist.raw.RawObject;
025:
026: /**
027: * A persistence secondary key creator/nullifier. This class always uses
028: * rawAccess=true to avoid depending on the presence of the proxy class.
029: *
030: * @author Mark Hayes
031: */
032: public class PersistKeyCreator implements SecondaryKeyCreator,
033: SecondaryMultiKeyCreator, ForeignMultiKeyNullifier {
034:
035: static boolean isManyType(Class cls) {
036: return cls.isArray() || Collection.class.isAssignableFrom(cls);
037: }
038:
039: private Catalog catalog;
040: private int priKeyFormatId;
041: private String keyName;
042: private Format keyFormat;
043: private boolean toMany;
044:
045: /**
046: * Creates a key creator/nullifier for a given entity class and key name.
047: */
048: public PersistKeyCreator(Catalog catalog,
049: EntityMetadata entityMeta, String keyClassName,
050: SecondaryKeyMetadata secKeyMeta) {
051: this .catalog = catalog;
052: Format priKeyFormat = catalog.getFormat(entityMeta
053: .getPrimaryKey().getClassName());
054: priKeyFormatId = priKeyFormat.getId();
055: keyName = secKeyMeta.getKeyName();
056: keyFormat = catalog.getFormat(keyClassName);
057: if (keyFormat == null) {
058: throw new IllegalArgumentException("Not a key class: "
059: + keyClassName);
060: }
061: if (keyFormat.isPrimitive()) {
062: throw new IllegalArgumentException(
063: "Use a primitive wrapper class instead of class: "
064: + keyFormat.getClassName());
065: }
066: Relationship rel = secKeyMeta.getRelationship();
067: toMany = (rel == Relationship.ONE_TO_MANY || rel == Relationship.MANY_TO_MANY);
068: }
069:
070: public boolean createSecondaryKey(SecondaryDatabase secondary,
071: DatabaseEntry key, DatabaseEntry data, DatabaseEntry result)
072: throws DatabaseException {
073:
074: if (toMany) {
075: throw new IllegalStateException();
076: }
077: KeyLocation loc = moveToKey(key, data);
078: if (loc != null) {
079: RecordOutput output = new RecordOutput(catalog, true /*rawAccess*/);
080: loc.format.copySecKey(loc.input, output);
081: TupleBase.outputToEntry(output, result);
082: return true;
083: } else {
084: /* Key field is not present or null. */
085: return false;
086: }
087: }
088:
089: public void createSecondaryKeys(SecondaryDatabase secondary,
090: DatabaseEntry key, DatabaseEntry data, Set results)
091: throws DatabaseException {
092:
093: if (!toMany) {
094: throw new IllegalStateException();
095: }
096: KeyLocation loc = moveToKey(key, data);
097: if (loc != null) {
098: loc.format.copySecMultiKey(loc.input, keyFormat, results);
099: }
100: /* Else key field is not present or null. */
101: }
102:
103: public boolean nullifyForeignKey(SecondaryDatabase secondary,
104: DatabaseEntry key, DatabaseEntry data, DatabaseEntry secKey)
105: throws DatabaseException {
106:
107: /* Deserialize the entity and get its current class format. */
108: RawObject entity = (RawObject) PersistEntityBinding.readEntity(
109: catalog, key, data, true /*rawAccess*/);
110: Format entityFormat = (Format) entity.getType();
111:
112: /*
113: * Set the key to null. For a TO_MANY key, pass the key object to be
114: * removed from the array/collection.
115: */
116: Object secKeyObject = null;
117: if (toMany) {
118: secKeyObject = PersistKeyBinding.readKey(keyFormat,
119: catalog, secKey.getData(), secKey.getOffset(),
120: secKey.getSize(), true /*rawAccess*/);
121: }
122: if (entityFormat.nullifySecKey(catalog, entity, keyName,
123: secKeyObject)) {
124:
125: /*
126: * Using the current format for the entity, serialize the modified
127: * entity back to the data entry.
128: */
129: PersistEntityBinding.writeEntity(entityFormat, catalog,
130: entity, data, true /*rawAccess*/);
131: return true;
132: } else {
133: /* Key field is not present or null. */
134: return false;
135: }
136: }
137:
138: /**
139: * Returns the location from which the secondary key field can be copied.
140: */
141: private KeyLocation moveToKey(DatabaseEntry priKey,
142: DatabaseEntry data) {
143:
144: RecordInput input = new RecordInput(catalog,
145: true /*rawAccess*/, priKey, priKeyFormatId, data
146: .getData(), data.getOffset(), data.getSize());
147: int formatId = input.readPackedInt();
148: Format entityFormat = catalog.getFormat(formatId);
149: Format fieldFormat = entityFormat.skipToSecKey(input, keyName);
150: if (fieldFormat != null) {
151: /* Returns null if key field is null. */
152: return input.getKeyLocation(fieldFormat);
153: } else {
154: /* Key field is not present in this class. */
155: return null;
156: }
157: }
158: }
|