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

org.bimserver.client.ClientIfcModel Maven / Gradle / Ivy

Go to download

A client library for BIMserver, can communicate via JSON, SOAP and ProtocolBuffers

There is a newer version: 2.0.0
Show newest version
package org.bimserver.client;

/******************************************************************************
 * 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.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bimserver.database.queries.om.Include;
import org.bimserver.database.queries.om.Include.TypeDef;
import org.bimserver.database.queries.om.JsonQueryObjectModelConverter;
import org.bimserver.database.queries.om.Query;
import org.bimserver.database.queries.om.QueryException;
import org.bimserver.database.queries.om.QueryPart;
import org.bimserver.emf.IdEObject;
import org.bimserver.emf.IdEObjectImpl;
import org.bimserver.emf.IdEObjectImpl.State;
import org.bimserver.emf.IfcModelInterfaceException;
import org.bimserver.emf.ModelMetaData;
import org.bimserver.emf.OidProvider;
import org.bimserver.emf.PackageMetaData;
import org.bimserver.emf.SharedJsonDeserializer;
import org.bimserver.ifc.IfcModel;
import org.bimserver.ifc.IfcModelChangeListener;
import org.bimserver.interfaces.objects.SDeserializerPluginConfiguration;
import org.bimserver.models.geometry.Bounds;
import org.bimserver.models.geometry.Buffer;
import org.bimserver.models.geometry.GeometryData;
import org.bimserver.models.geometry.GeometryFactory;
import org.bimserver.models.geometry.GeometryInfo;
import org.bimserver.models.geometry.GeometryPackage;
import org.bimserver.plugins.HeaderTakingSerializer;
import org.bimserver.plugins.ObjectAlreadyExistsException;
import org.bimserver.plugins.PluginConfiguration;
import org.bimserver.plugins.deserializers.DeserializeException;
import org.bimserver.plugins.serializers.ProjectInfo;
import org.bimserver.plugins.serializers.Serializer;
import org.bimserver.plugins.serializers.SerializerException;
import org.bimserver.plugins.serializers.SerializerInputstream;
import org.bimserver.shared.PluginClassLoaderProvider;
import org.bimserver.shared.exceptions.PublicInterfaceNotFoundException;
import org.bimserver.shared.exceptions.ServerException;
import org.bimserver.shared.exceptions.ServiceException;
import org.bimserver.shared.exceptions.UserException;
import org.bimserver.shared.interfaces.LowLevelInterface;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class ClientIfcModel extends IfcModel {
	public enum ModelState {
		NONE, LOADING, FULLY_LOADED
	}

	private static final Logger LOGGER = LoggerFactory.getLogger(ClientIfcModel.class);
	private BimServerClient bimServerClient;
	private ModelState modelState = ModelState.NONE;
	private long tid = -1;
	private long roid;
	private final Set loadedClasses = new HashSet();
	private int cachedObjectCount = -1;
	private boolean recordChanges;
	private boolean includeGeometry;

	private ClientDebugInfo clientDebugInfo = new ClientDebugInfo();

	public ClientIfcModel(BimServerClient bimServerClient, long poid, long roid, boolean deep, PackageMetaData packageMetaData, boolean recordChanges, boolean includeGeometry)
			throws ServerException, UserException, PublicInterfaceNotFoundException {
		super(packageMetaData, null);
		this.recordChanges = recordChanges;
		this.bimServerClient = bimServerClient;
		this.roid = roid;
		this.includeGeometry = includeGeometry;
		if (recordChanges) {
			try {
				tid = bimServerClient.getLowLevelInterface().startTransaction(poid);
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		if (deep) {
			try {
				loadDeep();
			} catch (QueryException e) {
				LOGGER.error("", e);
			}
		}
		pluginClassLoaderProvider = new PluginClassLoaderProvider() {
			@Override
			public ClassLoader getClassLoaderFor(String pluginName) {
				return ClientIfcModel.class.getClassLoader();
			}
		};
	}

	@Override
	public ModelMetaData getModelMetaData() {
		if (this.modelMetaData == null) {
			this.modelMetaData = new ModelMetaData();
			try {
				this.modelMetaData.setMinBounds(getBimServerClient().getServiceInterface().getModelMinBounds(roid));
				this.modelMetaData.setMaxBounds(getBimServerClient().getServiceInterface().getModelMaxBounds(roid));
			} catch (ServerException e1) {
				e1.printStackTrace();
			} catch (UserException e1) {
				e1.printStackTrace();
			} catch (PublicInterfaceNotFoundException e1) {
				e1.printStackTrace();
			}

			Query query = new Query(getPackageMetaData());

			JsonQueryObjectModelConverter converter = new JsonQueryObjectModelConverter(getPackageMetaData());
			try {
				long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), converter.toJson(query).toString(), bimServerClient.getJsonSerializerOid(), false);
				bimServerClient.waitForDonePreparing(topicId);
				processDownload(topicId);
				bimServerClient.getServiceInterface().cleanupLongAction(topicId);
			} catch (ServerException e) {
				e.printStackTrace();
			} catch (UserException e) {
				e.printStackTrace();
			} catch (PublicInterfaceNotFoundException e) {
				e.printStackTrace();
			} catch (IfcModelInterfaceException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return this.modelMetaData;
	}

	private ClientIfcModel(BimServerClient bimServerClient, PackageMetaData packageMetaData, long poid, boolean recordChanges) {
		super(packageMetaData, null);
		this.bimServerClient = bimServerClient;
		this.recordChanges = recordChanges;
		if (recordChanges) {
			try {
				tid = bimServerClient.getLowLevelInterface().startTransaction(poid);
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
	}

	private EContentAdapter adapter = new EContentAdapter() {
		public void notifyChanged(Notification notification) {
			super.notifyChanged(notification);
			IdEObject idEObject = (IdEObject) notification.getNotifier();
			EStructuralFeature eFeature = (EStructuralFeature) notification.getFeature();
			if (notification.getEventType() == Notification.ADD) {
				if (getModelState() != ModelState.LOADING) {
					try {
						if (eFeature.getEType() == EcorePackage.eINSTANCE.getEString()) {
							bimServerClient.getLowLevelInterface().addStringAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), notification.getNewStringValue());
						} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getELong() || eFeature.getEType() == EcorePackage.eINSTANCE.getELongObject()) {
							throw new UnsupportedOperationException();
						} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEDouble() || eFeature.getEType() == EcorePackage.eINSTANCE.getEDoubleObject()) {
							bimServerClient.getLowLevelInterface().addDoubleAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Double) notification.getNewValue());
						} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean() || eFeature.getEType() == EcorePackage.eINSTANCE.getEBooleanObject()) {
							bimServerClient.getLowLevelInterface().addBooleanAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), notification.getNewBooleanValue());
						} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEInt() || eFeature.getEType() == EcorePackage.eINSTANCE.getEIntegerObject()) {
							bimServerClient.getLowLevelInterface().addIntegerAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), notification.getNewIntValue());
						} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEByteArray()) {
							throw new UnsupportedOperationException();
						} else if (eFeature.getEType() instanceof EEnum) {
							throw new UnsupportedOperationException();
						} else if (eFeature instanceof EReference) {
							if (notification.getNewValue() == null) {
							} else {
								bimServerClient.getLowLevelInterface().addReference(getTransactionId(), idEObject.getOid(), eFeature.getName(), ((IdEObject) notification.getNewValue()).getOid());
							}
						} else {
							throw new RuntimeException("Unimplemented " + eFeature.getEType().getName() + " " + notification.getNewValue());
						}
					} catch (ServiceException e) {
						LOGGER.error("", e);
					} catch (PublicInterfaceNotFoundException e) {
						LOGGER.error("", e);
					}
				}
			} else if (notification.getEventType() == Notification.REMOVE) {
				if (getModelState() != ModelState.LOADING) {
					try {
						if (eFeature instanceof EReference) {
							IdEObject oldValue = (IdEObject) notification.getOldValue();
							bimServerClient.getLowLevelInterface().removeReferenceByOid(getTransactionId(), idEObject.getOid(), eFeature.getName(), oldValue.getOid());
						} else {
							throw new RuntimeException("Unimplemented " + eFeature.getEType().getName() + " " + notification.getNewValue());
						}
					} catch (ServiceException e) {
						LOGGER.error("", e);
					} catch (PublicInterfaceNotFoundException e) {
						LOGGER.error("", e);
					}
				}
			}
		}
	};
	private boolean assumeCompletePreload;
	private PluginClassLoaderProvider pluginClassLoaderProvider;

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public ClientIfcModel branch(long poid, boolean recordChanges) {
		// TODO this should of course be done server side, without any copying
		ClientIfcModel branch = new ClientIfcModel(bimServerClient, getPackageMetaData(), poid, recordChanges);
		try {
			loadDeep();
		} catch (ServerException e) {
			LOGGER.error("", e);
		} catch (UserException e) {
			LOGGER.error("", e);
		} catch (PublicInterfaceNotFoundException e) {
			LOGGER.error("", e);
		} catch (QueryException e) {
			LOGGER.error("", e);
		}
		Map map = new HashMap();
		for (IdEObject sourceObject : getValues()) {
			try {
				IdEObjectImpl targetObject = branch.create(sourceObject.eClass());
				targetObject.setLoadingState(State.LOADED);
				map.put(sourceObject, targetObject);
			} catch (IfcModelInterfaceException e) {
				LOGGER.error("", e);
			}
		}
		for (IdEObject sourceObject : getObjects().values()) {
			IdEObject targetObject = map.get(sourceObject);
			for (EStructuralFeature eStructuralFeature : sourceObject.eClass().getEAllStructuralFeatures()) {
				Object sourceValue = sourceObject.eGet(eStructuralFeature);
				if (eStructuralFeature instanceof EReference) {
					if (eStructuralFeature.isMany()) {
						List sourceList = (List) sourceValue;
						List targetList = (List) targetObject.eGet(eStructuralFeature);
						for (Object sourceItem : sourceList) {
							IdEObject e = map.get(sourceItem);
							if (e != null) {
								targetList.add(e);
							}
						}
					} else {
						targetObject.eSet(eStructuralFeature, map.get(sourceValue));
					}
				} else {
					if (eStructuralFeature.isMany()) {
						List sourceList = (List) sourceValue;
						List targetList = (List) targetObject.eGet(eStructuralFeature);
						for (Object sourceItem : sourceList) {
							targetList.add(sourceItem);
						}
					} else {
						targetObject.eSet(eStructuralFeature, sourceValue);
					}
				}
			}
		}
		branch.setModelState(ModelState.FULLY_LOADED);
		return branch;
	}

	private void setModelState(ModelState modelState) {
		this.modelState = modelState;
	}

	public BimServerClient getBimServerClient() {
		return bimServerClient;
	}

	public long commit(String comment) throws ServerException, UserException, PublicInterfaceNotFoundException {
		if (tid == -1) {
			throw new UserException("No transaction was started");
		}
		return bimServerClient.getLowLevelInterface().commitTransaction(tid, comment);
	}

	private void loadDeep() throws ServerException, UserException, PublicInterfaceNotFoundException, QueryException {
		long start = System.nanoTime();
		if (modelState != ModelState.FULLY_LOADED && modelState != ModelState.LOADING) {
			modelState = ModelState.LOADING;
			Query query = new Query("test", getPackageMetaData());
			QueryPart queryPart = query.createQueryPart();
			queryPart.setIncludeAllFields(true);

			ObjectNode queryNode = new JsonQueryObjectModelConverter(query.getPackageMetaData()).toJson(query);
			Long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), queryNode.toString(), bimServerClient.getJsonSerializerOid(), false);
			bimServerClient.waitForDonePreparing(topicId);
			try {
				processDownload(topicId);
				bimServerClient.getServiceInterface().cleanupLongAction(topicId);
				modelState = ModelState.FULLY_LOADED;
				buildIndex();
				loadGeometry();
			} catch (IfcModelInterfaceException | IOException e) {
				LOGGER.error("", e);
			} catch (QueryException e) {
				LOGGER.error("", e);
			} catch (GeometryException e) {
				LOGGER.error("", e);
			}
		}
		long end = System.nanoTime();
//		LOGGER.info((((end - start) / 1000000) + " ms"));
	}

	private void loadGeometry() throws QueryException, ServerException, UserException, PublicInterfaceNotFoundException, IOException, GeometryException, IfcModelInterfaceException {
		if (includeGeometry) {
			Query query = new Query("test", getPackageMetaData());
			ObjectNode settings = new ObjectMapper().createObjectNode();
			query.setGeometrySettings(settings);
			query.getGeometrySettings().put("useSmallInts", false);
			query.getGeometrySettings().put("splitGeometry", false);
			QueryPart queryPart = query.createQueryPart();

			Map geometryInfoOidToOid = new HashMap<>();

			EClass ifcProductClass = getPackageMetaData().getEClass("IfcProduct");
			EStructuralFeature geometryFeature = ifcProductClass.getEStructuralFeature("geometry");
			List allWithSubTypes = new ArrayList<>(super.getAllWithSubTypes(ifcProductClass));
			for (IdEObject ifcProduct : allWithSubTypes) {
				GeometryInfo geometry = (GeometryInfo) ifcProduct.eGet(geometryFeature);
				if (geometry != null) {
					if (geometry.getData() == null || geometry.getData().getIndices() == null) {
						queryPart.addOid(geometry.getOid());
						geometryInfoOidToOid.put(geometry.getOid(), ifcProduct.getOid());
					}
				}
			}

			if (queryPart.getOids() == null) {
				return;
			}
			LOGGER.info("Loading geometry for " + queryPart.getOids().size() + " objects");
			EClass geometryInfoClass = getPackageMetaData().getEClassIncludingDependencies("GeometryInfo");
			Include include = queryPart.createInclude();
			include.addType(geometryInfoClass, false);
			include.addField("data");
			Include geometryData = include.createInclude();
			geometryData.addType(getPackageMetaData().getEClassIncludingDependencies("GeometryData"), false);
			geometryData.addFieldDirect("indices");
			geometryData.addFieldDirect("normals");
			geometryData.addFieldDirect("vertices");
			geometryData.addFieldDirect("colorsQuantized");

			long serializerOid = bimServerClient.getBinaryGeometryMessagingStreamingSerializerOid();

			long topicId = bimServerClient.query(query, roid, serializerOid);
			// TODO use websocket notifications
			bimServerClient.waitForDonePreparing(topicId);
			InputStream inputStream = bimServerClient.getDownloadData(topicId);
			clientDebugInfo.incrementGeometryGetDownloadData();
			try {
				processGeometryInputStream(inputStream, geometryInfoOidToOid);
			} catch (Throwable e) {
				e.printStackTrace();
			} finally {
				bimServerClient.getServiceInterface().cleanupLongAction(topicId);
			}
		}
	}

	public ClientDebugInfo getClientDebugInfo() {
		return clientDebugInfo;
	}

	private void processGeometryInputStream(InputStream inputStream, Map geometryInfoOidToOid) throws IOException, GeometryException, IfcModelInterfaceException {
		int t = 0;
		CountingLittleEndianDataInputStream dataInputStream = new CountingLittleEndianDataInputStream(inputStream);
		try {
			boolean done = false;
			while (true) {
				byte geometryType = dataInputStream.readByte();
				if (geometryType == 0) {
					String protocol = dataInputStream.readUTF();
					if (!protocol.equals("BGS")) {
						throw new GeometryException("Protocol != BGS (" + protocol + ")");
					}
					byte formatVersion = dataInputStream.readByte();
					if (formatVersion != 17) {
						throw new GeometryException("Unsupported version " + formatVersion + " / 17");
					}

					float multiplierToMm = dataInputStream.readFloat();
					dataInputStream.align8();
					for (int i = 0; i < 6; i++) {
						dataInputStream.readDouble();
					}
				} else if (geometryType == 5) {
					long oid = dataInputStream.readLong();
					String type = dataInputStream.readUTF();
					dataInputStream.align8();
					long roid = dataInputStream.readLong(); // roid
					long geometryInfoOid = dataInputStream.readLong();
					boolean hasTransparency = dataInputStream.readLong() == 1; // transparent
					GeometryInfo geometryInfo = (GeometryInfo) get(geometryInfoOid);
					if (geometryInfo == null) {
						geometryInfo = create(GeometryInfo.class);
					}
					((IdEObjectImpl) geometryInfo).setOid(geometryInfoOid);
					((IdEObjectImpl) geometryInfo).setLoadingState(State.LOADING);
					add(geometryInfoOid, geometryInfo);

					Long ifcProductOid = geometryInfoOidToOid.get(geometryInfoOid);
					if (ifcProductOid == null) {
						throw new GeometryException("Missing geometry info id: " + geometryInfoOid);
					}
					IdEObject ifcProduct = get(ifcProductOid);

					EStructuralFeature geometryFeature = getPackageMetaData().getEClass("IfcProduct").getEStructuralFeature("geometry");
					ifcProduct.eSet(geometryFeature, geometryInfo);

					org.bimserver.models.geometry.Vector3f minBounds = GeometryFactory.eINSTANCE.createVector3f();
					minBounds.setX(dataInputStream.readDouble());
					minBounds.setY(dataInputStream.readDouble());
					minBounds.setZ(dataInputStream.readDouble());

					org.bimserver.models.geometry.Vector3f maxBounds = GeometryFactory.eINSTANCE.createVector3f();
					maxBounds.setX(dataInputStream.readDouble());
					maxBounds.setY(dataInputStream.readDouble());
					maxBounds.setZ(dataInputStream.readDouble());

					Bounds bounds = GeometryFactory.eINSTANCE.createBounds();

					bounds.setMin(minBounds);
					bounds.setMax(maxBounds);

					geometryInfo.setBounds(bounds);

					byte[] transformation = new byte[16 * 8];
					dataInputStream.readFully(transformation);
					geometryInfo.setTransformation(transformation);

					long geometryDataOid = dataInputStream.readLong();
					GeometryData geometryData = (GeometryData) get(geometryDataOid);
					if (geometryData == null) {
						geometryData = GeometryFactory.eINSTANCE.createGeometryData();
						add(geometryDataOid, geometryData);
					}
					geometryInfo.setData(geometryData);
					((IdEObjectImpl) geometryData).setLoadingState(State.LOADED);
				} else if (geometryType == 3) {
					throw new GeometryException("Parts not supported");
				} else if (geometryType == 1) {
					int reused = dataInputStream.readInt();
					String type = dataInputStream.readUTF();
					dataInputStream.align8();
					long roid = dataInputStream.readLong();
					long croid = dataInputStream.readLong();
					boolean hasTransparency = dataInputStream.readLong() == 1; // transparent
					long geometryDataOid = dataInputStream.readLong();

					GeometryData geometryData = (GeometryData) get(geometryDataOid);
					if (geometryData == null) {
						geometryData = GeometryFactory.eINSTANCE.createGeometryData();
						add(geometryDataOid, geometryData);
					}
					((IdEObjectImpl) geometryData).setOid(geometryDataOid);
					((IdEObjectImpl) geometryData).setLoadingState(State.LOADING);

					int nrIndices = dataInputStream.readInt();
					byte[] indices = new byte[nrIndices * 4];
					dataInputStream.readFully(indices);
					Buffer buffer = GeometryFactory.eINSTANCE.createBuffer();
					buffer.setData(indices);
					geometryData.setIndices(buffer);

					int colorType = dataInputStream.readInt();
					if (colorType == 1) {
						dataInputStream.readFloat();
						dataInputStream.readFloat();
						dataInputStream.readFloat();
						dataInputStream.readFloat();
					}

					int nrVertices = dataInputStream.readInt();
					byte[] vertices = new byte[nrVertices * 4];
					dataInputStream.readFully(vertices);
					Buffer verticesBuffer = GeometryFactory.eINSTANCE.createBuffer();
					verticesBuffer.setData(vertices);
					geometryData.setVertices(verticesBuffer);

					int nrNormals = dataInputStream.readInt();
					byte[] normals = new byte[nrNormals * 4];
					dataInputStream.readFully(normals);
					Buffer normalsBuffer = GeometryFactory.eINSTANCE.createBuffer();
					normalsBuffer.setData(normals);
					geometryData.setNormals(normalsBuffer);

					int nrMaterials = dataInputStream.readInt();
					byte[] materials = new byte[nrMaterials * 4];
					dataInputStream.readFully(materials);
					Buffer colorsBuffer = GeometryFactory.eINSTANCE.createBuffer();
					colorsBuffer.setData(materials);
					geometryData.setColorsQuantized(colorsBuffer);
					((IdEObjectImpl) geometryData).setLoadingState(State.LOADED);
				} else if (geometryType == 6) {
					done = true;
				} else {
					throw new GeometryException("Unimplemented geometryType: " + geometryType);
				}
				t++;
				dataInputStream.align8();
			}
		} catch (EOFException e) {
		} catch (IOException e) {
			System.out.println("T: " + t);
			e.printStackTrace();
		} catch (ObjectAlreadyExistsException e) {
			e.printStackTrace();
		} finally {
			dataInputStream.close();
			this.clientDebugInfo.incBytesOverTheLine(dataInputStream.getPos());
		}
	}

	private void processDownload(Long topicId) throws UserException, ServerException, PublicInterfaceNotFoundException, IfcModelInterfaceException, IOException {
		InputStream inputStream = bimServerClient.getDownloadData(topicId);
		if (inputStream == null) {
			throw new IfcModelInterfaceException("No InputStream to read from for topicId " + topicId);
		}
		InputStream downloadData = new org.bimserver.utils.CountingInputStream(inputStream) {
			public void close() throws IOException {
				ClientIfcModel.this.clientDebugInfo.incBytesOverTheLine(getCount());
				super.close();
			}
		};
		try {
			new SharedJsonDeserializer(false).read(downloadData, this, false);
		} catch (DeserializeException e) {
			throw new IfcModelInterfaceException(e);
		} catch (Exception e) {
			throw new IfcModelInterfaceException(e);
		} finally {
			if (downloadData != null) {
				downloadData.close();
			}
		}
	}

	@Override
	public  List getAll(EClass eClass) {
		if (!loadedClasses.contains(eClass.getName()) && modelState != ModelState.FULLY_LOADED && !assumeCompletePreload) {
			try {
				modelState = ModelState.LOADING;

				Query query = new Query(getPackageMetaData());
				QueryPart queryPart = query.createQueryPart();
				queryPart.addType(eClass, false);
				if (includeGeometry && getPackageMetaData().getEClass("IfcProduct").isSuperTypeOf(eClass)) {
					Include include = queryPart.createInclude();
					include.addType(eClass, false);
					include.addField("geometry");
					Include include2 = include.createInclude();
					include2.addType(new TypeDef(GeometryPackage.eINSTANCE.getGeometryInfo(), false));
					include2.addField("data");
				}

				JsonQueryObjectModelConverter converter = new JsonQueryObjectModelConverter(getPackageMetaData());
				long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), converter.toJson(query).toString(), bimServerClient.getJsonSerializerOid(), false);

				bimServerClient.waitForDonePreparing(topicId);

				clientDebugInfo.incrementGetAll();

				processDownload(topicId);
				bimServerClient.getServiceInterface().cleanupLongAction(topicId);

				loadedClasses.add(eClass.getName());
				rebuildIndexPerClass(eClass);
				modelState = ModelState.NONE;
				
				try {
					loadGeometry();
				} catch (ServerException e) {
					e.printStackTrace();
				} catch (UserException e) {
					e.printStackTrace();
				} catch (PublicInterfaceNotFoundException e) {
					e.printStackTrace();
				} catch (QueryException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				} catch (GeometryException e) {
					e.printStackTrace();
				} catch (IfcModelInterfaceException e) {
					e.printStackTrace();
				}
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		List result = super.getAll(eClass);
		return result;
	}

	@Override
	public Set getGuids(EClass eClass) {
		getAllWithSubTypes(eClass);
		return super.getGuids(eClass);
	}

	@Override
	public Set getNames(EClass eClass) {
		getAllWithSubTypes(eClass);
		return super.getNames(eClass);
	}

	@Override
	public IdEObject getByName(EClass eClass, String name) {
		// TODO
		return super.getByName(eClass, name);
	}

	@Override
	public long size() {
		if (cachedObjectCount == -1) {
			try {
				cachedObjectCount = bimServerClient.getLowLevelInterface().count(roid, "[ALL]");
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return cachedObjectCount;
	}

	@Override
	public Set keySet() {
		try {
			loadDeep();
		} catch (Exception e) {
			LOGGER.error("", e);
		}
		return super.keySet();
	}

	@Override
	public IdEObject get(long oid) {
		IdEObject idEObject = super.get(oid);
		if (idEObject == null) {
			loadExplicit(oid);
			return super.get(oid);
		}
		return idEObject;
	}

	public void loadExplicit(long oid) {
		try {
			IdEObjectImpl idEObjectImpl = (IdEObjectImpl) super.get(oid);
			if (idEObjectImpl != null && !idEObjectImpl.isLoadedOrLoading() && !assumeCompletePreload) {
				idEObjectImpl.setLoadingState(State.LOADING);
				modelState = ModelState.LOADING;

				Query query = new Query(getPackageMetaData());
				QueryPart queryPart = query.createQueryPart();
				queryPart.addOid(oid);

				JsonQueryObjectModelConverter converter = new JsonQueryObjectModelConverter(getPackageMetaData());

				long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), converter.toJson(query).toString(), bimServerClient.getJsonSerializerOid(), false);
				bimServerClient.waitForDonePreparing(topicId);
				clientDebugInfo.incExplicit();
				processDownload(topicId);
				bimServerClient.getServiceInterface().cleanupLongAction(topicId);
				idEObjectImpl.setLoadingState(State.LOADED);
				modelState = ModelState.NONE;
			}
		} catch (Exception e) {
			LOGGER.error("", e);
		}
	}

	public IdEObject getNoFetch(long oid) {
		return super.get(oid);
	}

	@Override
	public Collection getValues() {
		try {
			loadDeep();
		} catch (Exception e) {
			LOGGER.error("", e);
		}
		return super.getValues();
	}

	@Override
	public  List getAllWithSubTypes(EClass eClass) {
		if (!loadedClasses.contains(eClass.getName()) && modelState != ModelState.FULLY_LOADED && !assumeCompletePreload) {
			try {
				modelState = ModelState.LOADING;

				Query query = new Query(getPackageMetaData());
				QueryPart queryPart = query.createQueryPart();
				queryPart.addType(eClass, true);

				if (includeGeometry && getPackageMetaData().getEClass("IfcProduct").isSuperTypeOf(eClass)) {
					Include include = queryPart.createInclude();
					include.addType(eClass, true);
					include.addField("geometry");
					Include include2 = include.createInclude();
					include2.addType(new TypeDef(GeometryPackage.eINSTANCE.getGeometryInfo(), false));
					include2.addField("data");
				}

				JsonQueryObjectModelConverter converter = new JsonQueryObjectModelConverter(getPackageMetaData());
				long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), converter.toJson(query).toString(), bimServerClient.getJsonSerializerOid(), false);

				bimServerClient.waitForDonePreparing(topicId);
				processDownload(topicId);
				clientDebugInfo.incrementGetAll();
				bimServerClient.getServiceInterface().cleanupLongAction(topicId);

				for (EClass subClass : bimServerClient.getMetaDataManager().getPackageMetaData(eClass.getEPackage().getName()).getAllSubClasses(eClass)) {
					loadedClasses.add(subClass.getName());
					rebuildIndexPerClass(eClass);
				}
				loadedClasses.add(eClass.getName());
				modelState = ModelState.NONE;
				loadGeometry();
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return super.getAllWithSubTypes(eClass);
	}

	public Long getTransactionId() {
		return tid;
	}

	public ModelState getModelState() {
		return modelState;
	}

	@Override
	public boolean contains(long oid) {
		get(oid);
		return super.contains(oid);
	}

	public boolean containsNoFetch(long oid) {
		return super.contains(oid);
	}

	@Override
	public boolean containsGuid(String guid) {
		getByGuid(guid);
		return super.containsGuid(guid);
	}

	@Override
	public int count(EClass eClass) {
		try {
			return bimServerClient.getLowLevelInterface().count(roid, eClass.getName());
		} catch (UserException e) {
			e.printStackTrace();
		} catch (ServerException e) {
			e.printStackTrace();
		} catch (PublicInterfaceNotFoundException e) {
			e.printStackTrace();
		}
		return super.count(eClass);
	}

	@Override
	public IdEObject getByGuid(String guid) {
		IdEObject idEObject = super.getByGuid(guid);
		if (idEObject == null && !assumeCompletePreload) {
			try {
				modelState = ModelState.LOADING;

				Query query = new Query(getPackageMetaData());
				QueryPart queryPart = query.createQueryPart();
				queryPart.addGuid(guid);

				JsonQueryObjectModelConverter converter = new JsonQueryObjectModelConverter(getPackageMetaData());

				long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), converter.toJson(query).toString(), bimServerClient.getJsonSerializerOid(), false);

				bimServerClient.waitForDonePreparing(topicId);
				processDownload(topicId);
				clientDebugInfo.incGuid();
				bimServerClient.getServiceInterface().cleanupLongAction(topicId);

				modelState = ModelState.NONE;
				return super.getByGuid(guid);
			} catch (Exception e) {
				LOGGER.error("", e);
			}
		}
		return idEObject;
	}

	public  T create(Class clazz) throws IfcModelInterfaceException, ObjectAlreadyExistsException {
		EClassifier eClassifier = getPackageMetaData().getEPackage().getEClassifier(clazz.getSimpleName());
		if (eClassifier == null) {
			eClassifier = GeometryPackage.eINSTANCE.getEClassifier(clazz.getSimpleName());
		}
		if (eClassifier == null) {
			throw new IfcModelInterfaceException("EClass not found " + clazz);
		}
		return create((EClass) eClassifier);
	}

	@SuppressWarnings("unchecked")
	@Override
	public  T create(EClass eClass, long oid) throws IfcModelInterfaceException {
		IdEObjectImpl object = super.create(eClass, oid);
		if (recordChanges) {
			object.eAdapters().add(adapter);
		}
		return (T) object;
	}

	@SuppressWarnings("unchecked")
	@Override
	public  T create(EClass eClass) throws IfcModelInterfaceException, ObjectAlreadyExistsException {
		final IdEObjectImpl idEObject = (IdEObjectImpl) eClass.getEPackage().getEFactoryInstance().create(eClass);
		idEObject.setModel(this);

		if (recordChanges) {
			idEObject.eAdapters().add(adapter);
			try {
				Long oid = bimServerClient.getLowLevelInterface().createObject(tid, eClass.getName(), eClass.getEStructuralFeature("GlobalId") != null);
				idEObject.setOid(oid);
			} catch (Exception e) {
				LOGGER.error("", e);
			}
			add(idEObject.getOid(), idEObject);
		}
		return (T) idEObject;
	}

	@Override
	public void set(IdEObject idEObject, EStructuralFeature eFeature, Object newValue) {
		if (!recordChanges) {
			return;
		}
		if (!eFeature.isMany()) {
			if (getModelState() != ModelState.LOADING && ((IdEObjectImpl) idEObject).getLoadingState() != State.LOADING) {
				try {
					if (newValue != EStructuralFeature.Internal.DynamicValueHolder.NIL) {
						LowLevelInterface lowLevelInterface = getBimServerClient().getLowLevelInterface();
						if (eFeature.getName().equals("wrappedValue")) {
							// Wrapped objects get the same oid as their
							// "parent" object, so we know which object the
							// client wants to update. That's why we can use
							// idEObject.getOid() here
							// We are making this crazy hack ever crazier, let's
							// iterate over our parents features, and see if
							// there is one matching our wrapped type...
							// Seriously, when there are multiple fields of the
							// same type, this fails miserably, a real fix
							// should probably store the parent-oid + feature
							// name in the wrapped object (requires two extra,
							// volatile, fields),
							// or we just don't support this (just create a new
							// wrapped object too), we could even throw some
							// sort of exception. Hack morally okay because it's
							// client-side...
							EReference foundReference = null;
							if (contains(idEObject.getOid())) {
								IdEObject parentObject = get(idEObject.getOid());
								int found = 0;
								foundReference = null;
								for (EReference testReference : parentObject.eClass().getEAllReferences()) {
									if (((EClass) testReference.getEType()).isSuperTypeOf(idEObject.eClass())) {
										foundReference = testReference;
										found++;
										if (found > 1) {
											throw new RuntimeException(
													"Sorry, crazy hack could not resolve the right field, please let BIMserver developer know (debug info: " + parentObject.eClass().getName() + ", " + idEObject.eClass().getName() + ")");
										}
									}
								}
								if (eFeature.getEType() == EcorePackage.eINSTANCE.getEString()) {
									lowLevelInterface.setWrappedStringAttribute(getTransactionId(), idEObject.getOid(), foundReference.getName(), idEObject.eClass().getName(), (String) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getELong() || eFeature.getEType() == EcorePackage.eINSTANCE.getELongObject()) {
									lowLevelInterface.setWrappedLongAttribute(getTransactionId(), idEObject.getOid(), foundReference.getName(), idEObject.eClass().getName(), (Long) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEDouble() || eFeature.getEType() == EcorePackage.eINSTANCE.getEDoubleObject()) {
									lowLevelInterface.setWrappedDoubleAttribute(getTransactionId(), idEObject.getOid(), foundReference.getName(), idEObject.eClass().getName(), (Double) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean() || eFeature.getEType() == EcorePackage.eINSTANCE.getEBooleanObject()) {
									lowLevelInterface.setWrappedBooleanAttribute(getTransactionId(), idEObject.getOid(), foundReference.getName(), idEObject.eClass().getName(), (Boolean) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEInt() || eFeature.getEType() == EcorePackage.eINSTANCE.getEIntegerObject()) {
									lowLevelInterface.setWrappedIntegerAttribute(getTransactionId(), idEObject.getOid(), foundReference.getName(), idEObject.eClass().getName(), (Integer) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEByteArray()) {
									throw new RuntimeException("Unimplemented " + eFeature.getEType().getName() + " " + newValue);
								}
							} else {
								if (eFeature.getEType() == EcorePackage.eINSTANCE.getEString()) {
									lowLevelInterface.setStringAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (String) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getELong() || eFeature.getEType() == EcorePackage.eINSTANCE.getELongObject()) {
									lowLevelInterface.setLongAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Long) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEDouble() || eFeature.getEType() == EcorePackage.eINSTANCE.getEDoubleObject()) {
									lowLevelInterface.setDoubleAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Double) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean() || eFeature.getEType() == EcorePackage.eINSTANCE.getEBooleanObject()) {
									lowLevelInterface.setBooleanAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Boolean) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEInt() || eFeature.getEType() == EcorePackage.eINSTANCE.getEIntegerObject()) {
									lowLevelInterface.setIntegerAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Integer) newValue);
								} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEByteArray()) {
									lowLevelInterface.setByteArrayAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Byte[]) newValue);
								} else if (eFeature.getEType() instanceof EEnum) {
									lowLevelInterface.setEnumAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), ((Enum) newValue).toString());
								} else if (eFeature instanceof EReference) {
									if (newValue == null) {
										lowLevelInterface.setReference(getTransactionId(), idEObject.getOid(), eFeature.getName(), -1L);
									} else {
										lowLevelInterface.setReference(getTransactionId(), idEObject.getOid(), eFeature.getName(), ((IdEObject) newValue).getOid());
									}
								} else {
									throw new RuntimeException("Unimplemented " + eFeature.getEType().getName() + " " + newValue);
								}
							}
						} else {
							if (eFeature.getEType() == EcorePackage.eINSTANCE.getEString()) {
								lowLevelInterface.setStringAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (String) newValue);
							} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getELong() || eFeature.getEType() == EcorePackage.eINSTANCE.getELongObject()) {
								lowLevelInterface.setLongAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Long) newValue);
							} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEDouble() || eFeature.getEType() == EcorePackage.eINSTANCE.getEDoubleObject()) {
								lowLevelInterface.setDoubleAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Double) newValue);
							} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEBoolean() || eFeature.getEType() == EcorePackage.eINSTANCE.getEBooleanObject()) {
								lowLevelInterface.setBooleanAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Boolean) newValue);
							} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEInt() || eFeature.getEType() == EcorePackage.eINSTANCE.getEIntegerObject()) {
								lowLevelInterface.setIntegerAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Integer) newValue);
							} else if (eFeature.getEType() == EcorePackage.eINSTANCE.getEByteArray()) {
								if (newValue instanceof byte[]) {
									Byte[] n = new Byte[((byte[]) newValue).length];
									for (int i = 0; i < n.length; i++) {
										n[i] = ((byte[]) newValue)[i];
									}
									newValue = n;
								}
								lowLevelInterface.setByteArrayAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), (Byte[]) newValue);
							} else if (eFeature.getEType() instanceof EEnum) {
								lowLevelInterface.setEnumAttribute(getTransactionId(), idEObject.getOid(), eFeature.getName(), ((Enum) newValue).toString());
							} else if (eFeature instanceof EReference) {
								if (newValue == null) {
									lowLevelInterface.setReference(getTransactionId(), idEObject.getOid(), eFeature.getName(), -1L);
								} else {
									lowLevelInterface.setReference(getTransactionId(), idEObject.getOid(), eFeature.getName(), ((IdEObject) newValue).getOid());
								}
							} else {
								throw new RuntimeException("Unimplemented " + eFeature.getEType().getName() + " " + newValue);
							}
						}
					}
				} catch (ServiceException e) {
					LOGGER.error("", e);
				} catch (PublicInterfaceNotFoundException e) {
					LOGGER.error("", e);
				}
			}
		}
	}

	/**
	 * 
	 * This method requires IfcPlugins to be loaded (either on the default cp, or a a BIMserver plugin)
	 * 
	 */
	public void checkin(long poid, String comment) throws ServerException, UserException, PublicInterfaceNotFoundException {
		this.fixOids(new OidProvider() {
			private long c = 1;

			@Override
			public long newOid(EClass eClass) {
				return c++;
			}
		});
		try {
			Class stepSerializerClass = getPluginClassLoaderProvider().getClassLoaderFor("org.bimserver.ifc.step.serializer.Ifc2x3tc1StepSerializerPlugin").loadClass("org.bimserver.ifc.step.serializer.IfcStepSerializer");
			Constructor constructor = (Constructor) stepSerializerClass.getConstructor(PluginConfiguration.class);
			Serializer ifcStepSerializer = (Serializer) constructor.newInstance(new PluginConfiguration());
			ProjectInfo projectInfo = new ProjectInfo();
			ifcStepSerializer.init(this, projectInfo, true);
			((HeaderTakingSerializer)ifcStepSerializer).setHeaderSchema(getPackageMetaData().getSchema().getHeaderName());
			SDeserializerPluginConfiguration deserializer = bimServerClient.getServiceInterface().getSuggestedDeserializerForExtension("ifc", poid);
			bimServerClient.checkinSync(poid, comment, deserializer.getOid(), false, -1, "test", new SerializerInputstream(ifcStepSerializer));
		} catch (SerializerException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	public void load(IdEObject object) {
		if (((IdEObjectImpl) object).getLoadingState() == State.LOADING) {
			return;
		}
		loadExplicit(object.getOid());
	}

	@Override
	public void remove(IdEObject object) {
		try {
			bimServerClient.getLowLevelInterface().removeObject(getTransactionId(), object.getOid());
		} catch (PublicInterfaceNotFoundException e) {
			LOGGER.error("", e);
		} catch (ServerException e) {
			LOGGER.error("", e);
		} catch (UserException e) {
			LOGGER.error("", e);
		}
	}

	// @Override
	// public void query(ObjectNode query) {
	// try {
	// modelState = ModelState.LOADING;
	// Long downloadByTypes =
	// bimServerClient.getServiceInterface().downloadByJsonQuery(Collections.singleton(roid),
	// query.toString(), getJsonSerializerOid(), true);
	// processDownload(downloadByTypes);
	// modelState = ModelState.NONE;
	// } catch (Exception e) {
	// LOGGER.error("", e);
	// }
	// }

	@Override
	public void query(ObjectNode query, boolean assumeCompletePreload) throws ServerException, UserException, PublicInterfaceNotFoundException, IfcModelInterfaceException, IOException {
		this.assumeCompletePreload = assumeCompletePreload;
		modelState = ModelState.LOADING;
		Long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), query.toString(), bimServerClient.getJsonSerializerOid(), false);
		bimServerClient.waitForDonePreparing(topicId);

		processDownload(topicId);
		bimServerClient.getServiceInterface().cleanupLongAction(topicId);

		modelState = ModelState.NONE;
	}
	
	public void queryNew(Query query, IfcModelChangeListener ifcModelChangeListener) {
		try {
			modelState = ModelState.LOADING;
			JsonQueryObjectModelConverter converter = new JsonQueryObjectModelConverter(getPackageMetaData());
			Long topicId = bimServerClient.getServiceInterface().download(Collections.singleton(roid), converter.toJson(query).toString(), bimServerClient.getJsonSerializerOid(), false);
			bimServerClient.waitForDonePreparing(topicId);

			if (ifcModelChangeListener != null) {
				addChangeListener(ifcModelChangeListener);
			}
			processDownload(topicId);
			bimServerClient.getServiceInterface().cleanupLongAction(topicId);
			if (ifcModelChangeListener != null) {
				removeChangeListener(ifcModelChangeListener);
			}

			modelState = ModelState.NONE;
		} catch (Exception e) {
			LOGGER.error("", e);
		}
	}

	// @Override
	// public SIfcHeader getIfcHeader() {
	// SIfcHeader ifcHeader = super.getIfcHeader();
	// if (ifcHeader == null) {
	// try {
	// SRevision revision =
	// bimServerClient.getServiceInterface().getRevision(roid);
	// if (revision.getConcreteRevisions().size() == 1) {
	// ifcHeader =
	// bimServerClient.getServiceInterface().getIfcHeader(revision.getConcreteRevisions().get(0));
	// if (ifcHeader != null) {
	// setIfcHeader(ifcHeader);
	// }
	// return ifcHeader;
	// }
	// } catch (ServerException e) {
	// LOGGER.error("", e);
	// } catch (UserException e) {
	// LOGGER.error("", e);
	// } catch (PublicInterfaceNotFoundException e) {
	// LOGGER.error("", e);
	// }
	// }
	// return null;
	// }
	
	@Override
	public void dumpDebug() {
		clientDebugInfo.dump();
	}

	@Override
	public PluginClassLoaderProvider getPluginClassLoaderProvider() {
		return pluginClassLoaderProvider;
	}

	@Override
	public void setPluginClassLoaderProvider(PluginClassLoaderProvider pluginClassLoaderProvider) {
		this.pluginClassLoaderProvider = pluginClassLoaderProvider;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy