| /*- |
| * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved. |
| * |
| * This file was distributed by Oracle as part of a version of Oracle Berkeley |
| * DB Java Edition made available at: |
| * |
| * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html |
| * |
| * Please see the LICENSE file included in the top-level directory of the |
| * appropriate version of Oracle Berkeley DB Java Edition for a copy of the |
| * license and additional information. |
| */ |
| |
| package com.sleepycat.persist.impl; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import com.sleepycat.bind.tuple.TupleBase; |
| import com.sleepycat.compat.DbCompat; |
| import com.sleepycat.je.DatabaseEntry; |
| import com.sleepycat.persist.model.Persistent; |
| import com.sleepycat.persist.model.PersistentProxy; |
| import com.sleepycat.persist.raw.RawObject; |
| |
| /** |
| * Proxy for Collection types. |
| * |
| * @author Mark Hayes |
| */ |
| @Persistent |
| abstract class CollectionProxy<E> |
| implements PersistentProxy<Collection<E>> { |
| |
| private E[] elements; |
| |
| protected CollectionProxy() {} |
| |
| public final void initializeProxy(Collection<E> collection) { |
| elements = (E[]) new Object[collection.size()]; |
| int i = 0; |
| for (E element : collection) { |
| elements[i] = element; |
| i += 1; |
| } |
| } |
| |
| public final Collection<E> convertProxy() { |
| Collection<E> collection = newInstance(elements.length); |
| for (E element : elements) { |
| collection.add(element); |
| } |
| return collection; |
| } |
| |
| protected abstract Collection<E> newInstance(int size); |
| |
| @Persistent(proxyFor=ArrayList.class) |
| static class ArrayListProxy<E> extends CollectionProxy<E> { |
| |
| protected ArrayListProxy() {} |
| |
| protected Collection<E> newInstance(int size) { |
| return new ArrayList<E>(size); |
| } |
| } |
| |
| @Persistent(proxyFor=LinkedList.class) |
| static class LinkedListProxy<E> extends CollectionProxy<E> { |
| |
| protected LinkedListProxy() {} |
| |
| protected Collection<E> newInstance(int size) { |
| return new LinkedList<E>(); |
| } |
| } |
| |
| @Persistent(proxyFor=HashSet.class) |
| static class HashSetProxy<E> extends CollectionProxy<E> { |
| |
| protected HashSetProxy() {} |
| |
| protected Collection<E> newInstance(int size) { |
| return new HashSet<E>(size); |
| } |
| } |
| |
| @Persistent(proxyFor=TreeSet.class) |
| static class TreeSetProxy<E> extends CollectionProxy<E> { |
| |
| protected TreeSetProxy() {} |
| |
| protected Collection<E> newInstance(int size) { |
| return new TreeSet<E>(); |
| } |
| } |
| |
| static Object[] getElements(RawObject collection) { |
| Object value = null; |
| while (value == null && collection != null) { |
| Map<String, Object> values = collection.getValues(); |
| if (values != null) { |
| value = values.get("elements"); |
| if (value == null) { |
| collection = collection.getSuper(); |
| } |
| } |
| } |
| if (value == null || !(value instanceof RawObject)) { |
| throw new IllegalStateException |
| ("Collection proxy for a secondary key field must " + |
| "contain a field named 'elements'"); |
| } |
| RawObject rawObj = (RawObject) value; |
| Format format = (Format) rawObj.getType(); |
| if (!format.isArray() || |
| format.getComponentType().getId() != Format.ID_OBJECT) { |
| throw new IllegalStateException |
| ("Collection proxy 'elements' field must be an Object array"); |
| } |
| return rawObj.getElements(); |
| } |
| |
| static void setElements(RawObject collection, Object[] elements) { |
| RawObject value = null; |
| while (value == null && collection != null) { |
| Map<String, Object> values = collection.getValues(); |
| if (values != null) { |
| value = (RawObject) values.get("elements"); |
| if (value != null) { |
| values.put("elements", |
| new RawObject(value.getType(), elements)); |
| } else { |
| collection = collection.getSuper(); |
| } |
| } |
| } |
| if (value == null) { |
| throw DbCompat.unexpectedState(); |
| } |
| } |
| |
| static void copyElements(RecordInput input, |
| Format format, |
| Format keyFormat, |
| Set results) |
| throws RefreshException { |
| |
| /* |
| * This could be optimized by traversing the byte format of the |
| * collection's elements array. |
| */ |
| RawObject collection = (RawObject) format.newInstance(input, true); |
| collection = (RawObject) format.readObject(collection, input, true); |
| Object[] elements = getElements(collection); |
| if (elements != null) { |
| for (Object elem : elements) { |
| RecordOutput output = |
| new RecordOutput(input.getCatalog(), true); |
| output.writeKeyObject(elem, keyFormat); |
| DatabaseEntry entry = new DatabaseEntry(); |
| TupleBase.outputToEntry(output, entry); |
| results.add(entry); |
| } |
| } |
| } |
| } |