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

nl.bimbase.bimworks.client.BimQuery Maven / Gradle / Ivy

There is a newer version: 0.0.185
Show newest version
package nl.bimbase.bimworks.client;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.DoubleNode;
import com.fasterxml.jackson.databind.node.IntNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import nl.bimbase.bimworks.actions.Discipline;
import nl.bimbase.simplebim.Qid;

@JsonInclude(Include.NON_NULL)
public class BimQuery {
	public static final BimQuery ALL = new BimQuery();
	public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
	private static final int VERSION = 1;
	private int version = 1;
	private Set types;
	private Set buildingStoreyLevels;
	private Set buildingStoreyNames;
	private Set buildingStoreyQids;
	private Set qids;
	private Map fields;
	private Map> properties;
	private Set calculatedValues;
	private Set quantities;
	private Set disciplines;
	private Set layers;
	private Set classifications;
	private Set materialNames;
	private Set guids;
	private Set propertySets;
	private Set zones;
	private Map modelInfo;
	private Set groupFeatures;

	public BimQuery() {
	}

	@JsonIgnore
	public boolean isEmpty() {
		return 
			types == null &&
			buildingStoreyLevels == null &&
			qids == null &&
			fields == null &&
			properties == null &&
			calculatedValues == null &&
			quantities == null &&
			disciplines == null &&
			layers == null &&
			classifications == null &&
			materialNames == null &&
			buildingStoreyNames == null &&
			guids == null &&
			propertySets == null &&
			zones == null &&
			buildingStoreyQids == null &&
			modelInfo == null;
	}
	
	public BimQuery addType(String... types) {
		if (this.types == null) {
			this.types = new TreeSet<>(); // Canonical
		}
		for (String type : types) {
			this.types.add(type);
		}
		return this;
	}
	
	public ObjectNode toJson() {
		ObjectNode queryNode = OBJECT_MAPPER.createObjectNode();
		queryNode.put("version", version);
		if (types != null) {
			ArrayNode typesNode = OBJECT_MAPPER.createArrayNode();
			for (String type : types) {
				typesNode.add(type);
			}
			queryNode.set("types", typesNode);
		}
		if (modelInfo != null) {
			ObjectNode modelInfoNode = OBJECT_MAPPER.createObjectNode();
			for (String key : modelInfo.keySet()) {
				modelInfoNode.put(key, modelInfo.get(key));
			}
		}
		if (buildingStoreyLevels != null) {
			ArrayNode buildingStoreyLevelsNode = OBJECT_MAPPER.createArrayNode();
			for (BuildingStoreyLevelQuery level : buildingStoreyLevels) {
				buildingStoreyLevelsNode.add(level.toJson());
			}
			queryNode.set("buildingStoreyLevels", buildingStoreyLevelsNode);
		}
		if (buildingStoreyQids != null) {
			ArrayNode buildingStoreyQidsNode = OBJECT_MAPPER.createArrayNode();
			for (Qid qid : buildingStoreyQids) {
				buildingStoreyQidsNode.add(qid.toString());
			}
			queryNode.set("buildingStoreyQids", buildingStoreyQidsNode);
		}
		if (buildingStoreyNames != null) {
			ArrayNode buildingStoreysNode = OBJECT_MAPPER.createArrayNode();
			for (String name : buildingStoreyNames) {
				buildingStoreysNode.add(name);
			}
			queryNode.set("buildingStoreys", buildingStoreysNode);
		}
		if (layers != null) {
			ArrayNode layersNode = OBJECT_MAPPER.createArrayNode();
			for (String layer : layers) {
				layersNode.add(layer);
			}
			queryNode.set("layers", layersNode);
		}
		if (zones != null) {
			ArrayNode zonesNode = OBJECT_MAPPER.createArrayNode();
			for (String zone : zones) {
				zonesNode.add(zone);
			}
			queryNode.set("zones", zonesNode);
		}
		if (materialNames != null) {
			ArrayNode materialsNode = OBJECT_MAPPER.createArrayNode();
			for (String materialName : materialNames) {
				materialsNode.add(materialName);
			}
			queryNode.set("materialNames", materialsNode);
		}
		if (quantities != null) {
			ArrayNode quantitiesNode = OBJECT_MAPPER.createArrayNode();
			for (QuantityValueQuery quantityValueQuery : quantities) {
				quantitiesNode.add(quantityValueQuery.toJson());
			}
			queryNode.set("quantities", quantitiesNode);
		}
		if (classifications != null) {
			ArrayNode classificationsNode = OBJECT_MAPPER.createArrayNode();
			for (String classification : classifications) {
				classificationsNode.add(classification);
			}
			queryNode.set("classifications", classificationsNode);
		}
		if (qids != null) {
			ArrayNode qidsNode = OBJECT_MAPPER.createArrayNode();
			for (Qid qid : qids) {
				qidsNode.add(qid.toString());
			}
			queryNode.set("qids", qidsNode);
		}
		if (disciplines != null) {
			ArrayNode disciplinesNode = OBJECT_MAPPER.createArrayNode();
			for (Discipline discipline : disciplines) {
				disciplinesNode.add(discipline.name());
			}
			queryNode.set("disciplines", disciplinesNode);
		}
		if (guids != null) {
			ArrayNode guidsNode = OBJECT_MAPPER.createArrayNode();
			for (String guid : guids) {
				guidsNode.add(guid);
			}
			queryNode.set("guids", guidsNode);
		}
		if (fields != null) {
			ArrayNode fieldsNode = OBJECT_MAPPER.createArrayNode();
			for (String fieldName : fields.keySet()) {
				FieldQuery fieldQuery = fields.get(fieldName);
				fieldsNode.add(fieldQuery.toJson());
			}
			queryNode.set("fields", fieldsNode);
		}
		if (properties != null) {
			ArrayNode propertiesNode = OBJECT_MAPPER.createArrayNode();
			for (String propertySetName : properties.keySet()) {
				Map map = properties.get(propertySetName);
				for (String propertyName : map.keySet()) {
					propertiesNode.add(map.get(propertyName).toJson());
				}
			}
			queryNode.set("properties", propertiesNode);
		}
		if (propertySets != null) {
			ArrayNode propertySetsNode = OBJECT_MAPPER.createArrayNode();
			for (String propertySetName : propertySets) {
				propertySetsNode.add(propertySetName);
			}
			queryNode.set("propertySets", propertySetsNode);
		}
		if (calculatedValues != null) {
			ArrayNode calculatedValuesNode = OBJECT_MAPPER.createArrayNode();
			for (CalculatedValueQuery calculatedValueQuery : calculatedValues) {
				calculatedValuesNode.add(calculatedValueQuery.toJson());
			}
			queryNode.set("calculated", calculatedValuesNode);
		}
		if (groupFeatures != null) {
			ArrayNode groupNodes = OBJECT_MAPPER.createArrayNode();
			for (String group : groupFeatures) {
				groupNodes.add(group);
			}
			queryNode.set("group", groupNodes);
		}
		return queryNode;
	}
	
	public BimQuery addProperty(String propertySetName, String propertyName, Operator operator, JsonNode value) {
		if (this.properties == null) {
			this.properties = new HashMap<>();
		}
		Map map = this.properties.get(propertySetName);
		if (map == null) {
			map = new HashMap<>();
			this.properties.put(propertySetName, map);
		}
		map.put(propertyName, new PropertyQuery(propertySetName, propertyName, operator, value));
		return this;
	}

