All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.bimserver.emf.SharedJsonDeserializer Maven / Gradle / Ivy

package org.bimserver.emf;

/******************************************************************************
 * Copyright (C) 2009-2017  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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.bimserver.emf.IdEObjectImpl.State;
import org.bimserver.models.ifc2x3tc1.Ifc2x3tc1Factory;
import org.bimserver.models.ifc2x3tc1.IfcGloballyUniqueId;
import org.bimserver.models.store.IfcHeader;
import org.bimserver.models.store.StoreFactory;
import org.bimserver.models.store.StorePackage;
import org.bimserver.plugins.deserializers.DeserializeException;
import org.bimserver.shared.ListWaitingObject;
import org.bimserver.shared.SingleWaitingObject;
import org.bimserver.shared.WaitingList;
import org.bimserver.shared.exceptions.BimServerClientException;
import org.eclipse.emf.common.util.AbstractEList;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Charsets;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;

import nl.tue.buildingsmart.schema.Attribute;
import nl.tue.buildingsmart.schema.EntityDefinition;
import nl.tue.buildingsmart.schema.InverseAttribute;

public class SharedJsonDeserializer {
	private static final Logger LOGGER = LoggerFactory.getLogger(SharedJsonDeserializer.class);
	private boolean skipInverses;

	public SharedJsonDeserializer(boolean skipInverses) {
		this.skipInverses = skipInverses;
	}

	@SuppressWarnings("rawtypes")
	public IfcModelInterface read(InputStream in, IfcModelInterface model, boolean checkWaitingList) throws DeserializeException {
		if (model.getPackageMetaData().getSchemaDefinition() == null) {
			throw new DeserializeException("No SchemaDefinition available");
		}
		WaitingList waitingList = new WaitingList();
		final boolean log = false;
		if (log) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			try {
				IOUtils.copy(in, baos);
				File file = new File("debug.json");
				System.out.println(file.getAbsolutePath());
				FileUtils.writeByteArrayToFile(file, baos.toByteArray());
			} catch (IOException e) {
				e.printStackTrace();
			}
			in = new ByteArrayInputStream(baos.toByteArray());
		}
		JsonReader jsonReader = new JsonReader(new InputStreamReader(in, Charsets.UTF_8));
		int nrObjects = 0;
		try {
			JsonToken peek = jsonReader.peek();
			if (peek != null && peek == JsonToken.BEGIN_OBJECT) {
				jsonReader.beginObject();
				peek = jsonReader.peek();
				while (peek == JsonToken.NAME) {
					String nextName = jsonReader.nextName();
					if (nextName.equals("objects")) {
						jsonReader.beginArray();
						while (jsonReader.hasNext()) {
							nrObjects++;
							processObject(model, waitingList, jsonReader, null);
						}
						jsonReader.endArray();
					} else if (nextName.equals("header")) {
						IfcHeader ifcHeader = (IfcHeader) processObject(model, waitingList, jsonReader, StorePackage.eINSTANCE.getIfcHeader());
						model.getModelMetaData().setIfcHeader(ifcHeader);
					}
					peek = jsonReader.peek();
				}
				jsonReader.endObject();
			}
		} catch (IOException e) {
			LOGGER.error("", e);
		} catch (IfcModelInterfaceException e) {
			LOGGER.error("", e);
		} finally {
			LOGGER.info("# Objects: " + nrObjects);
			try {
				jsonReader.close();
			} catch (IOException e) {
				LOGGER.error("", e);
			}
		}
		boolean checkUnique = false;
		if (checkUnique) {
			for (IdEObject idEObject : model.getValues()) {
				for (EStructuralFeature eStructuralFeature : idEObject.eClass().getEAllStructuralFeatures()) {
					Object value = idEObject.eGet(eStructuralFeature);
					if (eStructuralFeature instanceof EReference) {
						if (eStructuralFeature.isMany()) {
							List list = (List)value;
							if (eStructuralFeature.isUnique()) {
								Set t = new HashSet<>();
								for (Object v : list) {
									if (t.contains(v)) {
//									LOGGER.error("NOT UNIQUE " + idEObject.eClass().getName() + "." + eStructuralFeature.getName());
									}
									t.add(v);
								}
							}
						}
					}
				}
			}
		}
		if (checkWaitingList && waitingList.size() > 0) {
			try {
				waitingList.dumpIfNotEmpty();
			} catch (BimServerClientException e) {
				e.printStackTrace();
			}
			throw new DeserializeException("Waitinglist should be empty (" + waitingList.size() + ")");
		}
		return model;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private IdEObject processObject(IfcModelInterface model, WaitingList waitingList, JsonReader jsonReader, EClass eClass) throws IOException, DeserializeException, IfcModelInterfaceException {
		IdEObjectImpl object = null;
		jsonReader.beginObject();
		if (jsonReader.nextName().equals("_i")) {
			long oid = jsonReader.nextLong();
			if (jsonReader.nextName().equals("_t")) {
				String type = jsonReader.nextString();
				if (eClass == null) {
					eClass = model.getPackageMetaData().getEClassIncludingDependencies(type);
				}
				if (eClass == null) {
					throw new DeserializeException("No class found with name " + type);
				}
				if (model.containsNoFetch(oid)) {
					object = (IdEObjectImpl) model.getNoFetch(oid);
				} else {
					if (eClass == StorePackage.eINSTANCE.getIfcHeader()) {
						object = (IdEObjectImpl) StoreFactory.eINSTANCE.createIfcHeader();
					} else {
						object = (IdEObjectImpl) model.create(eClass, oid);
					}
				}

				if (jsonReader.nextName().equals("_s")) {
					int state = jsonReader.nextInt();
					if (state == 1) {
						object.setLoadingState(State.LOADED);
						while (jsonReader.hasNext()) {
							String featureName = jsonReader.nextName();
							boolean embedded = false;
							if (featureName.startsWith("_r")) {
								featureName = featureName.substring(2);
							} else if (featureName.startsWith("_e")) {
								embedded = true;
								featureName = featureName.substring(2);
							}
							EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(featureName);
							if (eStructuralFeature == null) {
								throw new DeserializeException("Unknown field (" + featureName + ") on class " + eClass.getName());
							}
							if (eStructuralFeature.isMany()) {
								jsonReader.beginArray();
								if (eStructuralFeature instanceof EAttribute) {
									List list = (List) object.eGet(eStructuralFeature);
									List stringList = null;
									
									if (eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDoubleObject()
											|| eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
										EStructuralFeature asStringFeature = eClass.getEStructuralFeature(eStructuralFeature.getName() + "AsString");
										stringList = (List) object.eGet(asStringFeature);
									}
									
									while (jsonReader.hasNext()) {
										Object e = readPrimitive(jsonReader, eStructuralFeature);
										list.add(e);
										if (eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
											double val = (Double) e;
											stringList.add("" + val); // TODO
											// this
											// is
											// losing
											// precision,
											// maybe
											// also
											// send
											// the
											// string
											// value?
										}
									}
								} else if (eStructuralFeature instanceof EReference) {
									int index = 0;
									AbstractEList list = (AbstractEList) object.eGet(eStructuralFeature);
									while (jsonReader.hasNext()) {
										if (embedded) {
											JsonToken peek = jsonReader.peek();
											if (peek == JsonToken.NUMBER) {
												long refOid = jsonReader.nextLong();
												processRef(model, waitingList, object, eStructuralFeature, index, list, refOid);
											} else {
												jsonReader.beginObject();
												String nextName = jsonReader.nextName();
												if (nextName.equals("_t")) {
													String t = jsonReader.nextString();
													IdEObject wrappedObject = (IdEObject) model.create(model.getPackageMetaData().getEClass(t), -1);
													if (jsonReader.nextName().equals("_v")) {
														EStructuralFeature wv = wrappedObject.eClass().getEStructuralFeature("wrappedValue");
														wrappedObject.eSet(wv, readPrimitive(jsonReader, wv));
														list.add(wrappedObject);
													} else {
														// error
													}
												} else if (nextName.equals("_i")) {
													// Not all are embedded...
													long refOid = jsonReader.nextLong();
													processRef(model, waitingList, object, eStructuralFeature, index, list, refOid);
												}
												jsonReader.endObject();
											}
										} else {
											long refOid = jsonReader.nextLong();
											processRef(model, waitingList, object, eStructuralFeature, index, list, refOid);
										}
										index++;
									}
								}
								jsonReader.endArray();
							} else {
								if (eStructuralFeature instanceof EAttribute) {
									Object x = readPrimitive(jsonReader, eStructuralFeature);
									if (eStructuralFeature.getEType() == EcorePackage.eINSTANCE.getEDouble()) {
										EStructuralFeature asStringFeature = object.eClass().getEStructuralFeature(eStructuralFeature.getName() + "AsString");
										if (asStringFeature != null) {
											object.eSet(asStringFeature, "" + x); // TODO
										}
										// this
										// is
										// losing
										// precision,
										// maybe
										// also
										// send
										// the
										// string
										// value?
									}
									object.eSet(eStructuralFeature, x);
								} else if (eStructuralFeature instanceof EReference) {
									if (eStructuralFeature.getName().equals("GlobalId")) {
										IfcGloballyUniqueId globallyUniqueId = Ifc2x3tc1Factory.eINSTANCE.createIfcGloballyUniqueId();
										globallyUniqueId.setWrappedValue(jsonReader.nextString());
										object.eSet(eStructuralFeature, globallyUniqueId);
									} else if (embedded) {
										jsonReader.beginObject();
										if (jsonReader.nextName().equals("_t")) {
											String t = jsonReader.nextString();
											IdEObject wrappedObject = (IdEObject) model.create(model.getPackageMetaData().getEClassIncludingDependencies(t), -1);
											if (eStructuralFeature.getEAnnotation("dbembed") != null) {
												for (EStructuralFeature eStructuralFeature2 : wrappedObject.eClass().getEAllStructuralFeatures()) {
													String fn = jsonReader.nextName();
													if (fn.equals(eStructuralFeature2.getName())) {
														wrappedObject.eSet(eStructuralFeature2, readPrimitive(jsonReader, eStructuralFeature2));
													} else {
														throw new DeserializeException(fn + " / " + eStructuralFeature2.getName());
													}
												}
												object.eSet(eStructuralFeature, wrappedObject);
											} else {
												if (jsonReader.nextName().equals("_v")) {
													EStructuralFeature wv = wrappedObject.eClass().getEStructuralFeature("wrappedValue");
													wrappedObject.eSet(wv, readPrimitive(jsonReader, wv));
													object.eSet(eStructuralFeature, wrappedObject);
												}
											}
										}
										jsonReader.endObject();
									} else {
										long refOid = jsonReader.nextLong();
										boolean isInverse = false;
										EntityDefinition entityBN = model.getPackageMetaData().getSchemaDefinition().getEntityBN(object.eClass().getName());
										if (entityBN != null) {
											// Some entities like GeometryInfo/Data are not in IFC schema, but valid
											Attribute attributeBN = entityBN.getAttributeBNWithSuper(eStructuralFeature.getName());
											if (attributeBN != null) {
												if (attributeBN instanceof InverseAttribute) {
													isInverse = true;
												}
											}
										}
										if (!isInverse) {
											if (model.contains(refOid)) {
												object.eSet(eStructuralFeature, model.get(refOid));
											} else {
												waitingList.add(refOid, new SingleWaitingObject(-1, object, (EReference) eStructuralFeature));
											}
										}												
									}
								}
							}
						}
					} else {
						// state not_loaded
						object.setLoadingState(State.TO_BE_LOADED);
					}
					if (waitingList.containsKey(oid)) {
						waitingList.updateNode(oid, eClass, object);
					}
					model.add(object.getOid(), object);
				} else {
					LOGGER.info("_s expected");
				}
			} else {
				LOGGER.info("_t expected");
			}
		} else {
			LOGGER.info("_i expected");
		}
		jsonReader.endObject();
		return object;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void processRef(IfcModelInterface model, WaitingList waitingList, IdEObjectImpl object,
			EStructuralFeature eStructuralFeature, int index, AbstractEList list, long refOid)
					throws DeserializeException {
		EntityDefinition entityBN = model.getPackageMetaData().getSchemaDefinition().getEntityBN(object.eClass().getName());
		Attribute attributeBN = entityBN.getAttributeBNWithSuper(eStructuralFeature.getName());
		if (skipInverses && attributeBN instanceof InverseAttribute && ((EReference)eStructuralFeature).getEOpposite() != null) {
			// skip
		} else {
			if (model.contains(refOid)) {
				EObject referencedObject = model.get(refOid);
				if (referencedObject != null) {
					EClass referenceEClass = referencedObject.eClass();
					if (((EClass) eStructuralFeature.getEType()).isSuperTypeOf(referenceEClass)) {
						while (list.size() <= index) {
							list.addUnique(referencedObject);
						}
					} else {
						throw new DeserializeException(-1, referenceEClass.getName() + " cannot be stored in " + eStructuralFeature.getName());
					}
				}
			} else {
				waitingList.add(refOid, new ListWaitingObject(-1, object, (EReference) eStructuralFeature, index));
			}
		}
	}

	private Object readPrimitive(JsonReader jsonReader, EStructuralFeature eStructuralFeature) throws IOException {
		EClassifier eClassifier = eStructuralFeature.getEType();
		if (eClassifier == EcorePackage.eINSTANCE.getEString()) {
			return jsonReader.nextString();
		} else if (eClassifier == EcorePackage.eINSTANCE.getEDouble()) {
			return jsonReader.nextDouble();
		} else if (eClassifier == EcorePackage.eINSTANCE.getEBoolean()) {
			return jsonReader.nextBoolean();
		} else if (eClassifier == EcorePackage.eINSTANCE.getEInt()) {
			return jsonReader.nextInt();
		} else if (eClassifier == EcorePackage.eINSTANCE.getELong()) {
			return jsonReader.nextLong();
		} else if (eClassifier == EcorePackage.eINSTANCE.getEIntegerObject()) {
			return jsonReader.nextInt();
		} else if (eClassifier == EcorePackage.eINSTANCE.getEByteArray()) {
			return Base64.decodeBase64(jsonReader.nextString());
		} else if (eClassifier == EcorePackage.eINSTANCE.getEDate()) {
			long timestamp = jsonReader.nextLong();
			return new Date(timestamp);
		} else if (eClassifier == EcorePackage.eINSTANCE.getEFloat()) {
			return (float)jsonReader.nextDouble();
		} else if (eClassifier == EcorePackage.eINSTANCE.getEEnum()) {
			EEnum eEnum = (EEnum) eStructuralFeature.getEType();
			return eEnum.getEEnumLiteral(jsonReader.nextString()).getInstance();
		} else if (eClassifier instanceof EClass) {
			if (eStructuralFeature.getEType().getName().equals("IfcGloballyUniqueId")) {
				IfcGloballyUniqueId ifcGloballyUniqueId = Ifc2x3tc1Factory.eINSTANCE.createIfcGloballyUniqueId();
				ifcGloballyUniqueId.setWrappedValue(jsonReader.nextString());
				return ifcGloballyUniqueId;
			} else {
				throw new RuntimeException();
			}
		} else if (eClassifier instanceof EEnum) {
			EEnum eEnum = (EEnum) eStructuralFeature.getEType();
			if (jsonReader.peek() == JsonToken.BOOLEAN) {
				return eEnum.getEEnumLiteral(jsonReader.nextBoolean() ? "TRUE" : "FALSE").getInstance();
			} else {
				return eEnum.getEEnumLiteral(jsonReader.nextString()).getInstance();
			}
		} else {
			throw new RuntimeException("Unimplemented type " + eStructuralFeature.getEType().getName());
		}
	}
}