blob: 5fd718e137f040ae9f5bd39128ce9ddfcc327040 [file] [log] [blame]
/*-
* 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);
}
}
}
}