	public static BimQuery of(ObjectNode jsonNode) throws UnsupportedBimQueryVersion, BimQueryValidationException {
		if (jsonNode == null) {
			return BimQuery.ALL;
		}
//		System.out.println(jsonNode.toString());
		BimQuery bimQuery = new BimQuery();
		jsonNode = jsonNode.deepCopy(); // Doing this because we don't want to alter the original... TODO make more efficient
		if (!jsonNode.has("version")) {
			throw new BimQueryValidationException("version field is required");
		}
		bimQuery.version = jsonNode.get("version").asInt();
		jsonNode.remove("version");
		if (bimQuery.version != VERSION) {
			throw new UnsupportedBimQueryVersion(bimQuery.version, VERSION);
		}
		if (jsonNode.has("propertySets")) {
			ArrayNode propertySetsNode = (ArrayNode)jsonNode.get("propertySets");
			for (JsonNode propertySetNode : propertySetsNode) {
				bimQuery.addPropertySet(propertySetNode.asText());
			}
			jsonNode.remove("propertySets");
		}
		if (jsonNode.hasNonNull("modelInfo")) {
			ArrayNode modelInfoNode = (ArrayNode) jsonNode.get("modelInfo");
			for (JsonNode modelNode : modelInfoNode) {
//				bimQuery.addModelInfo();
			}
			jsonNode.remove("modelInfo");
		}
		if (jsonNode.has("types")) {
			ArrayNode typesNode = (ArrayNode)jsonNode.get("types");
			for (JsonNode typeNode : typesNode) {
				bimQuery.addType(typeNode.asText());
			}
			jsonNode.remove("types");
		}
		if (jsonNode.has("zones")) {
			ArrayNode zonesNode = (ArrayNode)jsonNode.get("zones");
			for (JsonNode zoneNode : zonesNode) {
				bimQuery.addZone(zoneNode.asText());
			}
			jsonNode.remove("zones");
		}
		if (jsonNode.has("guids")) {
			ArrayNode guidsNode = (ArrayNode)jsonNode.get("guids");
			for (JsonNode guidNode : guidsNode) {
				bimQuery.addGuid(guidNode.asText());
			}
			jsonNode.remove("guids");
		}
		if (jsonNode.has("buildingStoreyLevels")) {
			ArrayNode buildingStoreyLevelsNode = (ArrayNode) jsonNode.get("buildingStoreyLevels");
			for (JsonNode buildingStoreyLevelNode : buildingStoreyLevelsNode) {
				bimQuery.addBuildingStoreyLevel(BuildingStoreyLevelQuery.of(buildingStoreyLevelsNode));
			}
			jsonNode.remove("buildingStoreyLevels");
		}
		if (jsonNode.hasNonNull("buildingStoreyQids")) {
			ArrayNode buildingStoreyQidsNode = (ArrayNode) jsonNode.get("buildingStoreyQids");
			for (JsonNode buildingStoreyQidNode : buildingStoreyQidsNode) {
				bimQuery.addBuildingStoreyQid(Qid.of(buildingStoreyQidNode.asText()));
			}
			jsonNode.remove("buildingStoreyQids");
		}
		if (jsonNode.has("buildingStoreyNames")) {
			ArrayNode buildingStoreysNode = (ArrayNode) jsonNode.get("buildingStoreyNames");
			for (JsonNode buildingStoreyNode : buildingStoreysNode) {
				bimQuery.addBuildingStoreyName(buildingStoreyNode.asText());
			}
			jsonNode.remove("buildingStoreyNames");
		}
		if (jsonNode.has("qids")) {
			ArrayNode qidsNode = (ArrayNode) jsonNode.get("qids");
			for (JsonNode qidNode : qidsNode) {
				bimQuery.addQid(Qid.of(qidNode.asText()));
			}
			jsonNode.remove("qids");
		}
		if (jsonNode.has("classifications")) {
			ArrayNode classificationsNode = (ArrayNode) jsonNode.get("classifications");
			for (JsonNode classificationNode : classificationsNode) {
				bimQuery.addClassification(classificationNode.asText());
			}
			jsonNode.remove("classifications");
		}
		if (jsonNode.has("materialNames")) {
			ArrayNode materialNamesNode = (ArrayNode) jsonNode.get("materialNames");
			for (JsonNode materialNameNode : materialNamesNode) {
				bimQuery.addMaterialName(materialNameNode.asText());
			}
			jsonNode.remove("materialNames");
		}
		if (jsonNode.has("fields")) {
			ArrayNode fieldsNode = (ArrayNode) jsonNode.get("fields");
			for (JsonNode fieldNode : fieldsNode) {
				String name = fieldNode.get("name").asText();
				Operator operator = Operator.EXISTS;
				if (fieldNode.has("operator")) {
					operator = Operator.bySymbol(fieldNode.get("operator").asText());
				}
				bimQuery.addField(name, operator, fieldNode.get("value"));
			}
			jsonNode.remove("fields");
		}
		if (jsonNode.has("quantities")) {
			ArrayNode quantitiesNode = (ArrayNode)jsonNode.get("quantities");
			for (JsonNode quantityNode : quantitiesNode) {
				bimQuery.addQuantity(QuantityValueQuery.of(quantityNode));
			}
			jsonNode.remove("quantities");
		}
		if (jsonNode.has("layers")) {
			ArrayNode layersNode = (ArrayNode) jsonNode.get("layers");
			for (JsonNode layerNode : layersNode) {
				bimQuery.addLayer(layerNode.asText());
			}
			jsonNode.remove("layers");
		}
		if (jsonNode.has("disciplines")) {
			ArrayNode disciplinesNode = (ArrayNode) jsonNode.get("disciplines");
			for (JsonNode disciplineNode : disciplinesNode) {
				bimQuery.addDiscipline(Discipline.valueOf(disciplineNode.asText().toLowerCase()));
			}
			jsonNode.remove("disciplines");
		}
		if (jsonNode.has("properties")) {
			ArrayNode propertiesNode = (ArrayNode) jsonNode.get("properties");
			for (JsonNode propertyNode : propertiesNode) {
				String propertySetName = propertyNode.has("propertySetName") ? propertyNode.get("propertySetName").asText() : null;
				if (propertyNode.has("value")) {
					bimQuery.addProperty(propertySetName, propertyNode.get("name").asText(), Operator.bySymbol(propertyNode.get("operator").asText()), propertyNode.get("value"));
				} else {
					bimQuery.addProperty(propertySetName, propertyNode.get("name").asText());
				}
			}
			jsonNode.remove("properties");
		}
		if (jsonNode.has("calculated")) {
			ArrayNode calculatedValuesNode = (ArrayNode) jsonNode.get("calculated");
			for (JsonNode calculatedValueNode : calculatedValuesNode) {
				if (calculatedValueNode.has("name")) {
					String[] path = calculatedValueNode.get("name").asText().split("\\.");
					Operator operator = Operator.EQUALS;
					if (calculatedValueNode.hasNonNull("operator")) {
						operator = Operator.bySymbol(calculatedValueNode.get("operator").asText());
					}
					bimQuery.addCalculatedValue(new CalculatedValueQuery(path, operator, calculatedValueNode.get("value")));
				}
			}
			jsonNode.remove("calculated");
		}
		if (jsonNode.hasNonNull("group")) {
			JsonNode group = jsonNode.get("group");
			if (group instanceof ObjectNode) {
				ObjectNode groupNode = (ObjectNode)group;
				bimQuery.addGroup(groupNode.asText());
			} else if (group instanceof ArrayNode) {
				ArrayNode groupNodes = (ArrayNode) group;
				for (JsonNode groupNode : groupNodes) {
					bimQuery.addGroup(groupNode.asText());
				}
			}
			jsonNode.remove("group");
		}
		if (jsonNode.has("features")) {
			jsonNode.remove("features");
		}
		Iterator fieldNames = jsonNode.fieldNames();
		if (fieldNames.hasNext()) {
			throw new BimQueryValidationException("Unexpected field: " + fieldNames.next());
		}
		return bimQuery;
	}
	
	public BimQuery addGroup(String group) {
		if (this.groupFeatures == null) {
			this.groupFeatures = new LinkedHashSet<>();
		}
		this.groupFeatures.add(group);
		return this;
	}

	public void addBuildingStoreyQid(Qid qid) {
		if (this.buildingStoreyQids == null) {
			this.buildingStoreyQids = new HashSet<>();
		}
		this.buildingStoreyQids.add(qid);
	}

	public void addModelInfo(String fieldName, String value) {
		if (this.modelInfo == null) {
			this.modelInfo = new HashMap<>();
		}
		this.modelInfo.put(fieldName, value);
	}

	public BimQuery addGuid(String guid) {
		if (this.guids == null) {
			this.guids = new HashSet<>();
		}
		this.guids.add(guid);
		return this;
	}

	private void addBuildingStoreyName(String name) {
		if (this.buildingStoreyNames == null) {
			this.buildingStoreyNames = new HashSet<>();
		}
		this.buildingStoreyNames.add(name);
	}

	public BimQuery addLayer(String layer) {
		if (this.layers == null) {
			this.layers = new HashSet<>();
		}
		this.layers.add(layer);
		return this;
	}

	public void addDiscipline(Discipline discipline) {
		if (disciplines == null) {
			this.disciplines = new HashSet<>();
		}
		this.disciplines.add(discipline);
	}

