diff --git a/Middleware/.classpath b/Middleware/.classpath
index 8b1b747d..ee4a5b45 100644
--- a/Middleware/.classpath
+++ b/Middleware/.classpath
@@ -32,8 +32,8 @@
-
+
diff --git a/Middleware/docs/examples/code/CalibrationExampleWithCITYdata.py b/Middleware/docs/examples/code/CalibrationExampleWithCITYdata.py
index 01587ef0..c4801ec9 100644
--- a/Middleware/docs/examples/code/CalibrationExampleWithCITYdata.py
+++ b/Middleware/docs/examples/code/CalibrationExampleWithCITYdata.py
@@ -8,12 +8,12 @@
# USER CONFIGURATION
# ==========================
# Configuration
-BASE_URL = "https://ngci.encs.concordia.ca/citydata"
-USERNAME = username # Production username created by CITYdata team
-PASSWORD = password # Production password created by CITYdata team
-# BASE_URL = "http://localhost:8080/citydata"
-# USERNAME = username # Local username created with the script (cf. README)
-# PASSWORD = password # Local password created with the script (cf. README)
+#BASE_URL = "https://ngci.encs.concordia.ca/citydata"
+#USERNAME = "workshop" # Production username
+#PASSWORD = "workshop2026" # Production password
+BASE_URL = "http://localhost:8080"
+USERNAME = "temp" # Local username
+PASSWORD = "temp" # Local password
@@ -33,7 +33,7 @@ def print_result(response):
raw_data = response.get("result", "")
raw_data = raw_data.strip("[]")
- parts = raw_data.split(", ")
+ parts =raw_data.split(", ")
print("\nResults:\n")
for i in range(0, len(parts), 3):
@@ -55,37 +55,39 @@ def fetch_consumption(base_url, token):
"Authorization": f"Bearer {token}"
}
- # json_input = {
- # "use": "ca.concordia.encs.citydata.producers.CalibrationProducer",
- # "withParams": [
- # { "name": "filePath", "value": "src/test/resources/OMHM_natural_gas.csv" }
- # ],
- # "apply": [
- # {
- # "name": "ca.concordia.encs.citydata.operations.CSVFilterOperation",
- # "withParams": [
- # { "name": "addressFilter", "value": "H1W3J9" },
- # { "name": "dateFilter", "value": "2022-04-30" }
- # ]
- # }
- # ]
- # }
-
json_input = {
- "use": "ca.concordia.encs.citydata.producers.CalibrationProducer",
- "withParams": [
- { "name": "filePath", "value": "src/test/resources/OMHM_electricity.csv" }
- ],
- "apply": [
- {
- "name": "ca.concordia.encs.citydata.operations.CSVFilterOperation",
- "withParams": [
- { "name": "addressFilter", "value": "H1Z 0B3" },
- { "name": "dateFilter", "value": "2022-02-28" }
- ]
- }
- ]
- }
+ "use": "ca.concordia.encs.citydata.producers.CalibrationProducer",
+ "withParams": [
+ { "name": "filePath", "value": "src/test/resources/OMHM_natural_gas.csv" }
+ ],
+ "apply": [
+ {
+ "name": "ca.concordia.encs.citydata.operations.CSVFilterOperation",
+ "withParams": [
+ { "name": "addressFilter", "value": "8431 Allée Léo-Bricault Montréal H1Z 0B3;8441 Allée Léo-Bricault Montréal H1Z 0B3;8425 Avenue 25e Montréal H1Z 4A9" },
+ { "name": "startDateFilter", "value": "2022-01-31" },
+ { "name": "endDateFilter", "value": "2022-12-31" }
+ ]
+ }
+ ]
+ }
+
+ # json_input = {
+ # "use": "ca.concordia.encs.citydata.producers.CalibrationProducer",
+ # "withParams": [
+ # { "name": "filePath", "value": "src/test/resources/OMHM_electricity.csv" }
+ # ],
+ # "apply": [
+ # {
+ # "name": "ca.concordia.encs.citydata.operations.CSVFilterOperation",
+ # "withParams": [
+ # { "name": "addressFilter", "value": "8431 Allée Léo-Bricault Montréal H1Z 0B3;8441 Allée Léo-Bricault Montréal H1Z 0B3;8425 Avenue 25e Montréal H1Z 4A9" },
+ # { "name": "startDateFilter", "value": "2022-01-31" },
+ # { "name": "endDateFilter", "value": "2022-12-31" }
+ # ]
+ # }
+ # ]
+ # }
response = requests.post(sync_url, headers=headers, data=json.dumps(json_input))
diff --git a/Middleware/docs/examples/code/PortfolioManagerWithCITYDataTest.py b/Middleware/docs/examples/code/PortfolioManagerWithCITYDataTest.py
index 9d60a093..7a708bc5 100644
--- a/Middleware/docs/examples/code/PortfolioManagerWithCITYDataTest.py
+++ b/Middleware/docs/examples/code/PortfolioManagerWithCITYDataTest.py
@@ -9,7 +9,7 @@
# USER CONFIGURATION
# ==========================
# Configuration
-B ASE_URL = "https://ngci.encs.concordia.ca/citydata"
+BASE_URL = "https://ngci.encs.concordia.ca/citydata"
USERNAME = "workshop" # Production username
PASSWORD = "workshop2026" # Production password
#BASE_URL = "http://localhost:8080/citydata"
diff --git a/Middleware/docs/examples/queries/filterPortfolioManagerProducerConsumption.json b/Middleware/docs/examples/queries/filterPortfolioManagerProducerConsumption.json
index 24e21fe0..84024e1a 100644
--- a/Middleware/docs/examples/queries/filterPortfolioManagerProducerConsumption.json
+++ b/Middleware/docs/examples/queries/filterPortfolioManagerProducerConsumption.json
@@ -1,27 +1,16 @@
{
- "use": "ca.concordia.encs.citydata.producers.PortfolioManagerProducer",
+ "use": "ca.concordia.encs.citydata.core.implementations.PortfolioManagerProducer",
"withParams": [
- {
- "name": "meterId",
- "value": "299278275"
- }
+ { "name": "meterId", "value": meter_id }
],
"apply": [
- {
- "use": "ca.concordia.encs.citydata.producers.PortfolioManagerProducer",
- "withParams": [
- { "name": "meterId", "value": "299278275" }
- ],
- "apply": [
- {
- "name": "ca.concordia.encs.citydata.operations.XmlToJsonFilterOperation",
- "withParams": [
- { "name": "filterKey", "value": "startDate" },
- { "name": "from", "value": "2024-11-01" },
- { "name": "to", "value": "2024-12-31" }
- ]
- }
- ]
- }
+ {
+ "name": "ca.concordia.encs.citydata.operations.XmlToJsonFilterOperation",
+ "withParams": [
+ { "name": "filterKey", "value": "startDate" },
+ { "name": "from", "value": "2020-11-01" },
+ { "name": "to", "value": "2023-12-31" }
+ ]
+ }
]
}
\ No newline at end of file
diff --git a/Middleware/docs/examples/queries/mergeRandomNumberProducers.json b/Middleware/docs/examples/queries/mergeRandomNumberProducers.json
deleted file mode 100644
index 0eec3c40..00000000
--- a/Middleware/docs/examples/queries/mergeRandomNumberProducers.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "use": "ca.concordia.encs.citydata.producers.RandomNumberProducer",
- "withParams": [
- {
- "name": "listSize",
- "value": 10
- }
- ],
- "apply": [
- {
- "name": "ca.concordia.encs.citydata.operations.AverageOperation",
- "withParams": [
- {
- "name": "roundingMethod",
- "value": "floor"
- }
- ]
- },
- {
- "name": "ca.concordia.encs.citydata.operations.MergeOperation",
- "withParams": [
- {
- "name": "targetProducer",
- "value": "ca.concordia.encs.citydata.producers.RandomNumberProducer"
- },
- {
- "name": "targetProducerParams",
- "value": [
- {
- "name": "listSize",
- "value": 4
- }
- ]
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/Middleware/docs/examples/queries/randomNumberProducerFloor.json b/Middleware/docs/examples/queries/randomNumberProducerFloor.json
deleted file mode 100644
index 6d356b9f..00000000
--- a/Middleware/docs/examples/queries/randomNumberProducerFloor.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "use": "ca.concordia.encs.citydata.producers.RandomNumberProducer",
- "withParams": [
- {
- "name": "listSize",
- "value": 10
- }
- ],
- "apply": [
- {
- "name": "ca.concordia.encs.citydata.operations.AverageOperation",
- "withParams": [
- {
- "name": "roundingMethod",
- "value": "floor"
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/Middleware/docs/examples/queries/stringProducerRandom.json b/Middleware/docs/examples/queries/stringProducerRandom.json
deleted file mode 100644
index f2315582..00000000
--- a/Middleware/docs/examples/queries/stringProducerRandom.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "use": "ca.concordia.encs.citydata.producers.RandomStringProducer",
- "withParams": [
- {
- "name": "stringLength",
- "value": 10
- }
- ],
- "apply": []
-}
\ No newline at end of file
diff --git a/Middleware/docs/examples/queries/stringProducerRandomWithParams.json b/Middleware/docs/examples/queries/stringProducerRandomWithParams.json
deleted file mode 100644
index df2dce94..00000000
--- a/Middleware/docs/examples/queries/stringProducerRandomWithParams.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "use": "ca.concordia.encs.citydata.producers.RandomStringProducer",
- "withParams": [
- {
- "name": "stringLength",
- "value": 50
- }
- ],
- "apply": [
- {
- "name": "ca.concordia.encs.citydata.operations.StringReplaceOperation",
- "withParams": [
- {
- "name": "searchFor",
- "value": "a"
- },
- {
- "name": "replaceBy",
- "value": "==HELLO=="
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/AbstractProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/AbstractProducer.java
index 81db21f1..40b537b0 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/AbstractProducer.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/AbstractProducer.java
@@ -38,8 +38,9 @@
* @since 2025-05-27
*/
-public sealed abstract class AbstractProducer extends AbstractEntity implements IProducer permits JSONProducer,
- CSVProducer, ExceptionProducer, FirebaseProducer, PortfolioManagerProducer, PortfolioManagerMetadataProducer {
+public sealed abstract class AbstractProducer extends AbstractEntity implements IProducer
+ permits JSONProducer, CSVProducer, ExceptionProducer, FirebaseProducer, PortfolioManagerProducer,
+ PortfolioManagerMetadataProducer, JsonArrayProducer {
private String filePath;
private RequestOptions fileOptions;
private IOperation operation;
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/JsonArrayProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/JsonArrayProducer.java
new file mode 100644
index 00000000..f9716e0c
--- /dev/null
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/JsonArrayProducer.java
@@ -0,0 +1,55 @@
+package ca.concordia.encs.citydata.core.implementations;
+
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import ca.concordia.encs.citydata.core.contracts.IProducer;
+import ca.concordia.encs.citydata.core.utils.RequestOptions;
+
+/**
+*This acts as a base producer for EnergyConsuimption Producer and any other producer that needs to return a JSON array.
+*
+* @author Sikandar Ejaz
+* @since 2026-05-13
+*/
+
+public non-sealed class JsonArrayProducer extends AbstractProducer implements IProducer {
+
+ public JsonArrayProducer(final String filePath) {
+ super(filePath);
+ }
+
+ public JsonArrayProducer(final String filePath, final RequestOptions fileOptions) {
+ super(filePath, fileOptions);
+ }
+
+ @Override
+ public void fetch() {
+ final ArrayList jsonOutput = new ArrayList<>();
+
+ // Use ByteArrayOutputStream to fetch data
+
+ OutputStream outputStream = this.fetchFromPath();
+ String inputJson = outputStream.toString();
+
+ // Convert JSON string to object
+ final JsonElement inputJsonElement = JsonParser.parseString(inputJson);
+
+ JsonObject outputJsonObject = new JsonObject();
+ if (inputJsonElement.isJsonArray()) {
+ outputJsonObject.add("result", inputJsonElement);
+ } else {
+ outputJsonObject = inputJsonElement.getAsJsonObject();
+ }
+
+ jsonOutput.add(outputJsonObject);
+ this.setResult(jsonOutput);
+ this.applyOperation();
+ }
+
+}
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerMetadataProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerMetadataProducer.java
index 81726e8e..d72fdb9e 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerMetadataProducer.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerMetadataProducer.java
@@ -29,6 +29,14 @@ public non-sealed class PortfolioManagerMetadataProducer extends AbstractProduce
private IOperation operation;
private IRunner runnerObserver;
+ public PortfolioManagerMetadataProducer() {
+ super();
+ }
+
+ public PortfolioManagerMetadataProducer(String filePath, RequestOptions fileOptions) {
+ super(filePath, fileOptions);
+ }
+
public void setAccountId(String accountId) {
this.accountId = accountId;
}
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerProducer.java
index b172a4b4..6d5d3ca7 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerProducer.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/core/implementations/PortfolioManagerProducer.java
@@ -24,11 +24,20 @@
public non-sealed class PortfolioManagerProducer extends AbstractProducer implements IProducer {
private String meterId;
private final ArrayList intermediateResult = new ArrayList<>();
-
- public void setMeterId(String meterId) {
- this.meterId = meterId;
- }
-
+
+ public PortfolioManagerProducer() {
+ super();
+ }
+
+ public PortfolioManagerProducer(String filePath, RequestOptions fileOptions) {
+ super(filePath, fileOptions);
+ }
+
+ public void setMeterId(String meterId) {
+ System.out.println(">>> setMeterId called with: " + meterId);
+ this.meterId = meterId;
+ }
+
@SuppressWarnings("unchecked")
private ArrayList getMeterMetadata(SingleStepRunner runner) {
final InMemoryDataStore store = InMemoryDataStore.getInstance();
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/operations/JsonArrayAverageOperation.java b/Middleware/src/main/java/ca/concordia/encs/citydata/operations/JsonArrayAverageOperation.java
index 2bf3d633..8557c0b0 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/operations/JsonArrayAverageOperation.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/operations/JsonArrayAverageOperation.java
@@ -38,6 +38,7 @@ public ArrayList apply(ArrayList inputs) {
// compute the average
for (JsonArray list : inputs) {
+ floatAverage = 0.0f;
for (JsonElement element : list) {
floatAverage += element.getAsJsonObject().get(keyName).getAsFloat();
}
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/CalibrationProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/CalibrationProducer.java
index 150c18e2..a3001770 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/CalibrationProducer.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/CalibrationProducer.java
@@ -6,6 +6,7 @@
import ca.concordia.encs.citydata.core.exceptions.MiddlewareException;
import ca.concordia.encs.citydata.core.implementations.CSVProducer;
+import ca.concordia.encs.citydata.core.utils.RequestOptions;
/**
* This Producer outputs metadata about a building, such as floors, zones and sensors.
@@ -19,6 +20,10 @@ public CalibrationProducer(String filePath) {
super(filePath);
}
+ public CalibrationProducer(String filePath, RequestOptions fileOptions) {
+ super(filePath, fileOptions);
+ }
+
@Override
public void fetch() {
System.out.println("Fetching file from path: " + this.getFilePath());
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/EnergyConsumptionProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/EnergyConsumptionProducer.java
index f5886651..4b4c124f 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/EnergyConsumptionProducer.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/EnergyConsumptionProducer.java
@@ -16,7 +16,7 @@
import ca.concordia.encs.citydata.core.exceptions.MiddlewareException;
import ca.concordia.encs.citydata.core.exceptions.MiddlewareException.DatasetNotFound;
-import ca.concordia.encs.citydata.core.implementations.CSVProducer;
+import ca.concordia.encs.citydata.core.implementations.JsonArrayProducer;
import ca.concordia.encs.citydata.core.utils.RequestOptions;
import ca.concordia.encs.citydata.core.utils.StringUtils;
@@ -30,7 +30,7 @@
* @since 2025-05-28
*/
-public class EnergyConsumptionProducer extends CSVProducer {
+public class EnergyConsumptionProducer extends JsonArrayProducer {
public EnergyConsumptionProducer(String filePath) {
super(filePath);
@@ -157,8 +157,8 @@ public void fetch() {
resultRow.addProperty("error", e.getMessage());
resultsArray.add(resultRow);
} finally {
- final ArrayList updatedResult = this.getResult();
- updatedResult.add(resultsArray.toString());
+ final ArrayList updatedResult = this.getResult();
+ updatedResult.add(resultsArray);
this.setResult(updatedResult);
this.applyOperation();
}
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/GeometryProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/GeometryProducer.java
index 862bdd7a..5f5c56ff 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/GeometryProducer.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/GeometryProducer.java
@@ -1,6 +1,9 @@
package ca.concordia.encs.citydata.producers;
import java.security.InvalidParameterException;
+import java.util.ArrayList;
+
+import com.google.gson.JsonObject;
import ca.concordia.encs.citydata.core.contracts.IOperation;
import ca.concordia.encs.citydata.core.contracts.IRunner;
@@ -15,9 +18,6 @@
*/
public class GeometryProducer extends JSONProducer {
- public GeometryProducer(String filePath, RequestOptions fileOptions) {
- super(filePath, fileOptions);
- }
private JSONProducer jsonProducer;
@@ -35,6 +35,19 @@ public void setOperation(IOperation operation) {
this.jsonProducer.setOperation(operation);
}
+ public GeometryProducer() {
+ super(null, null);
+ }
+
+ public GeometryProducer(String filePath, RequestOptions fileOptions) {
+ super(filePath, fileOptions);
+ }
+
+ @Override
+ public ArrayList getResult() {
+ return this.jsonProducer.getResult();
+ }
+
@Override
public void fetch() {
this.jsonProducer.fetch();
diff --git a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/RetrofitResultsProducer.java b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/RetrofitResultsProducer.java
index d077e146..fd52ffb4 100644
--- a/Middleware/src/main/java/ca/concordia/encs/citydata/producers/RetrofitResultsProducer.java
+++ b/Middleware/src/main/java/ca/concordia/encs/citydata/producers/RetrofitResultsProducer.java
@@ -31,6 +31,10 @@ public RetrofitResultsProducer(String filePath) {
super(filePath);
}
+ public RetrofitResultsProducer(String filePath, RequestOptions options) {
+ super(filePath, options);
+ }
+
private JsonArray buildingIds;
private IOperation jsonProducerOperation;
private IRunner runnerObserver;
diff --git a/Middleware/src/main/resources/application.properties b/Middleware/src/main/resources/application.properties
index 6cfc6966..f9fc9875 100644
--- a/Middleware/src/main/resources/application.properties
+++ b/Middleware/src/main/resources/application.properties
@@ -12,7 +12,7 @@ spring.data.mongodb.uri=mongodb://localhost:27017/citydata
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
# Portfolio Manager Energy Star Configuration
-# TODO: If multiple Portfolio manager accounts are needed, a dedicated authentication producer should replace multiple entries in the file. It is unrelated to the JWT auth
+#Warning, plan to create a portfolio manager auth producer if many instances of users will be managed
portfoliomanager.base-url=https://portfoliomanager.energystar.gov/ws
portfoliomanager.username=$PM_USERNAME
portfoliomanager.password=$PM_USERNAME
@@ -28,4 +28,4 @@ security.credentials.path=./src/main/resources/scripts/credentials/credentials.t
# server.servlet.context-path=/citydata
# Server port (8080 is the default from Spring)
-# server.port=8084
+# server.port=8084
\ No newline at end of file
diff --git a/Middleware/src/test/java/ca/concordia/encs/citydata/test/producers/ProducersSanityTest.java b/Middleware/src/test/java/ca/concordia/encs/citydata/test/producers/ProducersSanityTest.java
index c2c72fbc..95af82b9 100644
--- a/Middleware/src/test/java/ca/concordia/encs/citydata/test/producers/ProducersSanityTest.java
+++ b/Middleware/src/test/java/ca/concordia/encs/citydata/test/producers/ProducersSanityTest.java
@@ -4,6 +4,7 @@
import org.junit.jupiter.api.Test;
+import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import ca.concordia.encs.citydata.operations.StandardFilteringOperation;
@@ -34,7 +35,7 @@ public void testEnergyConsumptionProducer() {
producer1.validateParams();
producer1.buildQuery();
producer1.fetch();
- ArrayList result = producer1.getResult();
+ ArrayList result = producer1.getResult();
System.out.println(result);
}