org.bimserver.ifc.step.deserializer.IfcStepStreamingDeserializer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ifcplugins Show documentation
Show all versions of ifcplugins Show documentation
BIMserver plugin that provides IFC serializers/deserializers
The newest version!
package org.bimserver.ifc.step.deserializer;
/******************************************************************************
* Copyright (C) 2009-2019 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.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.bimserver.BimserverDatabaseException;
import org.bimserver.CannotStoreReferenceInFieldException;
import org.bimserver.database.MetricCollector;
import org.bimserver.emf.IdEObjectImpl;
import org.bimserver.emf.MetaDataException;
import org.bimserver.emf.PackageMetaData;
import org.bimserver.emf.Schema;
import org.bimserver.models.ifc4.Ifc4Package;
import org.bimserver.models.store.IfcHeader;
import org.bimserver.models.store.StoreFactory;
import org.bimserver.plugins.deserializers.ByteProgressReporter;
import org.bimserver.plugins.deserializers.DatabaseInterface;
import org.bimserver.plugins.deserializers.DeserializeException;
import org.bimserver.plugins.deserializers.DeserializerErrorCode;
import org.bimserver.plugins.deserializers.StreamingDeserializer;
import org.bimserver.shared.ByteBufferList;
import org.bimserver.shared.ByteBufferVirtualObject;
import org.bimserver.shared.ByteBufferWrappedVirtualObject;
import org.bimserver.shared.Guid;
import org.bimserver.shared.GuidCompressor;
import org.bimserver.shared.InvalidGuidException;
import org.bimserver.shared.ListCapableVirtualObject;
import org.bimserver.shared.ListWaitingVirtualObject;
import org.bimserver.shared.PrimitiveByteBufferList;
import org.bimserver.shared.QueryContext;
import org.bimserver.shared.SingleWaitingVirtualObject;
import org.bimserver.shared.TwoDimensionalListWaitingVirtualObject;
import org.bimserver.shared.VirtualObject;
import org.bimserver.shared.WaitingListVirtualObject;
import org.bimserver.shared.WrappedVirtualObject;
import org.bimserver.utils.FakeClosingInputStream;
import org.bimserver.utils.StringUtils;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
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.EClassImpl;
import org.eclipse.emf.ecore.impl.EEnumImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Charsets;
import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap;
import nl.tue.buildingsmart.schema.Attribute;
import nl.tue.buildingsmart.schema.EntityDefinition;
import nl.tue.buildingsmart.schema.ExplicitAttribute;
public abstract class IfcStepStreamingDeserializer implements StreamingDeserializer {
private static final Logger LOGGER = LoggerFactory.getLogger(IfcStepStreamingDeserializer.class);
private ByteProgressReporter byteProgressReporter;
private PackageMetaData packageMetaData;
private static final String WRAPPED_VALUE = "wrappedValue";
private WaitingListVirtualObject waitingList;
private Mode mode = Mode.HEADER;
private long lineNumber;
private Schema schema;
// ExpressID -> ObjectID
private Map mappedObjects;
private QueryContext reusable;
private IfcHeader ifcHeader;
private static MetricCollector metricCollector = new MetricCollector();
// This is enabled for now so we can test more models, not decided yet whether this will be enabled in the final release
private static final boolean CONVERT_INVALID_IFC_GUIDS = true;
// Use String instead of EClass, compare takes 1.7%
private final Map summaryMap = new TreeMap<>();
private int numberOfEntitiesRead;
@Override
public void init(PackageMetaData packageMetaData) {
this.packageMetaData = packageMetaData;
this.schema = packageMetaData.getSchema();
}
@Override
public Map getSummaryMap() {
Map newMap = new TreeMap<>(new Comparator(){
@Override
public int compare(EClass o1, EClass o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (String key : this.summaryMap.keySet()) {
EClass eClass = packageMetaData.getEClass(key);
newMap.put(eClass, this.summaryMap.get(key).get());
}
return newMap;
}
@Override
public void setProgressReporter(ByteProgressReporter byteProgressReporter) {
this.byteProgressReporter = byteProgressReporter;
}
public enum Mode {
HEADER, DATA, FOOTER, DONE
}
public PackageMetaData getPackageMetaData() {
return packageMetaData;
}
@Override
public long read(InputStream in, String filename, long fileSize, QueryContext reusable) throws DeserializeException {
this.reusable = reusable;
mappedObjects = new Long2LongOpenHashMap();
waitingList = new WaitingListVirtualObject();
mode = Mode.HEADER;
if (filename != null && (filename.toUpperCase().endsWith(".ZIP") || filename.toUpperCase().endsWith(".IFCZIP"))) {
ZipInputStream zipInputStream = new ZipInputStream(in);
try {
ZipEntry nextEntry = zipInputStream.getNextEntry();
if (nextEntry == null) {
throw new DeserializeException(DeserializerErrorCode.IFCZIP_CONTAINS_NO_IFC_FILES, "Zip files must contain exactly one IFC-file, this zip-file looks empty");
}
if (nextEntry.getName().toUpperCase().endsWith(".IFC")) {
FakeClosingInputStream fakeClosingInputStream = new FakeClosingInputStream(zipInputStream);
long size = read(fakeClosingInputStream, fileSize);
if (size == 0) {
throw new DeserializeException(DeserializerErrorCode.IFCZIP_CONTAINS_EMPTY_IFC_MODEL, "Uploaded file does not seem to be a correct IFC file");
}
if (zipInputStream.getNextEntry() != null) {
throw new DeserializeException(DeserializerErrorCode.IFCZIP_FILE_CONTAINS_TOO_MANY_FILES, "Zip files may only contain one IFC-file, this zip-file contains more files");
}
return numberOfEntitiesRead;
} else {
throw new DeserializeException(DeserializerErrorCode.IFCZIP_MUST_CONTAIN_EXACTLY_ONE_IFC_FILE, "Zip files must contain exactly one IFC-file, this zip-file seems to have one or more non-IFC files");
}
} catch (IOException e) {
throw new DeserializeException(e);
}
} else {
read(in, fileSize);
return numberOfEntitiesRead;
}
}
private long read(InputStream inputStream, long fileSize) throws DeserializeException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charsets.UTF_8));
long bytesRead = 0;
lineNumber = 0;
try {
String line = reader.readLine();
if (line == null) {
throw new DeserializeException(DeserializerErrorCode.UNEXPECTED_END_OF_STREAM_WHILE_READING_FIRST_LINE, 0, "Unexpected end of stream reading first line");
}
MessageDigest md = MessageDigest.getInstance("MD5");
while (line != null) {
byte[] bytes = line.getBytes(Charsets.UTF_8);
md.update(bytes, 0, bytes.length);
try {
while (!processLine(line.trim())) {
String readLine = reader.readLine();
if (readLine == null) {
break;
}
line += readLine;
lineNumber++;
}
} catch (Exception e) {
if (e instanceof DeserializeException) {
throw (DeserializeException)e;
} else {
throw new DeserializeException(DeserializerErrorCode.UNKNOWN_DESERIALIZER_ERROR, lineNumber, " (" + e.getMessage() + ") " + line, e);
}
}
bytesRead += bytes.length;
if (byteProgressReporter != null) {
byteProgressReporter.progress(bytesRead);
}
line = reader.readLine();
lineNumber++;
}
// model.getModelMetaData().setChecksum(md.digest());
if (mode == Mode.HEADER) {
throw new DeserializeException(DeserializerErrorCode.NO_VALID_IFC_HEADER_FOUND, lineNumber, "No valid IFC header found");
}
return lineNumber;
} catch (IOException e) {
throw new DeserializeException(DeserializerErrorCode.IO_EXCEPTION, lineNumber, e);
} catch (NoSuchAlgorithmException e) {
throw new DeserializeException(DeserializerErrorCode.INTERNAL_BIMSERVER_ERROR, lineNumber, e);
}
}
private boolean processLine(String line) throws DeserializeException, MetaDataException, BimserverDatabaseException {
switch (mode) {
case HEADER:
if (line.length() > 0) {
if (line.endsWith(";")) {
processHeader(line);
} else {
return false;
}
}
if (line.equals("DATA;")) {
mode = Mode.DATA;
}
break;
case DATA:
if (line.equals("ENDSEC;")) {
mode = Mode.FOOTER;
waitingList.dumpIfNotEmpty();
} else {
if (line.length() > 0 && line.charAt(0) == '#') {
while (line.endsWith("*/")) {
line = line.substring(0, line.lastIndexOf("/*")).trim();
}
if (line.endsWith(";")) {
processRecord(line);
} else {
return false;
}
}
}
break;
case FOOTER:
if (line.equals("ENDSEC;")) {
mode = Mode.DONE;
}
break;
case DONE:
}
return true;
}
public IfcHeader getIfcHeader() {
return ifcHeader;
}
private void processHeader(String line) throws DeserializeException {
if (ifcHeader == null) {
ifcHeader = StoreFactory.eINSTANCE.createIfcHeader();
}
((IdEObjectImpl)ifcHeader).setUuid(UUID.randomUUID());
if (line.startsWith("/*")) {
if (line.contains("*/")) {
line = line.substring(line.indexOf("*/") + 2);
}
}
if (line.startsWith("FILE_DESCRIPTION")) {
String filedescription = line.substring("FILE_DESCRIPTION".length()).trim();
new IfcHeaderParser().parseDescription(filedescription.substring(1, filedescription.length() - 2), ifcHeader, lineNumber);
} else if (line.startsWith("FILE_NAME")) {
String filename = line.substring("FILE_NAME".length()).trim();
new IfcHeaderParser().parseFileName(filename.substring(1, filename.length() - 2), ifcHeader, lineNumber);
} else if (line.startsWith("FILE_SCHEMA")) {
String fileschema = line.substring("FILE_SCHEMA".length()).trim();
new IfcHeaderParser().parseFileSchema(fileschema.substring(1, fileschema.length() - 2), ifcHeader, lineNumber);
String ifcSchemaVersion = ifcHeader.getIfcSchemaVersion();
if (!ifcSchemaVersion.toLowerCase().equalsIgnoreCase(schema.getHeaderName().toLowerCase())) {
throw new DeserializeException(DeserializerErrorCode.IFC_SCHEMA_NOT_SUPPORTED_BY_DESERIALIZER, lineNumber, ifcSchemaVersion + " is not supported by this deserializer (" + schema.getHeaderName() + " is)");
}
ifcHeader.setIfcSchemaVersion(ifcSchemaVersion);
} else if (line.startsWith("ENDSEC;")) {
// Do nothing
}
}
private VirtualObject newVirtualObject(EClass eClass, int lineLength) {
return new ByteBufferVirtualObject(reusable, eClass, metricCollector.estimateRequiredBytes(lineLength));
}
private ByteBufferWrappedVirtualObject newWrappedVirtualObject(EClass eClass) {
return new ByteBufferWrappedVirtualObject(reusable, eClass);
}
public void processRecord(String line) throws DeserializeException, MetaDataException, BimserverDatabaseException {
int equalSignLocation = line.indexOf("=");
int lastIndexOfSemiColon = line.lastIndexOf(";");
if (lastIndexOfSemiColon == -1) {
throw new DeserializeException(DeserializerErrorCode.NO_SEMICOLON_FOUND_IN_RECORD, lineNumber, "No semicolon found in line");
}
int indexOfFirstParen = line.indexOf("(", equalSignLocation);
if (indexOfFirstParen == -1) {
throw new DeserializeException(DeserializerErrorCode.NO_LEFT_PARENTHESIS_FOUND_IN_RECORD, lineNumber, "No left parenthesis found in line");
}
int indexOfLastParen = line.lastIndexOf(")", lastIndexOfSemiColon);
if (indexOfLastParen == -1) {
throw new DeserializeException(DeserializerErrorCode.NO_RIGHT_PARENTHESIS_FOUND_IN_RECORD, lineNumber, "No right parenthesis found in line");
}
this.numberOfEntitiesRead++;
long recordNumber = Long.parseLong(line.substring(1, equalSignLocation).trim());
String name = line.substring(equalSignLocation + 1, indexOfFirstParen).trim();
EClass eClass = (EClass) getPackageMetaData().getEClassifierCaseInsensitive(name);
if (eClass == null) {
throw new DeserializeException(DeserializerErrorCode.UNKNOWN_ENTITY, lineNumber, name + " is not a known entity");
}
VirtualObject object = newVirtualObject(eClass, line.length());
AtomicInteger atomicInteger = summaryMap.get(eClass.getName());
if (atomicInteger == null) {
summaryMap.put(eClass.getName(), new AtomicInteger(1));
} else {
atomicInteger.incrementAndGet();
}
mappedObjects.put(recordNumber, object.getOid());
boolean openReferences = false;
if (eClass != null) {
String realData = line.substring(indexOfFirstParen + 1, indexOfLastParen);
int lastIndex = 0;
EntityDefinition entityBN = getPackageMetaData().getSchemaDefinition().getEntityBN(name);
if (entityBN == null) {
throw new DeserializeException(DeserializerErrorCode.UNKNOWN_ENTITY, lineNumber, "Unknown entity " + name);
}
for (EStructuralFeature eStructuralFeature : eClass.getEAllStructuralFeatures()) {
if (getPackageMetaData().useForSerialization(eClass, eStructuralFeature)) {
if (getPackageMetaData().useForDatabaseStorage(eClass, eStructuralFeature)) {
int nextIndex = StringUtils.nextString(realData, lastIndex);
if (nextIndex <= lastIndex && eStructuralFeature == Ifc4Package.eINSTANCE.getIfcSurfaceStyleShading_Transparency()) {
// IFC4 add1/add2 hack
object.set(eStructuralFeature.getName(), 0D);
object.set(eStructuralFeature.getEContainingClass().getEStructuralFeature(eStructuralFeature.getName() + "AsString").getName(), "0");
continue;
}
String val = null;
try {
val = realData.substring(lastIndex, nextIndex - 1).trim();
} catch (Exception e) {
int expected = 0;
for (Attribute attribute2 : entityBN.getAttributesCached(true)) {
if (attribute2 instanceof ExplicitAttribute) {
expected++;
}
}
throw new DeserializeException(DeserializerErrorCode.NOT_ENOUGH_FIELDS_FOR_ENTITY, lineNumber, eClass.getName() + " expects " + expected + " fields, but less found (" + e.getMessage() + ")", e);
}
lastIndex = nextIndex;
if (val.length() == 0) {
throw new DeserializeException(DeserializerErrorCode.EXPECTED_CHARACTER_BUT_EMPTY_FIELD, lineNumber, "Expected non-comma character, but field value length is 0");
}
char firstChar = val.charAt(0);
if (firstChar == '$') {
object.eUnset(eStructuralFeature);
if (eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
EStructuralFeature doubleStringFeature = eClass.getEStructuralFeature(eStructuralFeature.getName() + "AsString");
object.eUnset(doubleStringFeature);
}
} else if (firstChar == '#') {
if (!readReference(val, object, eStructuralFeature)) {
openReferences = true;
}
} else if (firstChar == '.') {
readEnum(val, object, (EAttribute) eStructuralFeature);
} else if (firstChar == '(') {
if (!readList(val, (ListCapableVirtualObject) object, eStructuralFeature, object, -1)) {
openReferences = true;
}
} else if (firstChar == '*') {
object.eUnset(eStructuralFeature);
} else {
if (!eStructuralFeature.isMany()) {
Object converted = convert(eStructuralFeature, eStructuralFeature.getEType(), val);
if (eStructuralFeature.getName().equals("GlobalId")) {
processGuid(object, eStructuralFeature, converted);
} else {
if (eStructuralFeature instanceof EAttribute) {
object.setAttribute((EAttribute) eStructuralFeature, converted);
} else {
object.setReference((EReference) eStructuralFeature, (WrappedVirtualObject)converted);
}
}
if (eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
EStructuralFeature doubleStringFeature = eClass.getEStructuralFeature(eStructuralFeature.getName() + "AsString");
object.setAttribute((EAttribute) doubleStringFeature, val);
}
} else {
// It's not a list in the file, but it is in the
// schema??
}
}
} else {
int nextIndex = StringUtils.nextString(realData, lastIndex);
lastIndex = nextIndex;
}
} else {
if (getPackageMetaData().useForDatabaseStorage(eClass, eStructuralFeature)) {
if (eStructuralFeature instanceof EReference && getPackageMetaData().isInverse((EReference) eStructuralFeature)) {
object.eUnset(eStructuralFeature);
} else {
if (eStructuralFeature.getEAnnotation("asstring") == null) {
object.eUnset(eStructuralFeature);
}
}
}
}
}
// Other objects waiting for me?
if (waitingList.containsKey(recordNumber)) {
waitingList.updateNode(recordNumber, eClass, object);
}
if (!openReferences) {
int nrBytes = getDatabaseInterface().save(object);
metricCollector.collect(line.length(), nrBytes);
}
}
}
private void processGuid(VirtualObject object, EStructuralFeature eStructuralFeature, Object converted) throws BimserverDatabaseException, DeserializeException {
try {
GuidCompressor.getGuidFromCompressedString(converted.toString(), new Guid());
object.setAttribute((EAttribute) eStructuralFeature, converted);
// If it's valid, we do nothing, we just store it as it was
} catch (InvalidGuidException e) {
if (CONVERT_INVALID_IFC_GUIDS) {
// The GUID is invalid according to the IFC spec, sometimes another representation is used in IFC files, which is a valid GUID, but not according to the IFC spec
// The next bit of code tries this variant, it remains to be decided what will be the final implementation for this in deserializer
try {
UUID uuid = UUID.fromString(converted.toString());
String ifcGuid = GuidCompressor.compressGuidString(uuid.toString());
LOGGER.warn("Invalid GUID on line " + lineNumber + " , converted from default UUID format (" + uuid.toString() + ") to IFC format (" + ifcGuid + ")");
// If this succeeds, we convert the UUID to the IFC format, and store that, so this "changes" the model
object.setAttribute((EAttribute) eStructuralFeature, ifcGuid);
} catch (Exception e2) {
// We use the original exception's message, since that is most accurate
throw new DeserializeException(DeserializerErrorCode.INVALID_GUID, lineNumber, "Invalid GUID: \"" + converted.toString() + "\": " + e.getMessage());
}
} else {
throw new DeserializeException(DeserializerErrorCode.INVALID_GUID, lineNumber, "Invalid GUID: \"" + converted.toString() + "\": " + e.getMessage());
}
}
}
private DatabaseInterface getDatabaseInterface() {
return reusable.getDatabaseInterface();
}
private boolean readList(String val, ListCapableVirtualObject object, EStructuralFeature structuralFeature, VirtualObject parentObject, int parentIndex) throws DeserializeException, MetaDataException, BimserverDatabaseException {
int index = 0;
if (!structuralFeature.isMany()) {
throw new DeserializeException(DeserializerErrorCode.UNEXPECTED_AGGREGATION, lineNumber, "Field " + structuralFeature.getName() + " of " + (parentObject == null ? structuralFeature.getEContainingClass().getName() : parentObject.eClass().getName()) + " is no aggregation");
}
boolean isDouble = structuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble();
EStructuralFeature doubleStringFeature = null;
if (isDouble) {
doubleStringFeature = structuralFeature.getEContainingClass().getEStructuralFeature(structuralFeature.getName() + "AsString");
if (doubleStringFeature == null) {
throw new DeserializeException(DeserializerErrorCode.INTERNAL_BIMSERVER_ERROR, lineNumber, "Field not found: " + structuralFeature.getName() + "AsString");
}
}
String realData = val.substring(1, val.length() - 1);
int lastIndex = 0;
object.startList(structuralFeature);
// TODO not always instantiate
List doubles = new ArrayList<>();
boolean complete = true;
while (lastIndex != realData.length() + 1) {
int nextIndex = StringUtils.nextString(realData, lastIndex);
String stringValue = realData.substring(lastIndex, nextIndex - 1).trim();
lastIndex = nextIndex;
if (stringValue.length() > 0) {
if (stringValue.charAt(0) == '#') {
Long referenceId = Long.parseLong(stringValue.substring(1));
if (mappedObjects.containsKey(referenceId)) {
Long referencedOid = mappedObjects.get(referenceId);
if (referencedOid != null) {
EClass referenceEClass = getDatabaseInterface().getEClassForOid(referencedOid);
if (((EClass) structuralFeature.getEType()).isSuperTypeOf(referenceEClass)) {
// TODO unique checking?
object.setListItemReference(structuralFeature, index, referenceEClass, referencedOid, -1);
} else {
throw new DeserializeException(DeserializerErrorCode.REFERENCED_OBJECT_CANNOT_BE_STORED_IN_THIS_FIELD, lineNumber, referenceEClass.getName() + " cannot be stored in " + structuralFeature.getName());
}
}
} else {
int pos = object.reserveSpaceForListReference();
if (object instanceof VirtualObject) {
waitingList.add(referenceId, new ListWaitingVirtualObject(lineNumber, (VirtualObject) object, structuralFeature, index, pos));
} else if (object instanceof ByteBufferList) {
if (parentObject == null) {
throw new DeserializeException(DeserializerErrorCode.INTERNAL_BIMSERVER_ERROR, lineNumber, "Need a parentObject");
}
waitingList.add(referenceId, new TwoDimensionalListWaitingVirtualObject(lineNumber, parentObject, (ByteBufferList) object, structuralFeature, parentIndex, index, pos));
}
complete = false;
}
} else if (stringValue.charAt(0) == '(') {
// Two dimensional list
if (structuralFeature.getEType() instanceof EClass) {
ByteBufferList newObject = new ByteBufferList(reusable, (EClass) structuralFeature.getEType());
if (!readList(stringValue, newObject, newObject.eClass().getEStructuralFeature("List"), parentObject, index)) {
complete = false;
}
object.setListItem(structuralFeature, index, newObject);
} else {
PrimitiveByteBufferList newObject = new PrimitiveByteBufferList(reusable, (EDataType) structuralFeature.getEType());
readList(stringValue, newObject, structuralFeature, parentObject, index);
object.setListItem(structuralFeature, index, newObject);
}
} else {
Object convert = convert(structuralFeature, structuralFeature.getEType(), stringValue);
if (convert != null) {
object.setListItem(structuralFeature, index, convert);
if (isDouble) {
doubles.add(stringValue);
}
}
}
}
index++;
}
object.endList();
// TODO make more efficient
if (isDouble) {
object.startList(doubleStringFeature);
int i=0;
for (String d : doubles) {
object.setListItem(doubleStringFeature, i++, d);
}
object.endList();
}
return complete;
}
private Object convert(EStructuralFeature eStructuralFeature, EClassifier classifier, String value) throws DeserializeException, MetaDataException, BimserverDatabaseException {
if (classifier != null) {
if (classifier instanceof EClassImpl) {
if (null != ((EClassImpl) classifier).getEStructuralFeature(WRAPPED_VALUE)) {
EAttribute wrappedFeature = (EAttribute) ((EClass) classifier).getEStructuralFeature(WRAPPED_VALUE);
if (wrappedFeature.isMany()) {
ByteBufferList object = new ByteBufferList(reusable, (EClass) classifier);
readList(value, object, wrappedFeature, null, -1);
return object;
} else {
ByteBufferWrappedVirtualObject newObject = newWrappedVirtualObject((EClass) classifier);
Class> instanceClass = wrappedFeature.getEType().getInstanceClass();
if (value.equals("")) {
} else {
if (instanceClass == Integer.class || instanceClass == int.class) {
try {
newObject.setAttribute(wrappedFeature, Integer.parseInt(value));
} catch (NumberFormatException e) {
throw new DeserializeException(DeserializerErrorCode.INVALID_INTEGER_LITERAL, lineNumber, value + " is not a valid integer value");
}
} else if (instanceClass == Long.class || instanceClass == long.class) {
newObject.setAttribute(wrappedFeature, Long.parseLong(value));
} else if (instanceClass == Boolean.class || instanceClass == boolean.class) {
newObject.setAttribute(wrappedFeature, value.equals(".T."));
} else if (instanceClass == Double.class || instanceClass == double.class) {
try {
newObject.setAttribute(wrappedFeature, Double.parseDouble(value));
} catch (NumberFormatException e) {
throw new DeserializeException(DeserializerErrorCode.INVALID_DOUBLE_LITERAL, lineNumber, value + " is not a valid double floating point number");
}
newObject.setAttribute((EAttribute) newObject.eClass().getEStructuralFeature(WRAPPED_VALUE + "AsString"), value);
} else if (instanceClass == String.class) {
newObject.setAttribute(wrappedFeature, IfcParserWriterUtils.readString(value, lineNumber));
} else if (instanceClass.getSimpleName().equals("Tristate")) {
Object tristate = null;
if (value.equals(".T.")) {
tristate = getPackageMetaData().getEEnumLiteral("Tristate", "TRUE");
} else if (value.equals(".F.")) {
tristate = getPackageMetaData().getEEnumLiteral("Tristate", "FALSE");
} else if (value.equals(".U.")) {
tristate = getPackageMetaData().getEEnumLiteral("Tristate", "UNDEFINED");
}
newObject.setAttribute(wrappedFeature, tristate);
} else if (instanceClass.isEnum()) {
String realEnumValue = value.substring(1, value.length() - 1);
EStructuralFeature feature = wrappedFeature;
EEnumLiteral enumValue = (((EEnumImpl) feature.getEType()).getEEnumLiteral(realEnumValue));
if (enumValue == null) {
throw new DeserializeException(DeserializerErrorCode.NON_EXISTING_ENUM_LITERAL_USED, lineNumber, "Enum type " + feature.getEType().getName() + " has no literal value '" + realEnumValue + "'");
}
newObject.setAttribute(wrappedFeature, enumValue);
} else {
throw new DeserializeException(DeserializerErrorCode.UNIMPLEMENTED_BIMSERVER_FEATURE, lineNumber, "Not implemented: " + instanceClass);
}
}
return newObject;
}
} else {
return processInline(eStructuralFeature, value);
}
} else if (classifier instanceof EDataType) {
return IfcParserWriterUtils.convertSimpleValue(getPackageMetaData(), eStructuralFeature, classifier.getInstanceClass(), value, lineNumber);
}
}
return null;
}
private Object processInline(EStructuralFeature eStructuralFeature, String value) throws DeserializeException, MetaDataException, BimserverDatabaseException {
if (value.indexOf("(") != -1) {
String typeName = value.substring(0, value.indexOf("(")).trim();
String v = value.substring(value.indexOf("(") + 1, value.length() - 1);
EClassifier eClassifier = getPackageMetaData().getEClassifierCaseInsensitive(typeName);
if (eClassifier instanceof EClass) {
return convert(eStructuralFeature, eClassifier, v);
} else {
throw new DeserializeException(DeserializerErrorCode.UNKNOWN_ENTITY, lineNumber, typeName + " is not an existing IFC entity");
}
} else {
return IfcParserWriterUtils.convertSimpleValue(getPackageMetaData(), eStructuralFeature, eStructuralFeature.getEType().getInstanceClass(), value, lineNumber);
}
}
private void readEnum(String val, VirtualObject object, EAttribute structuralFeature) throws DeserializeException, MetaDataException, BimserverDatabaseException {
if (val.equals(".T.")) {
if (structuralFeature.getEType().getName().equals("Tristate")) {
object.setAttribute(structuralFeature, getPackageMetaData().getEEnumLiteral("Tristate", "TRUE").getInstance());
} else if (structuralFeature.getEType().getName().equals("IfcBoolean")) {
EClass eClass = getPackageMetaData().getEClass("IfcBoolean");
VirtualObject createIfcBoolean = newVirtualObject(eClass, val.length());
createIfcBoolean.setAttribute((EAttribute) eClass.getEStructuralFeature("WrappedValue"), getPackageMetaData().getEEnumLiteral("Tristate", "TRUE").getInstance());
object.setAttribute(structuralFeature, createIfcBoolean);
} else if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean()) {
object.setAttribute(structuralFeature, true);
} else {
EClass eClass = getPackageMetaData().getEClass("IfcLogical");
VirtualObject createIfcBoolean = newVirtualObject(eClass, val.length());
createIfcBoolean.setAttribute((EAttribute) eClass.getEStructuralFeature("WrappedValue"), getPackageMetaData().getEEnumLiteral("Tristate", "TRUE").getInstance());
object.setAttribute(structuralFeature, createIfcBoolean);
}
} else if (val.equals(".F.")) {
if (structuralFeature.getEType().getName().equals("Tristate")) {
object.setAttribute(structuralFeature, getPackageMetaData().getEEnumLiteral("Tristate", "FALSE").getInstance());
} else if (structuralFeature.getEType().getName().equals("IfcBoolean")) {
EClass eClass = getPackageMetaData().getEClass("IfcBoolean");
VirtualObject createIfcBoolean = newVirtualObject(eClass, val.length());
createIfcBoolean.setAttribute((EAttribute) eClass.getEStructuralFeature("WrappedValue"), getPackageMetaData().getEEnumLiteral("Tristate", "FALSE").getInstance());
object.setAttribute(structuralFeature, createIfcBoolean);
} else if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean()) {
object.setAttribute(structuralFeature, false);
} else {
EClass eClass = getPackageMetaData().getEClass("IfcLogical");
VirtualObject createIfcBoolean = newVirtualObject(eClass, val.length());
createIfcBoolean.setAttribute((EAttribute) eClass.getEStructuralFeature("WrappedValue"), getPackageMetaData().getEEnumLiteral("Tristate", "FALSE").getInstance());
object.setAttribute(structuralFeature, createIfcBoolean);
}
} else if (val.equals(".U.")) {
if (structuralFeature.getEType().getName().equals("Tristate")) {
object.setAttribute(structuralFeature, getPackageMetaData().getEEnumLiteral("Tristate", "UNDEFINED").getInstance());
} else if (structuralFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean()) {
object.eUnset(structuralFeature);
} else {
EClass eClass = getPackageMetaData().getEClass("IfcLogical");
VirtualObject createIfcBoolean = newVirtualObject(eClass, val.length());
createIfcBoolean.setAttribute((EAttribute) eClass.getEStructuralFeature("WrappedValue"), getPackageMetaData().getEEnumLiteral("Tristate", "UNDEFINED").getInstance());
object.setAttribute(structuralFeature, createIfcBoolean);
}
} else {
if (structuralFeature.getEType() instanceof EEnumImpl) {
String realEnumValue = val.substring(1, val.length() - 1);
EEnumLiteral enumValue = (((EEnumImpl) structuralFeature.getEType()).getEEnumLiteral(realEnumValue));
if (enumValue == null) {
// Another IFC4/add1/add2 hack
if (structuralFeature.getEType() == Ifc4Package.eINSTANCE.getIfcExternalSpatialElementTypeEnum() && realEnumValue.equals("NOTDEFIEND")) {
realEnumValue = "NOTDEFINED";
enumValue = (((EEnumImpl) structuralFeature.getEType()).getEEnumLiteral(realEnumValue));
}
}
if (enumValue == null) {
throw new DeserializeException(DeserializerErrorCode.NON_EXISTING_ENUM_LITERAL_USED, lineNumber, "Enum type " + structuralFeature.getEType().getName() + " has no literal value '" + realEnumValue + "'");
}
object.setAttribute(structuralFeature, enumValue.getInstance());
} else {
throw new DeserializeException(DeserializerErrorCode.UNEXPECTED_ENUM, lineNumber, "Value " + val + " indicates enum type but " + structuralFeature.getEType().getName() + " expected");
}
}
}
private boolean readReference(String val, VirtualObject object, EStructuralFeature structuralFeature) throws DeserializeException, BimserverDatabaseException {
if (structuralFeature == Ifc4Package.eINSTANCE.getIfcIndexedColourMap_Opacity()) {
// HACK for IFC4/add1/add2
object.setAttribute((EAttribute) structuralFeature, 0D);
object.setAttribute((EAttribute) structuralFeature.getEContainingClass().getEStructuralFeature(structuralFeature.getName() + "AsString"), "0");
return true;
}
try {
long referenceId = Long.parseLong(val.substring(1));
if (mappedObjects.containsKey(referenceId)) {
try {
object.setReference((EReference) structuralFeature, mappedObjects.get(referenceId), -1);
} catch (CannotStoreReferenceInFieldException e) {
throw new DeserializeException(e.getDeserializerErrorCode(), lineNumber, e.getMessage());
}
return true;
} else {
int pos = object.reserveSpaceForReference(structuralFeature);
waitingList.add(referenceId, new SingleWaitingVirtualObject(lineNumber, object, structuralFeature, pos));
return false;
}
} catch (NumberFormatException e) {
throw new DeserializeException(DeserializerErrorCode.INVALID_REFERENCE, lineNumber, "'" + val + "' is not a valid reference");
}
}
}