org.bimserver.database.queries.DatabaseReadingStackFrame Maven / Gradle / Ivy
package org.bimserver.database.queries;
/******************************************************************************
* Copyright (C) 2009-2016 BIMserver.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see {@literal }.
*****************************************************************************/
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.Date;
import org.bimserver.BimserverDatabaseException;
import org.bimserver.database.DatabaseSession.GetResult;
import org.bimserver.database.Record;
import org.bimserver.database.SearchingRecordIterator;
import org.bimserver.database.queries.om.CanInclude;
import org.bimserver.database.queries.om.Include;
import org.bimserver.database.queries.om.QueryPart;
import org.bimserver.emf.PackageMetaData;
import org.bimserver.shared.HashMapVirtualObject;
import org.bimserver.shared.HashMapWrappedVirtualObject;
import org.bimserver.shared.QueryContext;
import org.bimserver.shared.QueryException;
import org.bimserver.utils.BinUtils;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.impl.EEnumImpl;
public abstract class DatabaseReadingStackFrame extends StackFrame implements ObjectProvidingStackFrame {
private QueryContext reusable;
private QueryObjectProvider queryObjectProvider;
protected HashMapVirtualObject currentObject;
private QueryPart queryPart;
public DatabaseReadingStackFrame(QueryContext reusable, QueryObjectProvider queryObjectProvider, QueryPart queryPart) {
this.reusable = reusable;
this.queryObjectProvider = queryObjectProvider;
this.queryPart = queryPart;
}
public QueryContext getReusable() {
return reusable;
}
@Override
public HashMapVirtualObject getCurrentObject() {
return currentObject;
}
public QueryObjectProvider getQueryObjectProvider() {
return queryObjectProvider;
}
public PackageMetaData getPackageMetaData() {
return reusable.getPackageMetaData();
}
public QueryPart getQueryPart() {
return queryPart;
}
protected void processPossibleIncludes(EClass previousType, CanInclude canInclude) throws QueryException, BimserverDatabaseException {
if (currentObject != null) {
if (canInclude.hasIncludes()) {
for (Include include : canInclude.getIncludes()) {
processPossibleInclude(canInclude, include);
}
} else if (canInclude.isIncludeAllFields()) {
for (EReference eReference : currentObject.eClass().getEAllReferences()) {
Include include = new Include(reusable.getPackageMetaData());
include.addType(currentObject.eClass(), false);
include.addField(eReference.getName());
processPossibleInclude(canInclude, include);
}
}
if (canInclude instanceof Include) {
processPossibleInclude(null, (Include) canInclude);
}
}
}
protected void processPossibleInclude(CanInclude previousInclude, Include include) throws QueryException, BimserverDatabaseException {
if (include.hasTypes()) {
for (EClass filterClass : include.getTypes()) {
if (!filterClass.isSuperTypeOf(currentObject.eClass())) {
// System.out.println(filterClass.getName() + " / " + currentObject.eClass().getName());
return;
}
}
}
if (include.hasFields()) {
for (EStructuralFeature eStructuralFeature : include.getFields()) {
currentObject.addUseForSerialization(eStructuralFeature);
}
}
getQueryObjectProvider().push(new QueryIncludeStackFrame(getQueryObjectProvider(), getReusable(), previousInclude, include, currentObject, queryPart));
}
public GetResult getMap(EClass originalQueryClass, EClass eClass, ByteBuffer buffer, int keyPid, long keyOid, int keyRid) throws BimserverDatabaseException {
if (keyPid == getReusable().getPid()) {
if (keyRid <= getReusable().getRid() && keyRid >= getReusable().getStopRid()) {
if (!getQueryObjectProvider().hasRead(keyOid)) {
if (buffer.capacity() == 1 && buffer.get(0) == -1) {
buffer.position(buffer.position() + 1);
return GetResult.CONTINUE_WITH_NEXT_OID;
// deleted entity
} else {
currentObject = convertByteArrayToObject(eClass, keyOid, buffer, keyRid);
}
}
return GetResult.CONTINUE_WITH_NEXT_OID;
} else {
return GetResult.CONTINUE_WITH_NEXT_RECORD;
}
} else {
return GetResult.STOP;
}
}
protected HashMapVirtualObject convertByteArrayToObject(EClass eClass, long oid, ByteBuffer buffer, int rid) throws BimserverDatabaseException {
try {
HashMapVirtualObject idEObject = new HashMapVirtualObject(reusable, eClass);
idEObject.setOid(oid);
int unsettedLength = getPackageMetaData().getUnsettedLength(eClass);
byte[] unsetted = new byte[unsettedLength];
buffer.get(unsetted);
int fieldCounter = 0;
for (EStructuralFeature feature : eClass.getEAllStructuralFeatures()) {
try {
if (getPackageMetaData().useForDatabaseStorage(eClass, feature)) {
boolean isUnsetted = (unsetted[fieldCounter / 8] & (1 << (fieldCounter % 8))) != 0;
if (isUnsetted) {
if (feature.isUnsettable()) {
idEObject.eUnset(feature);
} else if (feature.isMany()) {
// do nothing
} else if (feature.getDefaultValue() != null) {
idEObject.setAttribute(feature, feature.getDefaultValue());
}
} else {
Object newValue = null;
if (feature.isMany()) {
newValue = readList(idEObject, buffer, feature);
} else {
if (feature.getEType() instanceof EEnum) {
int enumOrdinal = buffer.getInt();
if (enumOrdinal == -1) {
newValue = null;
} else {
EClassifier eType = feature.getEType();
EEnumLiteral enumLiteral = ((EEnumImpl) eType).getEEnumLiteral(enumOrdinal);
if (enumLiteral != null) {
newValue = enumLiteral.getInstance();
}
}
} else if (feature.getEType() instanceof EClass) {
// EReference eReference = (EReference) feature;
short cid = buffer.getShort();
if (cid == -1) {
// null, do nothing
} else if (cid < 0) {
// negative cid means value is embedded in
// record
EClass referenceClass = queryObjectProvider.getDatabaseSession().getEClass((short) (-cid));
if (feature.getEAnnotation("dbembed") != null) {
newValue = readEmbeddedValue(feature, buffer, referenceClass);
} else {
newValue = readWrappedValue(feature, buffer, referenceClass);
}
} else if (cid > 0) {
// positive cid means value is reference to
// other record
EClass referenceClass = queryObjectProvider.getDatabaseSession().getEClass(cid);
if (referenceClass == null) {
throw new BimserverDatabaseException("No eClass found for cid " + cid);
}
newValue = readReference(buffer, feature, referenceClass);
if ((Long)newValue != -1) {
if (queryObjectProvider.hasReadOrIsGoingToRead(((Long)newValue)) || queryObjectProvider.hasReadOrIsGoingToRead(referenceClass)) {
idEObject.addUseForSerialization(feature);
}
}
// if (eReference.getEOpposite() != null &&
// ((IdEObjectImpl)
// newValue).isLoadedOrLoading()) {
// newValue = null;
// }
}
} else if (feature.getEType() instanceof EDataType) {
newValue = readPrimitiveValue(feature.getEType(), buffer);
}
if (newValue != null) {
idEObject.setAttribute(feature, newValue);
}
}
}
fieldCounter++;
}
} catch (StringIndexOutOfBoundsException e) {
throw new BimserverDatabaseException("Reading " + eClass.getName() + "." + feature.getName(), e);
} catch (BufferUnderflowException e) {
throw new BimserverDatabaseException("Reading " + eClass.getName() + "." + feature.getName(), e);
} catch (BufferOverflowException e) {
throw new BimserverDatabaseException("Reading " + eClass.getName() + "." + feature.getName(), e);
}
}
return idEObject;
} catch (BufferUnderflowException e) {
throw new BimserverDatabaseException("Reading " + eClass.getName(), e);
} catch (BufferOverflowException e) {
throw new BimserverDatabaseException("Reading " + eClass.getName(), e);
}
}
private long readReference(ByteBuffer buffer, EStructuralFeature feature, EClass eClass) throws BimserverDatabaseException {
if (buffer.capacity() == 1 && buffer.get(0) == -1) {
buffer.position(buffer.position() + 1);
return -1;
}
long oid = buffer.getLong();
return oid;
}
private HashMapWrappedVirtualObject readWrappedValue(EStructuralFeature feature, ByteBuffer buffer, EClass eClass) throws BimserverDatabaseException {
EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature("wrappedValue");
Object primitiveValue = readPrimitiveValue(eStructuralFeature.getEType(), buffer);
HashMapWrappedVirtualObject eObject = new HashMapWrappedVirtualObject(reusable, eClass);
eObject.setAttribute(eStructuralFeature, primitiveValue);
if (eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble() || eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDoubleObject()) {
EStructuralFeature strFeature = eClass.getEStructuralFeature("wrappedValueAsString");
Object stringVal = readPrimitiveValue(EcorePackage.eINSTANCE.getEString(), buffer);
eObject.setAttribute(strFeature, stringVal);
}
return eObject;
}
private HashMapWrappedVirtualObject readEmbeddedValue(EStructuralFeature feature, ByteBuffer buffer, EClass eClass) throws BimserverDatabaseException {
HashMapWrappedVirtualObject eObject = new HashMapWrappedVirtualObject(reusable, eClass);
for (EStructuralFeature eStructuralFeature : eClass.getEAllStructuralFeatures()) {
if (eStructuralFeature.isMany()) {
//
} else {
Object primitiveValue = readPrimitiveValue(eStructuralFeature.getEType(), buffer);
eObject.setAttribute(eStructuralFeature, primitiveValue);
}
}
return eObject;
}
public Object readPrimitiveValue(EClassifier classifier, ByteBuffer buffer) {
if (classifier == EcorePackage.eINSTANCE.getEString()) {
int length = buffer.getInt();
if (length != -1) {
return BinUtils.readString(buffer, length);
} else {
return null;
}
} else if (classifier == EcorePackage.eINSTANCE.getEInt() || classifier == EcorePackage.eINSTANCE.getEIntegerObject()) {
return buffer.getInt();
} else if (classifier == EcorePackage.eINSTANCE.getELong() || classifier == EcorePackage.eINSTANCE.getELongObject()) {
return buffer.getLong();
} else if (classifier == EcorePackage.eINSTANCE.getEFloat() || classifier == EcorePackage.eINSTANCE.getEFloatObject()) {
return buffer.getFloat();
} else if (classifier == EcorePackage.eINSTANCE.getEDouble() || classifier == EcorePackage.eINSTANCE.getEDoubleObject()) {
return buffer.getDouble();
} else if (classifier == EcorePackage.eINSTANCE.getEBoolean() || classifier == EcorePackage.eINSTANCE.getEBooleanObject()) {
return buffer.get() == 1;
} else if (classifier == EcorePackage.eINSTANCE.getEDate()) {
long val = buffer.getLong();
if (val == -1L) {
return null;
}
return new Date(val);
} else if (classifier == EcorePackage.eINSTANCE.getEByteArray()) {
int size = buffer.getInt();
byte[] result = new byte[size];
buffer.get(result);
return result;
} else if (classifier.getName().equals("Tristate")) {
int ordinal = buffer.getInt();
EEnum tristateEnum = getPackageMetaData().getEEnum("Tristate");
return tristateEnum.getEEnumLiteral(ordinal).getInstance();
} else if (classifier instanceof EEnum) {
int ordinal = buffer.getInt();
EEnum eEnum = (EEnum) classifier;
return eEnum.getEEnumLiteral(ordinal).getInstance();
} else {
throw new RuntimeException("Unsupported type " + classifier.getName());
}
}
private Object readList(HashMapVirtualObject idEObject, ByteBuffer buffer, EStructuralFeature feature) throws BimserverDatabaseException {
if (feature.getEType() instanceof EEnum) {
} else if (feature.getEType() instanceof EClass) {
if (buffer.capacity() == 1 && buffer.get(0) == -1) {
buffer.position(buffer.position() + 1);
} else {
int listSize = buffer.getInt();
for (int i = 0; i < listSize; i++) {
if (feature.getEAnnotation("twodimensionalarray") != null) {
HashMapVirtualObject newObject = new HashMapVirtualObject(reusable, (EClass) feature.getEType());
Object result = readList(newObject, buffer, newObject.eClass().getEStructuralFeature("List"));
if (result != null) {
newObject.setAttribute(newObject.eClass().getEStructuralFeature("List"), result);
}
idEObject.setListItem(feature, i, newObject);
} else {
short cid = buffer.getShort();
if (cid == -1) {
// null, do nothing
} else if (cid < 0) {
// negative cid means value is
// embedded
// in record
EClass referenceClass = queryObjectProvider.getDatabaseSession().getEClass((short) (-cid));
if (referenceClass == null) {
throw new BimserverDatabaseException("No class found for cid " + (-cid));
}
idEObject.setListItem(feature, i, readWrappedValue(feature, buffer, referenceClass));
} else if (cid > 0) {
// positive cid means value is a
// reference
// to another record
EClass referenceClass = queryObjectProvider.getDatabaseSession().getEClass(cid);
if (referenceClass == null) {
throw new BimserverDatabaseException("Cannot find class with cid " + cid);
}
long rf = readReference(buffer, feature, referenceClass);
idEObject.setListItemReference(feature, i, referenceClass, rf, -1);
if (rf != -1) {
if (queryObjectProvider.hasReadOrIsGoingToRead((rf)) || queryObjectProvider.hasReadOrIsGoingToRead(referenceClass)) {
idEObject.addUseForSerialization(feature, i);
}
}
}
}
}
}
} else if (feature.getEType() instanceof EDataType) {
int listSize = buffer.getInt();
for (int i = 0; i < listSize; i++) {
Object reference = readPrimitiveValue(feature.getEType(), buffer);
if (reference != null) {
idEObject.setListItem(feature, i, reference);
}
}
}
return null;
}
public HashMapVirtualObject getByOid(long oid) throws BimserverDatabaseException {
EClass eClass = getQueryObjectProvider().getDatabaseSession().getEClassForOid(oid);
ByteBuffer mustStartWith = ByteBuffer.wrap(new byte[12]);
mustStartWith.putInt(reusable.getPid());
mustStartWith.putLong(oid);
ByteBuffer startSearchWith = ByteBuffer.wrap(new byte[16]);
startSearchWith.putInt(reusable.getPid());
startSearchWith.putLong(oid);
startSearchWith.putInt(-reusable.getRid());
SearchingRecordIterator recordIterator = getQueryObjectProvider().getDatabaseSession().getKeyValueStore().getRecordIterator(eClass.getEPackage().getName() + "_" + eClass.getName(), mustStartWith.array(),
startSearchWith.array(), getQueryObjectProvider().getDatabaseSession());
try {
Record record = recordIterator.next();
if (record == null) {
return null;
}
getQueryObjectProvider().incReads();
ByteBuffer keyBuffer = ByteBuffer.wrap(record.getKey());
ByteBuffer valueBuffer = ByteBuffer.wrap(record.getValue());
keyBuffer.getInt(); // pid
long keyOid = keyBuffer.getLong();
int keyRid = -keyBuffer.getInt();
if (keyRid <= reusable.getRid()) {
if (valueBuffer.capacity() == 1 && valueBuffer.get(0) == -1) {
valueBuffer.position(valueBuffer.position() + 1);
return null;
// deleted entity
} else {
return convertByteArrayToObject(eClass, keyOid, valueBuffer, keyRid);
}
} else {
return null;
}
} finally {
recordIterator.close();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy