Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-188 events_mgmt adding support for Adobe Runtime Actions as webhooks #187

Merged
merged 8 commits into from
Oct 13, 2023
1 change: 1 addition & 0 deletions core/src/main/java/com/adobe/aio/util/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class Constants {
public static final String IMS_ORG_HEADER = "x-gw-ims-org-id";
public static final String IMS_URL = "https://ims-na1.adobelogin.com";
public static final String API_MANAGEMENT_URL = "https://api.adobe.io";
public static final String AIO_EVENTS_WEBHOOK_APP_URL = "https://webhooks.adobe.io/egauditor";
francoisledroff marked this conversation as resolved.
Show resolved Hide resolved
public static final String CUSTOM_EVENTS_PROVIDER_METADATA_ID = "3rd_party_custom_events";

private Constants() {
Expand Down
93 changes: 79 additions & 14 deletions core/src/main/java/com/adobe/aio/workspace/Workspace.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,31 @@
*/
package com.adobe.aio.workspace;

import static com.adobe.aio.util.FileUtil.getMapFromProperties;
import static com.adobe.aio.util.FileUtil.readPropertiesFromClassPath;
import static com.adobe.aio.util.FileUtil.readPropertiesFromFile;

import com.adobe.aio.auth.Context;
import com.adobe.aio.auth.JwtContext;
import com.adobe.aio.util.Constants;
import java.security.PrivateKey;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;

import com.adobe.aio.auth.Context;
import com.adobe.aio.auth.JwtContext;
import com.adobe.aio.util.Constants;

import static com.adobe.aio.util.FileUtil.*;

public class Workspace {

public static final String IMS_URL = "aio_ims_url";
public static final String IMS_ORG_ID = "aio_ims_org_id";
public static final String CONSUMER_ORG_ID = "aio_consumer_org_id";
public static final String PROJECT_ID = "aio_project_id";
public static final String WORKSPACE_ID = "aio_workspace_id";
public static final String RUNTIME_NAMESPACE = "aio_runtime_namespace";
public static final String RUNTIME_ACTIONS = "aio_runtime_actions";

public static final String API_KEY = "aio_api_key";
/**
Expand Down Expand Up @@ -61,19 +66,23 @@ public class Workspace {
private final String consumerOrgId;
private final String projectId;
private final String workspaceId;
private final String runtimeNamespace;
private final List<String> runtimeActions;
francoisledroff marked this conversation as resolved.
Show resolved Hide resolved
private final Context authContext;

private Workspace(final String imsUrl, final String imsOrgId, final String apiKey,
final String consumerOrgId, final String projectId, final String workspaceId,
Context authContext) {
final String runtimeNamespace, final List<String> runtimeActions, Context authContext) {
this.imsUrl = StringUtils.isEmpty(imsUrl) ? Constants.IMS_URL : imsUrl;
this.imsOrgId = imsOrgId;

this.apiKey = apiKey;
this.consumerOrgId = consumerOrgId;
this.projectId = projectId;
this.workspaceId = workspaceId;

this.runtimeNamespace = runtimeNamespace;
this.runtimeActions = (runtimeActions != null && !runtimeActions.isEmpty())
? runtimeActions : Collections.emptyList();
this.authContext = authContext;
}

Expand Down Expand Up @@ -109,6 +118,25 @@ public void validateWorkspaceContext() throws IllegalStateException {
}
}

/**
* Validates that this workspace context is populated properly for runtime integration test.
*
* @throws IllegalStateException if any properties are not specified.
*/
public void validateWorkspaceContextForRuntime() throws IllegalStateException {
validateWorkspaceContext();
if (StringUtils.isEmpty(this.getRuntimeNamespace())) {
throw new IllegalStateException("Your `Workspace` doesn't have runtime enabled, which is required for runtime e2e");
}
if (StringUtils.isNotEmpty(this.getRuntimeNamespace())) {
if (this.getRuntimeActions() == null || this.getRuntimeActions().isEmpty()) {
throw new IllegalStateException("Your `Workspace` has runtime enabled but missing runtime actions");
} else if (this.getRuntimeActions().size() < 2) {
throw new IllegalStateException("Your `Workspace has runtime enabled and requires at least 2 runtime actions for runtime e2e`");
}
}
}

public String getProjectUrl() {
if (!StringUtils.isEmpty(this.getConsumerOrgId()) && !StringUtils.isEmpty(
this.getProjectId())) {
Expand Down Expand Up @@ -143,6 +171,14 @@ public String getWorkspaceId() {
return workspaceId;
}

public String getRuntimeNamespace() {
return runtimeNamespace;
}

public List<String> getRuntimeActions() {
return runtimeActions;
}

public Context getAuthContext() {
return authContext;
}
Expand Down Expand Up @@ -173,13 +209,15 @@ public boolean equals(Object o) {
Objects.equals(imsOrgId, workspace.imsOrgId) &&
Objects.equals(consumerOrgId, workspace.consumerOrgId) &&
Objects.equals(projectId, workspace.projectId) &&
Objects.equals(workspaceId, workspace.workspaceId);
Objects.equals(workspaceId, workspace.workspaceId) &&
Objects.equals(runtimeNamespace, workspace.runtimeNamespace) &&
Objects.equals(runtimeActions, workspace.runtimeActions);
}

@Override
public int hashCode() {
return Objects
.hash(imsUrl, imsOrgId, consumerOrgId, projectId, workspaceId);
.hash(imsUrl, imsOrgId, consumerOrgId, projectId, workspaceId, runtimeNamespace, runtimeActions);
}

@Override
Expand All @@ -191,6 +229,8 @@ public String toString() {
", apiKey='" + apiKey + '\'' +
", projectId='" + projectId + '\'' +
", workspaceId='" + workspaceId + '\'' +
", runtimeNamespace='" + runtimeNamespace + '\'' +
", runtimeActions='" + runtimeActions + '\'' +
'}';
}

Expand All @@ -202,6 +242,8 @@ public static class Builder {
private String consumerOrgId;
private String projectId;
private String workspaceId;
private String runtimeNamespace;
private List<String> runtimeActions;

private Map<String, String> workspaceProperties;

Expand Down Expand Up @@ -241,6 +283,20 @@ public Builder workspaceId(final String workspaceId) {
return this;
}

public Builder runtimeNamespace(final String runtimeNamespace) {
this.runtimeNamespace = runtimeNamespace;
return this;
}

public Builder runtimeActions(final List<String> runtimeActions) {
if (runtimeActions != null && !runtimeActions.isEmpty()) {
this.runtimeActions = runtimeActions;
} else {
this.runtimeActions = Collections.emptyList();
}
return this;
}

public Builder authContext(final Context authContext) {
this.authContext = authContext;
return this;
Expand Down Expand Up @@ -293,14 +349,23 @@ public Builder configMap(final Map<String, String> configMap) {
.apiKey(configMap.get(API_KEY))
.consumerOrgId(configMap.get(CONSUMER_ORG_ID))
.projectId(configMap.get(PROJECT_ID))
.workspaceId(configMap.get(WORKSPACE_ID));
.workspaceId(configMap.get(WORKSPACE_ID))
.runtimeNamespace(configMap.get(RUNTIME_NAMESPACE))
.runtimeActions(getRuntimeActionsFromConfig(configMap));

// For backwards compatibility - should this be kept?
jwtbuilder = JwtContext.builder();
jwtbuilder.configMap(configMap);
return this;
}

public List<String> getRuntimeActionsFromConfig(final Map<String, String> configMap) {
if (StringUtils.isNotEmpty(configMap.get(RUNTIME_ACTIONS))) {
return Arrays.asList(configMap.get(RUNTIME_ACTIONS).split("\\s*,\\s*"));
}
return Collections.emptyList();
}

public Builder systemEnv() {
return configMap(System.getenv());
}
Expand All @@ -318,12 +383,12 @@ public Builder properties(final Properties properties) {
public Workspace build() {

if (authContext != null) {
return new Workspace(imsUrl, imsOrgId, apiKey, consumerOrgId, projectId, workspaceId, authContext);
return new Workspace(imsUrl, imsOrgId, apiKey, consumerOrgId, projectId, workspaceId, runtimeNamespace, runtimeActions, authContext);
}
if (jwtbuilder == null) {
jwtbuilder = JwtContext.builder();
}
return new Workspace(imsUrl, imsOrgId, apiKey, consumerOrgId, projectId, workspaceId, jwtbuilder.build());
return new Workspace(imsUrl, imsOrgId, apiKey, consumerOrgId, projectId, workspaceId, runtimeNamespace, runtimeActions, jwtbuilder.build());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright 2023 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package com.adobe.aio.event.management.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.Objects;

/**
* Event POJO that is fetched from the AIO Event Test Webhook App (a.k.a eg-auditor) endpoint
*/
@JsonInclude(Include.NON_NULL)
public class Event {
francoisledroff marked this conversation as resolved.
Show resolved Hide resolved

private final String id;

private final String env;

private final String clientId;

private final String registrationId;

private final String timeStamp;

private final JsonNode headers;

private final JsonNode message;

@JsonCreator
public Event(@JsonProperty("id") String id, @JsonProperty("env") String env,
@JsonProperty("clientId") String clientId,
@JsonProperty("registrationId") String registrationId,
@JsonProperty("timestamp") String timeStamp,
@JsonProperty("headers") JsonNode headers,
@JsonProperty("message") JsonNode message) {
this.id = id;
this.env = env;
this.clientId = clientId;
this.registrationId = registrationId;
this.timeStamp = timeStamp;
this.headers = headers;
this.message = message;
}

public String getId() {
return id;
}

public String getEnv() {
return env;
}

public String getClientId() {
return clientId;
}

public String getRegistrationId() {
return registrationId;
}

public String getTimeStamp() {
return timeStamp;
}

public JsonNode getHeaders() {
return headers;
}

public JsonNode getMessage() {
return message;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Event)) {
return false;
}
Event event = (Event) o;
return Objects.equals(id, event.id) && Objects.equals(env, event.env)
&& Objects.equals(clientId, event.clientId) && Objects.equals(
registrationId, event.registrationId) && Objects.equals(timeStamp, event.timeStamp)
&& Objects.equals(headers, event.headers) && Objects.equals(message,
event.message);
}

@Override
public int hashCode() {
return Objects.hash(id, env, clientId, registrationId, timeStamp, headers, message);
}

@Override
public String toString() {
return "Event{" +
"id='" + id + '\'' +
", env='" + env + '\'' +
", clientId='" + clientId + '\'' +
", registrationId='" + registrationId + '\'' +
", timeStamp='" + timeStamp + '\'' +
", headers='" + headers + '\'' +
", message='" + message + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ public class RegistrationCreateModel extends RegistrationUpdateModel {
private final String clientId;

private RegistrationCreateModel(final String clientId, final String name, final String description,
final String deliveryType, final Set<EventsOfInterestInputModel> eventsOfInterestInputModels,
final String deliveryType, final String runtimeAction,
final Set<EventsOfInterestInputModel> eventsOfInterestInputModels,
final String webhookUrl, final boolean enabled) {
super(name, description, webhookUrl, eventsOfInterestInputModels, deliveryType, enabled);
super(name, description, webhookUrl, eventsOfInterestInputModels, deliveryType, runtimeAction, enabled);
if (StringUtils.isBlank(clientId)) {
throw new IllegalArgumentException(
"Registration is missing a clientId");
Expand Down Expand Up @@ -58,7 +59,7 @@ public String getClientId() {

@Override
public int hashCode() {
return Objects.hash(clientId, name, description, deliveryType, eventsOfInterestInputModels, webhookUrl, enabled);
return Objects.hash(clientId, name, description, deliveryType, runtimeAction, eventsOfInterestInputModels, webhookUrl, enabled);
}

@Override
Expand All @@ -68,6 +69,7 @@ public String toString() {
", name='" + name + '\'' +
", description='" + description + '\'' +
", deliveryType=" + deliveryType +
", runtimeAction=" + runtimeAction +
", eventsOfInterestInputModels=" + eventsOfInterestInputModels +
", webhookUrl='" + webhookUrl + '\'' +
", enabled='" + enabled + '\'' +
Expand All @@ -90,8 +92,8 @@ public Builder clientId(String clientId) {

@Override
public RegistrationCreateModel build() {
return new RegistrationCreateModel(clientId, name, description, deliveryType, eventsOfInterestInputModels,
webhookUrl, enabled);
return new RegistrationCreateModel(clientId, name, description, deliveryType, runtimeAction,
eventsOfInterestInputModels, webhookUrl, enabled);
}
}
}
Loading