Java tutorial
package org.bimserver.client; /****************************************************************************** * Copyright (C) 2009-2013 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 <http://www.gnu.org/licenses/>. *****************************************************************************/ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; 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.apache.commons.codec.binary.Base64; import org.apache.commons.io.IOUtils; import org.bimserver.emf.IdEObject; import org.bimserver.emf.IdEObjectImpl; import org.bimserver.emf.IdEObjectImpl.State; import org.bimserver.emf.IfcModelInterfaceException; import org.bimserver.ifc.IfcModel; import org.bimserver.interfaces.objects.SSerializerPluginConfiguration; import org.bimserver.models.ifc2x3tc1.Ifc2x3tc1Factory; import org.bimserver.models.ifc2x3tc1.Ifc2x3tc1Package; import org.bimserver.models.ifc2x3tc1.IfcProduct; import org.bimserver.models.ifc2x3tc1.IfcRoot; import org.bimserver.plugins.deserializers.DeserializeException; import org.bimserver.plugins.serializers.SerializerException; import org.bimserver.plugins.serializers.SerializerInputstream; import org.bimserver.plugins.services.BimServerClientException; import org.bimserver.shared.ListWaitingObject; import org.bimserver.shared.PublicInterfaceNotFoundException; import org.bimserver.shared.SingleWaitingObject; import org.bimserver.shared.WaitingList; import org.bimserver.shared.exceptions.ServerException; import org.bimserver.shared.exceptions.UserException; 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.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; public class ClientIfcModel extends IfcModel { public static 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<String> loadedClasses = new HashSet<String>(); private long ifcSerializerOid = -1; private long jsonGeometrySerializerOid = -1; private ClientEStore eStore; public ClientIfcModel(BimServerClient bimServerClient, long poid, long roid, boolean deep) throws ServerException, UserException, BimServerClientException, PublicInterfaceNotFoundException { super(); this.eStore = new ClientEStore(this); this.bimServerClient = bimServerClient; this.roid = roid; try { tid = bimServerClient.getBimsie1LowLevelInterface().startTransaction(poid); } catch (Exception e) { LOGGER.error("", e); } if (deep) { loadDeep(); } } private ClientIfcModel(BimServerClient bimServerClient, long poid) { this.bimServerClient = bimServerClient; try { tid = bimServerClient.getBimsie1LowLevelInterface().startTransaction(poid); } catch (Exception e) { LOGGER.error("", e); } } @SuppressWarnings({ "unchecked", "rawtypes" }) public ClientIfcModel branch(long poid) { // TODO this should of course be done server side, without any copying ClientIfcModel branch = new ClientIfcModel(bimServerClient, poid); try { loadDeep(); } catch (ServerException e) { e.printStackTrace(); } catch (UserException e) { e.printStackTrace(); } catch (BimServerClientException e) { e.printStackTrace(); } catch (PublicInterfaceNotFoundException e) { e.printStackTrace(); } Map<IdEObject, IdEObject> map = new HashMap<IdEObject, IdEObject>(); for (IdEObject sourceObject : getObjects().values()) { try { IdEObject targetObject = create(sourceObject.eClass()); map.put(sourceObject, targetObject); } catch (IfcModelInterfaceException e) { e.printStackTrace(); } } 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) { targetList.add(map.get(sourceItem)); } } 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 { return bimServerClient.getBimsie1LowLevelInterface().commitTransaction(tid, comment); } public long getIfcSerializerOid() throws ServerException, UserException, PublicInterfaceNotFoundException { if (ifcSerializerOid == -1) { SSerializerPluginConfiguration serializerPluginConfiguration = bimServerClient.getPluginInterface() .getSerializerByPluginClassName("org.bimserver.serializers.JsonSerializerPlugin"); if (serializerPluginConfiguration != null) { ifcSerializerOid = serializerPluginConfiguration.getOid(); } } return ifcSerializerOid; } public long getJsonGeometrySerializerOid() throws ServerException, UserException, PublicInterfaceNotFoundException { if (jsonGeometrySerializerOid == -1) { SSerializerPluginConfiguration serializerPluginConfiguration = bimServerClient.getPluginInterface() .getSerializerByPluginClassName("org.bimserver.geometry.json.JsonGeometrySerializerPlugin"); if (serializerPluginConfiguration != null) { jsonGeometrySerializerOid = serializerPluginConfiguration.getOid(); } } return jsonGeometrySerializerOid; } private void loadDeep() throws ServerException, UserException, BimServerClientException, PublicInterfaceNotFoundException { if (modelState != ModelState.FULLY_LOADED) { modelState = ModelState.LOADING; Long download = bimServerClient.getBimsie1ServiceInterface().download(roid, getIfcSerializerOid(), true, true); processDownload(download); modelState = ModelState.FULLY_LOADED; } } @SuppressWarnings({ "unchecked", "rawtypes" }) private void processDownload(Long download) throws BimServerClientException, UserException, ServerException, PublicInterfaceNotFoundException { WaitingList<Long> waitingList = new WaitingList<Long>(); try { InputStream downloadData = bimServerClient.getDownloadData(download, getIfcSerializerOid()); boolean log = false; // TODO Make this streaming again, make sure the EmfSerializer getInputStream method is working properly if (log) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (downloadData instanceof SerializerInputstream) { SerializerInputstream serializerInputStream = (SerializerInputstream) downloadData; serializerInputStream.getEmfSerializer().writeToOutputStream(baos); } else { IOUtils.copy((InputStream) downloadData, baos); } FileOutputStream fos = new FileOutputStream(new File(download + ".json")); IOUtils.write(baos.toByteArray(), fos); fos.close(); downloadData = new ByteArrayInputStream(baos.toByteArray()); } else { ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (downloadData instanceof SerializerInputstream) { SerializerInputstream serializerInputStream = (SerializerInputstream) downloadData; serializerInputStream.getEmfSerializer().writeToOutputStream(baos); } else { IOUtils.copy((InputStream) downloadData, baos); } downloadData = new ByteArrayInputStream(baos.toByteArray()); } JsonReader jsonReader = new JsonReader(new InputStreamReader(downloadData, Charsets.UTF_8)); try { jsonReader.beginObject(); if (jsonReader.nextName().equals("objects")) { jsonReader.beginArray(); while (jsonReader.hasNext()) { jsonReader.beginObject(); if (jsonReader.nextName().equals("__oid")) { long oid = jsonReader.nextLong(); if (jsonReader.nextName().equals("__type")) { String type = jsonReader.nextString(); EClass eClass = (EClass) Ifc2x3tc1Package.eINSTANCE.getEClassifier(type); if (eClass == null) { throw new BimServerClientException("No class found with name " + type); } if (jsonReader.nextName().equals("__state")) { String state = jsonReader.nextString(); IdEObject object = null; if (containsNoFetch(oid)) { object = getNoFetch(oid); } else { object = (IdEObject) Ifc2x3tc1Factory.eINSTANCE.create(eClass); ((IdEObjectImpl) object).eSetStore(eStore); ((IdEObjectImpl) object).setOid(oid); add(oid, object); } if (state.equals("NOT_LOADED")) { ((IdEObjectImpl) object).setLoadingState(State.TO_BE_LOADED); } else { while (jsonReader.hasNext()) { String featureName = jsonReader.nextName(); boolean embedded = false; if (featureName.startsWith("__ref")) { featureName = featureName.substring(5); } else if (featureName.startsWith("__emb")) { embedded = true; featureName = featureName.substring(5); } EStructuralFeature eStructuralFeature = eClass .getEStructuralFeature(featureName); if (eStructuralFeature == null) { throw new BimServerClientException("Unknown field (" + featureName + ") on class " + eClass.getName()); } if (eStructuralFeature.isMany()) { jsonReader.beginArray(); if (eStructuralFeature instanceof EAttribute) { List list = (List) object.eGet(eStructuralFeature); List<String> stringList = null; if (eStructuralFeature.getEType() == EcorePackage.eINSTANCE .getEDoubleObject() || eStructuralFeature .getEType() == EcorePackage.eINSTANCE .getEDouble()) { EStructuralFeature asStringFeature = eClass .getEStructuralFeature( eStructuralFeature.getName() + "AsString"); stringList = (List<String>) 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; while (jsonReader.hasNext()) { if (embedded) { List list = (List) object.eGet(eStructuralFeature); jsonReader.beginObject(); String n = jsonReader.nextName(); if (n.equals("__type")) { String t = jsonReader.nextString(); IdEObject wrappedObject = (IdEObject) Ifc2x3tc1Factory.eINSTANCE .create((EClass) Ifc2x3tc1Package.eINSTANCE .getEClassifier(t)); if (jsonReader.nextName().equals("value")) { EStructuralFeature wv = wrappedObject.eClass() .getEStructuralFeature("wrappedValue"); wrappedObject.eSet(wv, readPrimitive(jsonReader, wv)); list.add(wrappedObject); } else { // error } } else if (n.equals("oid")) { // Sometimes embedded is true, bot also referenced are included, those are always embdedded in an object long refOid = jsonReader.nextLong(); if (containsNoFetch(refOid)) { IdEObject refObj = getNoFetch(refOid); AbstractEList l = (AbstractEList) object .eGet(eStructuralFeature); while (l.size() <= index) { l.addUnique(refObj.eClass().getEPackage() .getEFactoryInstance() .create(refObj.eClass())); } l.setUnique(index, refObj); } else { waitingList.add(refOid, new ListWaitingObject( object, eStructuralFeature, index)); } } jsonReader.endObject(); } else { long refOid = jsonReader.nextLong(); if (containsNoFetch(refOid)) { IdEObject refObj = getNoFetch(refOid); AbstractEList l = (AbstractEList) object .eGet(eStructuralFeature); while (l.size() <= index) { l.addUnique(refObj.eClass().getEPackage() .getEFactoryInstance() .create(refObj.eClass())); } l.setUnique(index, refObj); } else { waitingList.add(refOid, new ListWaitingObject( object, eStructuralFeature, index)); } 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"); 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 (embedded) { jsonReader.beginObject(); if (jsonReader.nextName().equals("__type")) { String t = jsonReader.nextString(); IdEObject wrappedObject = (IdEObject) Ifc2x3tc1Factory.eINSTANCE .create((EClass) Ifc2x3tc1Package.eINSTANCE .getEClassifier(t)); if (jsonReader.nextName().equals("value")) { EStructuralFeature wv = wrappedObject.eClass() .getEStructuralFeature("wrappedValue"); wrappedObject.eSet(wv, readPrimitive(jsonReader, wv)); object.eSet(eStructuralFeature, wrappedObject); } else { // error } } jsonReader.endObject(); } else { long refOid = jsonReader.nextLong(); if (containsNoFetch(refOid)) { IdEObject refObj = getNoFetch(refOid); object.eSet(eStructuralFeature, refObj); } else { waitingList.add(refOid, new SingleWaitingObject(object, eStructuralFeature)); } } } } } } if (waitingList.containsKey(oid)) { try { waitingList.updateNode(oid, eClass, object); } catch (DeserializeException e) { LOGGER.error("", e); } } } } } jsonReader.endObject(); } jsonReader.endArray(); } jsonReader.endObject(); } catch (IfcModelInterfaceException e1) { LOGGER.error("", e1); } finally { jsonReader.close(); } } catch (IOException e) { LOGGER.error("", e); } catch (SerializerException e) { LOGGER.error("", e); } finally { waitingList.dumpIfNotEmpty(); bimServerClient.getServiceInterface().cleanupLongAction(download); } } 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() || eClassifier == EcorePackage.eINSTANCE.getEDoubleObject()) { return jsonReader.nextDouble(); } else if (eClassifier == EcorePackage.eINSTANCE.getEFloat() || eClassifier == EcorePackage.eINSTANCE.getEFloatObject()) { return (float) jsonReader.nextDouble(); } else if (eClassifier == EcorePackage.eINSTANCE.getEBoolean() || eClassifier == EcorePackage.eINSTANCE.getEBooleanObject()) { return jsonReader.nextBoolean(); } else if (eClassifier == EcorePackage.eINSTANCE.getEInt() || eClassifier == EcorePackage.eINSTANCE.getEIntegerObject()) { return jsonReader.nextInt(); } else if (eClassifier == EcorePackage.eINSTANCE.getEEnum()) { // TODO DOES THIS EVER HAPPEN?? if (jsonReader.peek() == JsonToken.BOOLEAN) { EEnum eEnum = (EEnum) eStructuralFeature.getEType(); return eEnum.getEEnumLiteral(("" + jsonReader.nextBoolean()).toUpperCase()).getInstance(); } else { EEnum eEnum = (EEnum) eStructuralFeature.getEType(); return eEnum.getEEnumLiteral(jsonReader.nextString()).getInstance(); } } else if (eClassifier instanceof EClass) { throw new RuntimeException(); } else if (eClassifier == EcorePackage.eINSTANCE.getEByteArray()) { return Base64.decodeBase64(jsonReader.nextString().getBytes(Charsets.UTF_8)); } else if (eClassifier instanceof EEnum) { if (jsonReader.peek() == JsonToken.BOOLEAN) { EEnum eEnum = (EEnum) eStructuralFeature.getEType(); return eEnum.getEEnumLiteral(("" + jsonReader.nextBoolean()).toUpperCase()).getInstance(); } else { EEnum eEnum = (EEnum) eStructuralFeature.getEType(); return eEnum.getEEnumLiteral(jsonReader.nextString()).getInstance(); } } else { throw new RuntimeException("Unimplemented type " + eStructuralFeature.getEType().getName()); } } @Override public <T extends IdEObject> List<T> getAll(EClass eClass) { if (!loadedClasses.contains(eClass.getName()) && modelState != ModelState.FULLY_LOADED) { LOGGER.info("Loading all " + eClass.getName()); try { modelState = ModelState.LOADING; Long downloadByTypes = bimServerClient.getBimsie1ServiceInterface().downloadByTypes( Collections.singleton(roid), Collections.singleton(eClass.getName()), getIfcSerializerOid(), false, false, false, true); processDownload(downloadByTypes); loadedClasses.add(eClass.getName()); rebuildIndexPerClass(eClass); modelState = ModelState.NONE; } catch (Exception e) { LOGGER.error("", e); } } return super.getAll(eClass); } @Override public Set<String> getGuids(EClass eClass) { getAllWithSubTypes(eClass); return super.getGuids(eClass); } @Override public Set<String> 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() { try { loadDeep(); } catch (Exception e) { LOGGER.error("", e); } return super.size(); } @Override public Set<Long> 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.isLoadedOrLoading()) { LOGGER.info("Loading " + oid); modelState = ModelState.LOADING; Long downloadByOids = bimServerClient.getBimsie1ServiceInterface().downloadByOids( Collections.singleton(roid), Collections.singleton(oid), getIfcSerializerOid(), true, false); processDownload(downloadByOids); modelState = ModelState.NONE; } } catch (Exception e) { LOGGER.error("", e); } } public IdEObject getNoFetch(long oid) { return super.get(oid); } @Override public Collection<IdEObject> getValues() { try { loadDeep(); } catch (Exception e) { LOGGER.error("", e); } return super.getValues(); } @Override public <T extends IdEObject> List<T> getAllWithSubTypes(EClass eClass) { if (!loadedClasses.contains(eClass.getName()) && modelState != ModelState.FULLY_LOADED) { try { modelState = ModelState.LOADING; Long downloadByTypes = bimServerClient.getBimsie1ServiceInterface().downloadByTypes( Collections.singleton(roid), Collections.singleton(eClass.getName()), getIfcSerializerOid(), true, false, false, true); processDownload(downloadByTypes); for (EClass subClass : bimServerClient.getMetaDataManager().getAllSubClasses(eClass)) { loadedClasses.add(subClass.getName()); rebuildIndexPerClass(eClass); } loadedClasses.add(eClass.getName()); modelState = ModelState.NONE; } 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) { return super.count(eClass); } @Override public IfcRoot getByGuid(String guid) { IfcRoot idEObject = super.getByGuid(guid); if (idEObject == null) { try { modelState = ModelState.LOADING; Long downloadByGuids = bimServerClient.getBimsie1ServiceInterface().downloadByGuids( Collections.singleton(roid), Collections.singleton(guid), getIfcSerializerOid(), false, false); processDownload(downloadByGuids); modelState = ModelState.NONE; return super.getByGuid(guid); } catch (Exception e) { LOGGER.error("", e); } } return idEObject; } @Override public void remove(IdEObject idEObject) { // TODO super.remove(idEObject); } public <T extends IdEObject> T create(Class<T> clazz) throws IfcModelInterfaceException { return create((EClass) Ifc2x3tc1Package.eINSTANCE.getEClassifier(clazz.getSimpleName())); } @SuppressWarnings("unchecked") @Override public <T extends IdEObject> T create(EClass eClass) throws IfcModelInterfaceException { IdEObjectImpl object = (IdEObjectImpl) eClass.getEPackage().getEFactoryInstance().create(eClass); object.eSetStore(eStore); try { Long oid = bimServerClient.getBimsie1LowLevelInterface().createObject(tid, eClass.getName()); object.setOid(oid); } catch (Exception e) { LOGGER.error("", e); } return (T) object; } @SuppressWarnings({ "unused", "resource" }) public void getGeometry(IfcProduct ifcProduct) { try { Long downloadByOids = bimServerClient.getBimsie1ServiceInterface().downloadByOids( Collections.singleton(roid), Collections.singleton(ifcProduct.getOid()), getJsonGeometrySerializerOid(), true, false); InputStream downloadData = bimServerClient.getDownloadData(downloadByOids, getJsonGeometrySerializerOid()); JsonReader jsonReader = new JsonReader(new InputStreamReader(downloadData)); jsonReader.beginObject(); if (jsonReader.nextName().equals("geometry")) { jsonReader.beginArray(); while (jsonReader.hasNext()) { jsonReader.beginObject(); if (jsonReader.nextName().equals("material")) { String material = jsonReader.nextString(); if (jsonReader.nextName().equals("type")) { String type = jsonReader.nextString(); if (jsonReader.nextName().equals("coreId")) { String coreid = jsonReader.nextString(); if (jsonReader.nextName().equals("primitive")) { String primitive = jsonReader.nextString(); if (jsonReader.nextName().equals("positions")) { jsonReader.beginArray(); while (jsonReader.hasNext()) { double position = jsonReader.nextDouble(); } jsonReader.endArray(); if (jsonReader.nextName().equals("normals")) { jsonReader.beginArray(); while (jsonReader.hasNext()) { double normal = jsonReader.nextDouble(); } jsonReader.endArray(); if (jsonReader.nextName().equals("nrindices")) { int nrindices = jsonReader.nextInt(); } } } } } } } jsonReader.endObject(); } jsonReader.endArray(); } jsonReader.endObject(); } catch (Exception e) { LOGGER.error("", e); } } }