/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved. * */ package com.sleepycat.persist.impl; import com.sleepycat.bind.EntryBinding; import com.sleepycat.bind.tuple.TupleBase; import com.sleepycat.compat.DbCompat; import com.sleepycat.db.DatabaseEntry; /** * A persistence key binding for a given key class. * * @author Mark Hayes */ public class PersistKeyBinding implements EntryBinding { /* See Store.refresh for an explanation of the use of volatile fields. */ volatile Catalog catalog; volatile Format keyFormat; final boolean rawAccess; /** * Creates a key binding for a given key class. */ public PersistKeyBinding(Catalog catalogParam, String clsName, boolean rawAccess) { catalog = catalogParam; try { keyFormat = PersistEntityBinding.getOrCreateFormat (catalog, clsName, rawAccess); } catch (RefreshException e) { /* Must assign catalog field in constructor. */ catalog = e.refresh(); try { keyFormat = PersistEntityBinding.getOrCreateFormat (catalog, clsName, rawAccess); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } if (!keyFormat.isSimple() && !keyFormat.isEnum() && !(keyFormat.getClassMetadata() != null && keyFormat.getClassMetadata().getCompositeKeyFields() != null)) { throw new IllegalArgumentException ("Key class is not a simple type, an enum, or a composite " + "key class (composite keys must include @KeyField " + "annotations): " + clsName); } this.rawAccess = rawAccess; } /** * Creates a key binding dynamically for use by PersistComparator. Formats * are created from scratch rather than using a shared catalog. */ PersistKeyBinding(final Catalog catalog, final Class cls, final String[] compositeFieldOrder) { this.catalog = catalog; keyFormat = new CompositeKeyFormat(catalog, cls, compositeFieldOrder); keyFormat.initializeIfNeeded(catalog, null /*model*/); rawAccess = false; } /** * Binds bytes to an object for use by PersistComparator as well as * entryToObject. */ Object bytesToObject(byte[] bytes, int offset, int length) throws RefreshException { return readKey(keyFormat, catalog, bytes, offset, length, rawAccess); } /** * Binds bytes to an object for use by PersistComparator as well as * entryToObject. */ static Object readKey(Format keyFormat, Catalog catalog, byte[] bytes, int offset, int length, boolean rawAccess) throws RefreshException { EntityInput input = new RecordInput (catalog, rawAccess, null, 0, bytes, offset, length); return input.readKeyObject(keyFormat); } public Object entryToObject(DatabaseEntry entry) { try { return entryToObjectInternal(entry); } catch (RefreshException e) { e.refresh(); try { return entryToObjectInternal(entry); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } } private Object entryToObjectInternal(DatabaseEntry entry) throws RefreshException { return bytesToObject (entry.getData(), entry.getOffset(), entry.getSize()); } public void objectToEntry(Object object, DatabaseEntry entry) { try { objectToEntryInternal(object, entry); } catch (RefreshException e) { e.refresh(); try { objectToEntryInternal(object, entry); } catch (RefreshException e2) { throw DbCompat.unexpectedException(e2); } } } private void objectToEntryInternal(Object object, DatabaseEntry entry) throws RefreshException { RecordOutput output = new RecordOutput(catalog, rawAccess); output.writeKeyObject(object, keyFormat); TupleBase.outputToEntry(output, entry); } /** * See Store.refresh. */ void refresh(final PersistCatalog newCatalog) { catalog = newCatalog; keyFormat = catalog.getFormat(keyFormat.getClassName()); } }