blob: c19afac97c804b7becb106d1f07d8a87273fe1e9 [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.lang.reflect.Array;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sleepycat.compat.DbCompat;
/**
* Implements Accessor for a complex persistent class.
*
* @author Mark Hayes
*/
public class EnhancedAccessor implements Accessor {
private static final Map<String, Enhanced> classRegistry =
Collections.synchronizedMap(new HashMap<String, Enhanced>());
/* Is public for unit tests. */
public static final boolean EXPECT_ENHANCED =
"true".equals(System.getProperty("expectEnhanced"));
private Enhanced prototype;
private Format priKeyFormat;
private Format[] compositeKeyFormats;
private Class type;
/**
* Registers a prototype instance, and should be called during
* initialization of the prototype class. The prototype may be null for
* an abstract class.
*/
public static void registerClass(String className, Enhanced prototype) {
classRegistry.put(className, prototype);
}
/**
* Returns whether a given class is a (registered) enhanced class.
*/
static boolean isEnhanced(Class type) {
boolean enhanced = classRegistry.containsKey(type.getName());
if (!enhanced && EXPECT_ENHANCED) {
throw new IllegalStateException
("Test was run with expectEnhanced=true but class " +
type.getName() + " is not enhanced");
}
return enhanced;
}
private EnhancedAccessor(Class type) {
this.type = type;
prototype = classRegistry.get(type.getName());
assert prototype != null || Modifier.isAbstract(type.getModifiers());
}
/**
* Creates an accessor for a complex type.
*/
EnhancedAccessor(Catalog catalog, Class type, ComplexFormat format) {
this(type);
/*
* Find the primary key format for this format or one of its superclass
* formats.
*/
ComplexFormat declaringFormat = format;
while (declaringFormat != null) {
FieldInfo priKeyField = declaringFormat.getPriKeyFieldInfo();
if (priKeyField != null) {
priKeyFormat = catalog.getFormat(priKeyField.getClassName());
break;
} else {
declaringFormat = declaringFormat.getComplexSuper();
}
}
}
/**
* Creates an accessor for a composite key type.
*/
EnhancedAccessor(Catalog catalog, Class type, List<FieldInfo> fieldInfos) {
this(type);
final int nFields = fieldInfos.size();
compositeKeyFormats = new Format[nFields];
for (int i = 0; i < nFields; i += 1) {
compositeKeyFormats[i] =
catalog.getFormat(fieldInfos.get(i).getClassName());
}
}
public Object newInstance() {
if (prototype == null) {
/* Abstract class -- internal error. */
throw DbCompat.unexpectedState();
}
return prototype.bdbNewInstance();
}
public Object newArray(int len) {
if (prototype == null) {
/* Abstract class -- use reflection for now. */
return Array.newInstance(type, len);
}
return prototype.bdbNewArray(len);
}
public boolean isPriKeyFieldNullOrZero(Object o) {
if (priKeyFormat == null) {
throw DbCompat.unexpectedState
("No primary key: " + o.getClass().getName());
}
return ((Enhanced) o).bdbIsPriKeyFieldNullOrZero();
}
public void writePriKeyField(Object o, EntityOutput output)
throws RefreshException {
if (priKeyFormat == null) {
throw DbCompat.unexpectedState
("No primary key: " + o.getClass().getName());
}
((Enhanced) o).bdbWritePriKeyField(output, priKeyFormat);
}
public void readPriKeyField(Object o, EntityInput input)
throws RefreshException {
if (priKeyFormat == null) {
throw DbCompat.unexpectedState
("No primary key: " + o.getClass().getName());
}
((Enhanced) o).bdbReadPriKeyField(input, priKeyFormat);
}
public void writeSecKeyFields(Object o, EntityOutput output)
throws RefreshException {
((Enhanced) o).bdbWriteSecKeyFields(output);
}
public void readSecKeyFields(Object o,
EntityInput input,
int startField,
int endField,
int superLevel)
throws RefreshException {
((Enhanced) o).bdbReadSecKeyFields
(input, startField, endField, superLevel);
}
public void writeNonKeyFields(Object o, EntityOutput output)
throws RefreshException {
((Enhanced) o).bdbWriteNonKeyFields(output);
}
public void readNonKeyFields(Object o,
EntityInput input,
int startField,
int endField,
int superLevel)
throws RefreshException {
((Enhanced) o).bdbReadNonKeyFields
(input, startField, endField, superLevel);
}
public void writeCompositeKeyFields(Object o, EntityOutput output)
throws RefreshException {
((Enhanced) o).bdbWriteCompositeKeyFields(output, compositeKeyFormats);
}
public void readCompositeKeyFields(Object o, EntityInput input)
throws RefreshException {
((Enhanced) o).bdbReadCompositeKeyFields(input, compositeKeyFormats);
}
public Object getField(Object o,
int field,
int superLevel,
boolean isSecField) {
return ((Enhanced) o).bdbGetField(o, field, superLevel, isSecField);
}
public void setField(Object o,
int field,
int superLevel,
boolean isSecField,
Object value) {
((Enhanced) o).bdbSetField(o, field, superLevel, isSecField, value);
}
public void setPriField(Object o, Object value) {
((Enhanced) o).bdbSetPriField(o, value);
}
}