	@Override
	public String toString() {
		return toJson().toString();
	}
	
	private void addQid(Qid qid) {
		if (this.qids == null) {
			this.qids = new TreeSet<>();
		}
		this.qids.add(qid);
	}

	public BimQuery addField(String fieldName, Operator operator, JsonNode value) {
		if (this.fields == null) {
			this.fields = new TreeMap<>();
		}
		this.fields.put(fieldName, new FieldQuery(fieldName, operator, value));
		return this;
	}

	public BimQuery addField(String fieldName) {
		if (this.fields == null) {
			this.fields = new TreeMap<>();
		}
		this.fields.put(fieldName, new FieldQuery(fieldName, Operator.EXISTS, null));
		return this;
	}

	public void addField(String fieldName, Operator operator, double value) {
		if (this.fields == null) {
			this.fields = new TreeMap<>();
		}
		this.fields.put(fieldName, new FieldQuery(fieldName, operator, DoubleNode.valueOf(value)));
	}

	public BimQuery addProperty(String propertySetName, String propertyName) {
		if (this.properties == null) {
			this.properties = new TreeMap<>();
		}
		if (propertySetName == null) {
			propertySetName = "*";
		}
		Map map = this.properties.get(propertySetName);
		if (map == null) {
			map = new TreeMap<>();
			this.properties.put(propertySetName, map);
		}
		map.put(propertyName, new PropertyQuery(propertySetName, propertyName, Operator.EXISTS, null));
		return this;
	}

	public BimQuery addCalculatedValue(CalculatedValueQuery calculatedValueQuery) {
		if (this.calculatedValues == null) {
			this.calculatedValues = new TreeSet<>();
		}
		calculatedValues.add(calculatedValueQuery);
		return this;
	}
	
	public Set getDisciplines() {
		return disciplines;
	}
	
	public void addClassification(String classification) {
		if (this.classifications == null) {
			this.classifications = new HashSet<>();
		}
		this.classifications.add(classification);
	}
	
	public BimQuery addMaterialName(String materialName) {
		if (this.materialNames == null) {
			this.materialNames = new HashSet<>();
		}
		this.materialNames.add(materialName);
		return this;
	}
	
	public void addQuantity(QuantityValueQuery quantityValueQuery) {
		if (this.quantities == null) {
			this.quantities = new HashSet<>();
		}
		this.quantities.add(quantityValueQuery);
	}
	
	public void addPropertySet(String propertySetName) {
		if (this.propertySets == null) {
			this.propertySets = new HashSet<>();
		}
		this.propertySets.add(propertySetName);
	}
	
