Skip to content

Commit a120da0

Browse files
committed
Fixed unicorn_web issues.
1 parent 9d1f827 commit a120da0

File tree

7 files changed

+121
-74
lines changed

7 files changed

+121
-74
lines changed

unicorn_approvals/ApprovalsService/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,16 @@
136136
<configuration>
137137
<environmentVariables>
138138
<LAMBDA_TASK_ROOT>handler</LAMBDA_TASK_ROOT>
139+
<CONTRACT_STATUS_TABLE>test-table</CONTRACT_STATUS_TABLE>
139140
</environmentVariables>
140141
</configuration>
142+
<dependencies>
143+
<dependency>
144+
<groupId>org.apache.maven.surefire</groupId>
145+
<artifactId>surefire-junit4</artifactId>
146+
<version>3.5.3</version>
147+
</dependency>
148+
</dependencies>
141149
</plugin>
142150
<plugin>
143151
<groupId>org.apache.maven.plugins</groupId>

unicorn_approvals/ApprovalsService/src/main/java/approvals/ContractStatusChangedHandlerFunction.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,24 @@ public class ContractStatusChangedHandlerFunction {
4545
@Metrics(captureColdStart = true)
4646
@Logging(logEvent = true)
4747
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
48+
logger.info("TABLE_NAME environment variable: {}", TABLE_NAME);
49+
4850
Event event = Marshaller.unmarshal(inputStream, Event.class);
4951
ContractStatusChanged contractStatusChanged = event.getDetail();
52+
logger.info("Received event: {}", contractStatusChanged);
5053

51-
saveContractStatus(
52-
contractStatusChanged.getPropertyId(),
53-
contractStatusChanged.getContractStatus(),
54-
contractStatusChanged.getContractId(),
55-
contractStatusChanged.getContractLastModifiedOn()
56-
);
54+
try {
55+
saveContractStatus(
56+
contractStatusChanged.getPropertyId(),
57+
contractStatusChanged.getContractStatus(),
58+
contractStatusChanged.getContractId(),
59+
contractStatusChanged.getContractLastModifiedOn()
60+
);
61+
logger.info("Successfully updated contract status for property: {}", contractStatusChanged.getPropertyId());
62+
} catch (Exception e) {
63+
logger.error("Failed to update contract status for property: {}", contractStatusChanged.getPropertyId(), e);
64+
throw e;
65+
}
5766

5867
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
5968
writer.write(objectMapper.writeValueAsString(event.getDetail()));
@@ -62,6 +71,12 @@ public void handleRequest(InputStream inputStream, OutputStream outputStream, Co
6271

6372
@Tracing
6473
void saveContractStatus(String propertyId, String contractStatus, String contractId, Long contractLastModifiedOn) {
74+
if (TABLE_NAME == null || TABLE_NAME.isEmpty()) {
75+
throw new RuntimeException("CONTRACT_STATUS_TABLE environment variable is not set");
76+
}
77+
78+
logger.info("Updating DynamoDB table: {} for property: {}", TABLE_NAME, propertyId);
79+
6580
Map<String, AttributeValue> key = Map.of("property_id", AttributeValue.fromS(propertyId));
6681

6782
Map<String, AttributeValue> expressionAttributeValues = Map.of(
@@ -78,6 +93,7 @@ void saveContractStatus(String propertyId, String contractStatus, String contrac
7893
.build();
7994

8095
dynamodbClient.updateItem(updateItemRequest);
96+
logger.info("DynamoDB update completed for property: {}", propertyId);
8197
}
8298

8399
public void setDynamodbClient(DynamoDbClient dynamodbClient) {

unicorn_web/Common/src/main/java/dao/Property.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public String getPk() {
3535
if (country == null || city == null) {
3636
return pk; // Return stored value if components are null
3737
}
38-
return ("PROPERTY#" + country + "#" + city).replace(' ', '-').toLowerCase();
38+
return ("PROPERTY#" + country.toLowerCase() + "#" + city.toLowerCase()).replace(' ', '-');
3939
}
4040

4141
public void setPk(String pk) {

unicorn_web/Data/property_data.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[
22
{
3-
"PK": "property#usa#anytown",
3+
"PK": "PROPERTY#usa#anytown",
44
"SK": "main-street#111",
55
"country": "USA",
66
"city": "Anytown",
@@ -19,7 +19,7 @@
1919
"status": "PENDING"
2020
},
2121
{
22-
"PK": "property#usa#main-town",
22+
"PK": "PROPERTY#usa#main-town",
2323
"SK": "my-street#222",
2424
"country": "USA",
2525
"city": "Main Town",
@@ -38,7 +38,7 @@
3838
"status": "PENDING"
3939
},
4040
{
41-
"PK": "property#usa#anytown",
41+
"PK": "PROPERTY#usa#anytown",
4242
"SK": "main-street#333",
4343
"country": "USA",
4444
"city": "Anytown",

unicorn_web/PublicationManagerService/src/main/java/publicationmanager/PublicationApprovedEventHandler.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,23 +96,29 @@ public void handleRequest(InputStream inputStream, OutputStream outputStream, Co
9696

9797
@Tracing
9898
private void updatePropertyStatus(String evaluationResult, String propertyId) {
99+
logger.info("Updating property status for property ID: {}", propertyId);
100+
logger.info("Evaluation result: {}", evaluationResult);
99101
try {
100102
String[] parts = propertyId.split("/");
101103
if (parts.length != 4) {
102104
throw new IllegalArgumentException("Invalid property ID format: " + propertyId);
103105
}
104106

105-
String partitionKey = ("search#" + parts[0] + "#" + parts[1]).replace(' ', '-').toLowerCase();
107+
String partitionKey = ("PROPERTY#" + parts[0] + "#" + parts[1]).replace(' ', '-');
106108
String sortKey = (parts[2] + "#" + parts[3]).replace(' ', '-').toLowerCase();
107109

110+
logger.info("Paritition Key: {}", partitionKey);
111+
logger.info("Sort Key: {}", sortKey);
112+
108113
Key key = Key.builder().partitionValue(partitionKey).sortValue(sortKey).build();
109114
Property existingProperty = propertyTable.getItem(key).join();
110115

111116
if (existingProperty == null) {
112117
logger.error("Property not found for ID: {}", propertyId);
113118
throw new RuntimeException("Property not found with ID: " + propertyId);
114119
}
115-
120+
logger.info("Existing property: {}", existingProperty);
121+
116122
existingProperty.setPropertyNumber(parts[3]);
117123
existingProperty.setStatus(evaluationResult);
118124

unicorn_web/PublicationManagerService/src/main/java/publicationmanager/RequestApprovalFunction.java

Lines changed: 77 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
import java.util.regex.Pattern;
1313

1414
import com.amazonaws.services.lambda.runtime.Context;
15-
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
16-
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
15+
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
1716
import com.fasterxml.jackson.annotation.JsonProperty;
1817
import com.fasterxml.jackson.core.JsonProcessingException;
1918
import com.fasterxml.jackson.databind.JsonNode;
@@ -36,7 +35,6 @@
3635
import software.amazon.awssdk.services.eventbridge.EventBridgeAsyncClient;
3736
import software.amazon.awssdk.services.eventbridge.model.PutEventsRequest;
3837
import software.amazon.awssdk.services.eventbridge.model.PutEventsRequestEntry;
39-
import software.amazon.lambda.powertools.logging.CorrelationIdPathConstants;
4038
import software.amazon.lambda.powertools.logging.Logging;
4139
import software.amazon.lambda.powertools.metrics.Metrics;
4240
import software.amazon.lambda.powertools.tracing.Tracing;
@@ -49,7 +47,6 @@ public class RequestApprovalFunction {
4947
private static final Logger logger = LogManager.getLogger(RequestApprovalFunction.class);
5048
private static final Set<String> NO_ACTION_STATUSES = new HashSet<>(Arrays.asList("APPROVED"));
5149
private static final String PROPERTY_ID_PATTERN = "[a-z-]+\\/[a-z-]+\\/[a-z][a-z0-9-]*\\/[0-9-]+";
52-
private static final String CONTENT_TYPE = "application/json";
5350

5451
private final Pattern propertyIdPattern = Pattern.compile(PROPERTY_ID_PATTERN);
5552
private final String tableName = System.getenv("DYNAMODB_TABLE");
@@ -60,6 +57,7 @@ public class RequestApprovalFunction {
6057
private final ObjectMapper objectMapper = new ObjectMapper();
6158

6259
public RequestApprovalFunction() {
60+
6361
DynamoDbAsyncClient dynamodbClient = DynamoDbAsyncClient.builder()
6462
.httpClientBuilder(NettyNioAsyncHttpClient.builder())
6563
.build();
@@ -76,72 +74,74 @@ public RequestApprovalFunction() {
7674

7775
@Tracing
7876
@Metrics(captureColdStart = true)
79-
@Logging(logEvent = true, correlationIdPath = CorrelationIdPathConstants.API_GATEWAY_REST)
80-
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input,
81-
final Context context) {
82-
try {
83-
if (input.getBody() == null || input.getBody().trim().isEmpty()) {
84-
return createErrorResponse(400, "Request body is required");
85-
}
86-
87-
JsonNode rootNode = objectMapper.readTree(input.getBody());
88-
JsonNode propertyIdNode = rootNode.get("property_id");
89-
90-
if (propertyIdNode == null) {
91-
return createErrorResponse(400, "property_id field is required");
92-
}
77+
@Logging(logEvent = true)
78+
public void handleRequest(final SQSEvent input, final Context context) {
79+
logger.info("Environment variables - DYNAMODB_TABLE: {}, EVENT_BUS: {}", tableName, eventBus);
80+
logger.info("Starting approval request processing for {} messages", input.getRecords().size());
9381

94-
String propertyId = propertyIdNode.asText();
95-
if (!propertyIdPattern.matcher(propertyId).matches()) {
96-
return createErrorResponse(400, "Invalid property_id format. Must match: " + PROPERTY_ID_PATTERN);
97-
}
98-
99-
PropertyComponents components = parsePropertyId(propertyId);
100-
List<Property> properties = queryTable(components.partitionKey, components.sortKey);
101-
102-
if (properties.isEmpty()) {
103-
return createErrorResponse(404, "Property not found");
104-
}
105-
106-
Property property = properties.get(0);
107-
if (NO_ACTION_STATUSES.contains(property.getStatus())) {
108-
return createSuccessResponse("Property is already " + property.getStatus() + "; no action taken");
82+
83+
for (SQSEvent.SQSMessage message : input.getRecords()) {
84+
try {
85+
String body = message.getBody();
86+
logger.info("Processing SQS message: {}", body);
87+
88+
if (body == null || body.trim().isEmpty()) {
89+
logger.warn("Message body is null or empty");
90+
continue;
91+
}
92+
93+
JsonNode rootNode = objectMapper.readTree(body);
94+
JsonNode propertyIdNode = rootNode.get("property_id");
95+
96+
if (propertyIdNode == null) {
97+
logger.warn("property_id field missing from message");
98+
continue;
99+
}
100+
101+
String propertyId = propertyIdNode.asText();
102+
logger.info("Processing approval request for property: {}", propertyId);
103+
104+
if (!propertyIdPattern.matcher(propertyId).matches()) {
105+
logger.warn("Invalid property_id format: {}", propertyId);
106+
continue;
107+
}
108+
109+
PropertyComponents components = parsePropertyId(propertyId);
110+
logger.info("Parsed property ID components: {}", components);
111+
List<Property> properties = queryTable(components.partitionKey, components.sortKey);
112+
113+
if (properties.isEmpty()) {
114+
logger.warn("Property not found in database: {}", propertyId);
115+
continue;
116+
}
117+
118+
Property property = properties.get(0);
119+
logger.info("Found property with status: {}", property.getStatus());
120+
121+
if (NO_ACTION_STATUSES.contains(property.getStatus())) {
122+
logger.info("Property already approved, no action needed: {}", propertyId);
123+
continue;
124+
}
125+
126+
sendEvent(property);
127+
logger.info("Approval request completed successfully for property: {}", propertyId);
128+
129+
} catch (JsonProcessingException e) {
130+
logger.error("Invalid JSON in message body: {}", message.getBody(), e);
131+
} catch (Exception e) {
132+
logger.error("Error processing approval request for message: {}", message.getBody(), e);
109133
}
110-
111-
sendEvent(property);
112-
return createSuccessResponse("Approval requested successfully");
113-
114-
} catch (JsonProcessingException e) {
115-
logger.error("Invalid JSON in request body", e);
116-
return createErrorResponse(400, "Invalid JSON format");
117-
} catch (Exception e) {
118-
logger.error("Error processing approval request", e);
119-
return createErrorResponse(500, "Internal server error");
120134
}
121135
}
122136

123137
private PropertyComponents parsePropertyId(String propertyId) {
124138
String[] parts = propertyId.split("/");
125-
String partitionKey = ("search#" + parts[0] + "#" + parts[1]).replace(' ', '-').toLowerCase();
139+
String partitionKey = ("PROPERTY#" + parts[0] + "#" + parts[1]).replace(' ', '-');
126140
String sortKey = (parts[2] + "#" + parts[3]).replace(' ', '-').toLowerCase();
127141
return new PropertyComponents(partitionKey, sortKey);
128142
}
129143

130-
private APIGatewayProxyResponseEvent createSuccessResponse(String message) {
131-
String body = String.format("{\"result\":\"%s\"}", message);
132-
return new APIGatewayProxyResponseEvent()
133-
.withStatusCode(200)
134-
.withHeaders(Map.of("Content-Type", CONTENT_TYPE))
135-
.withBody(body);
136-
}
137144

138-
private APIGatewayProxyResponseEvent createErrorResponse(int statusCode, String message) {
139-
String body = String.format("{\"error\":\"%s\"}", message);
140-
return new APIGatewayProxyResponseEvent()
141-
.withStatusCode(statusCode)
142-
.withHeaders(Map.of("Content-Type", CONTENT_TYPE))
143-
.withBody(body);
144-
}
145145

146146
private static class PropertyComponents {
147147
final String partitionKey;
@@ -154,7 +154,10 @@ private static class PropertyComponents {
154154
}
155155

156156
private List<Property> queryTable(String partitionKey, String sortKey) throws Exception {
157+
logger.info("Starting DynamoDB query with partitionKey: {}, sortKey: {}", partitionKey, sortKey);
158+
157159
if (partitionKey == null || sortKey == null) {
160+
logger.error("Null keys provided - partitionKey: {}, sortKey: {}", partitionKey, sortKey);
158161
throw new IllegalArgumentException("Partition key and sort key cannot be null");
159162
}
160163

@@ -166,19 +169,24 @@ private List<Property> queryTable(String partitionKey, String sortKey) throws Ex
166169
.build();
167170

168171
try {
172+
logger.debug("Executing DynamoDB query on table: {}", tableName);
169173
SdkPublisher<Property> properties = propertyTable.query(request).items();
170174
CompletableFuture<Void> future = properties.subscribe(result::add);
171175
future.get();
176+
logger.info("DynamoDB query completed successfully, found {} properties", result.size());
172177
return result;
173178
} catch (DynamoDbException | InterruptedException | ExecutionException e) {
174-
logger.error("Error querying DynamoDB", e);
179+
logger.error("Error querying DynamoDB with partitionKey: {}, sortKey: {}, table: {}",
180+
partitionKey, sortKey, tableName, e);
175181
throw new Exception("Database query failed: " + e.getMessage());
176182
}
177183
}
178184

179185
@Tracing
180186
@Metrics
181187
private void sendEvent(Property property) throws JsonProcessingException {
188+
logger.info("Creating approval event for property: {}", property.getId());
189+
182190
RequestApproval event = new RequestApproval();
183191
event.setPropertyId(property.getId());
184192

@@ -189,6 +197,7 @@ private void sendEvent(Property property) throws JsonProcessingException {
189197
event.setAddress(address);
190198

191199
String eventString = objectMapper.writeValueAsString(event);
200+
logger.info("Event payload created: {}", eventString);
192201

193202
PutEventsRequestEntry requestEntry = PutEventsRequestEntry.builder()
194203
.eventBusName(eventBus)
@@ -202,8 +211,15 @@ private void sendEvent(Property property) throws JsonProcessingException {
202211
.entries(requestEntry)
203212
.build();
204213

205-
eventBridgeClient.putEvents(eventsRequest).join();
206-
logger.info("Event sent successfully for property: {}", property.getId());
214+
logger.debug("Sending event to EventBridge bus: {}", eventBus);
215+
try {
216+
eventBridgeClient.putEvents(eventsRequest).join();
217+
logger.info("Event sent successfully for property: {}", property.getId());
218+
} catch (Exception e) {
219+
logger.error("Failed to send event to EventBridge for property: {}, bus: {}",
220+
property.getId(), eventBus, e);
221+
throw e;
222+
}
207223
}
208224
}
209225

unicorn_web/SearchService/src/main/java/search/PropertySearchFunction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv
7676

7777
String partitionKey = buildPartitionKey(pathParams.get("country"), pathParams.get("city"));
7878
String sortKey = buildSortKey(input.getResource(), pathParams);
79+
logger.info("Partition Key: {}, Sort Key: {}", partitionKey, sortKey);
7980

8081
List<Property> properties = queryTable(partitionKey, sortKey);
8182
String responseBody = objectMapper.writeValueAsString(properties);
@@ -89,7 +90,7 @@ public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEv
8990
}
9091

9192
private String buildPartitionKey(String country, String city) {
92-
return ("search#" + country + "#" + city).replace(' ', '-').toLowerCase();
93+
return ("PROPERTY#" + country + "#" + city).replace(' ', '-');
9394
}
9495

9596
private String buildSortKey(String resource, Map<String, String> pathParams) {

0 commit comments

Comments
 (0)