• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/db-4.8.30/java/src/com/sleepycat/persist/impl/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9package com.sleepycat.persist.impl;
10
11import java.util.Collection;
12import java.util.Set;
13
14import com.sleepycat.bind.tuple.TupleBase;
15import com.sleepycat.db.DatabaseEntry;
16import com.sleepycat.db.ForeignMultiKeyNullifier;
17import com.sleepycat.db.SecondaryDatabase;
18import com.sleepycat.db.SecondaryKeyCreator;
19import com.sleepycat.db.SecondaryMultiKeyCreator;
20import com.sleepycat.persist.model.EntityMetadata;
21import com.sleepycat.persist.model.Relationship;
22import com.sleepycat.persist.model.SecondaryKeyMetadata;
23import com.sleepycat.persist.raw.RawObject;
24
25/**
26 * A persistence secondary key creator/nullifier.  This class always uses
27 * rawAccess=true to avoid depending on the presence of the proxy class.
28 *
29 * @author Mark Hayes
30 */
31public class PersistKeyCreator implements SecondaryKeyCreator,
32                                          SecondaryMultiKeyCreator,
33                                          ForeignMultiKeyNullifier {
34
35    static boolean isManyType(Class cls) {
36        return cls.isArray() || Collection.class.isAssignableFrom(cls);
37    }
38
39    private final Catalog catalog;
40    private final int priKeyFormatId;
41    private final String keyName;
42    private final Format keyFormat;
43    private final boolean toMany;
44
45    /**
46     * Creates a key creator/nullifier for a given entity class and key name.
47     */
48    public PersistKeyCreator(Catalog catalog,
49                             EntityMetadata entityMeta,
50                             String keyClassName,
51                             SecondaryKeyMetadata secKeyMeta,
52                             boolean rawAccess) {
53        this.catalog = catalog;
54        Format priKeyFormat = PersistEntityBinding.getOrCreateFormat
55            (catalog, entityMeta.getPrimaryKey().getClassName(), rawAccess);
56        priKeyFormatId = priKeyFormat.getId();
57        keyName = secKeyMeta.getKeyName();
58        keyFormat = PersistEntityBinding.getOrCreateFormat
59            (catalog, keyClassName, rawAccess);
60        if (keyFormat == null) {
61            throw new IllegalArgumentException
62                ("Not a key class: " + keyClassName);
63        }
64        if (keyFormat.isPrimitive()) {
65            throw new IllegalArgumentException
66                ("Use a primitive wrapper class instead of class: " +
67                 keyFormat.getClassName());
68        }
69        Relationship rel = secKeyMeta.getRelationship();
70        toMany = (rel == Relationship.ONE_TO_MANY ||
71                  rel == Relationship.MANY_TO_MANY);
72    }
73
74    public boolean createSecondaryKey(SecondaryDatabase secondary,
75				      DatabaseEntry key,
76				      DatabaseEntry data,
77				      DatabaseEntry result) {
78        if (toMany) {
79            throw new IllegalStateException();
80        }
81        KeyLocation loc = moveToKey(key, data);
82        if (loc != null) {
83            RecordOutput output = new RecordOutput
84                (catalog, true /*rawAccess*/);
85            loc.format.copySecKey(loc.input, output);
86            TupleBase.outputToEntry(output, result);
87            return true;
88        } else {
89            /* Key field is not present or null. */
90            return false;
91        }
92    }
93
94    public void createSecondaryKeys(SecondaryDatabase secondary,
95				    DatabaseEntry key,
96				    DatabaseEntry data,
97				    Set results) {
98        if (!toMany) {
99            throw new IllegalStateException();
100        }
101        KeyLocation loc = moveToKey(key, data);
102        if (loc != null) {
103            loc.format.copySecMultiKey(loc.input, keyFormat, results);
104        }
105        /* Else key field is not present or null. */
106    }
107
108    public boolean nullifyForeignKey(SecondaryDatabase secondary,
109                                     DatabaseEntry key,
110                                     DatabaseEntry data,
111                                     DatabaseEntry secKey) {
112        /* Deserialize the entity and get its current class format. */
113        RawObject entity = (RawObject) PersistEntityBinding.readEntity
114            (catalog, key, data, true /*rawAccess*/);
115        Format entityFormat = (Format) entity.getType();
116
117        /*
118         * Set the key to null.  For a TO_MANY key, pass the key object to be
119         * removed from the array/collection.
120         */
121        Object secKeyObject = null;
122        if (toMany) {
123            secKeyObject = PersistKeyBinding.readKey
124                (keyFormat, catalog, secKey.getData(), secKey.getOffset(),
125                 secKey.getSize(), true /*rawAccess*/);
126        }
127        if (entityFormat.nullifySecKey
128            (catalog, entity, keyName, secKeyObject)) {
129
130            /*
131             * Using the current format for the entity, serialize the modified
132             * entity back to the data entry.
133             */
134            PersistEntityBinding.writeEntity
135                (entityFormat, catalog, entity, data, true /*rawAccess*/);
136            return true;
137        } else {
138            /* Key field is not present or null. */
139            return false;
140        }
141    }
142
143    /**
144     * Returns the location from which the secondary key field can be copied.
145     */
146    private KeyLocation moveToKey(DatabaseEntry priKey, DatabaseEntry data) {
147
148        RecordInput input = new RecordInput
149            (catalog, true /*rawAccess*/, priKey, priKeyFormatId,
150             data.getData(), data.getOffset(), data.getSize());
151        int formatId = input.readPackedInt();
152        Format entityFormat = catalog.getFormat(formatId);
153        Format fieldFormat = entityFormat.skipToSecKey(input, keyName);
154        if (fieldFormat != null) {
155            /* Returns null if key field is null. */
156            return input.getKeyLocation(fieldFormat);
157        } else {
158            /* Key field is not present in this class. */
159            return null;
160        }
161    }
162}
163