	public BimQuery addZone(String zone) {
		if (this.zones == null) {
			this.zones = new HashSet<>();
		}
		this.zones.add(zone);
		return this;
	}

	public Set getBuildingStoreyQids() {
		return buildingStoreyQids;
	}

	public void setBuildingStoreyQids(Set buildingStoreyQids) {
		this.buildingStoreyQids = buildingStoreyQids;
	}
	
	public Set getTypes() {
		return types;
	}
	
	public Set getGuids() {
		return guids;
	}
	
	public Set getMaterialNames() {
		return materialNames;
	}
	
	public Set getLayers() {
		return layers;
	}
	
	public Set getZones() {
		return zones;
	}
	
	public Map> getProperties() {
		return properties;
	}

	@JsonIgnore
	public Set getPropertiesQueries() {
		Set set = new HashSet<>();
		for (Map map : properties.values()) {
			for (PropertyQuery propertyQuery : map.values()) {
				set.add(propertyQuery);
			}
		}
		return set;
	}
	
	public Map getFields() {
		return fields;
	}
	
	public Set getCalculatedValues() {
		return calculatedValues;
	}
	
	public Set getClassifications() {
		return classifications;
	}
	
	public Set getBuildingStoreyNames() {
		return buildingStoreyNames;
	}
	
	public Set getQuantities() {
		return quantities;
	}

	public boolean hasQids() {
		return qids != null && !qids.isEmpty();
	}

	public boolean hasTypes() {
		return types != null && !types.isEmpty();
	}

	public boolean hasBuildingStoreyNames() {
		return buildingStoreyNames != null && !buildingStoreyNames.isEmpty();
	}

	public boolean hasBuildingStoreyQids() {
		return buildingStoreyQids != null && !buildingStoreyQids.isEmpty();
	}

	public boolean hasBuildingStoreyLevels() {
		return buildingStoreyLevels != null && !buildingStoreyLevels.isEmpty();
	}

	public boolean hasMaterialNames() {
		return materialNames != null && !materialNames.isEmpty();
	}

	public boolean hasLayers() {
		return layers != null && !layers.isEmpty();
	}

	public boolean hasZones() {
		return zones != null && !zones.isEmpty();
	}

	public boolean hasClassifications() {
		return classifications != null && !classifications.isEmpty();
	}

	public Set getQids() {
		return qids;
	}

	public boolean hasCalculated() {
		return calculatedValues != null && !calculatedValues.isEmpty();
	}

	public boolean hasGuids() {
		return guids != null && !guids.isEmpty();
	}

	public boolean hasFields() {
		return fields != null && !fields.isEmpty();
	}

	public boolean hasProperties() {
		return properties != null && !properties.isEmpty();
	}

	public boolean hasQuantities() {
		return quantities != null && !quantities.isEmpty();
	}

	public boolean hasAggregations() {
		return groupFeatures != null && !groupFeatures.isEmpty();
	}

	public Set getGroupFeatures() {
		return groupFeatures;
	}

	public void setGroupFeatures(Set groupFeatures) {
		this.groupFeatures = groupFeatures;
	}

	public BimQuery addBuildingStoreyLevel(BuildingStoreyLevelQuery buildingStoreyLevelQuery) {
		if (this.buildingStoreyLevels == null) {
			this.buildingStoreyLevels = new HashSet<>();
		}
		this.buildingStoreyLevels.add(buildingStoreyLevelQuery);
		return this;
	}
	
	public BimQuery addBuildingStoreyLevel(int level, Operator operator) {
		if (this.buildingStoreyLevels == null) {
			this.buildingStoreyLevels = new HashSet<>();
		}
		this.buildingStoreyLevels.add(new BuildingStoreyLevelQuery(operator, IntNode.valueOf(level)));
		return this;
	}
	
	public Set getBuildingStoreyLevels() {
		return buildingStoreyLevels;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy