added svcapi ui and camunda code
Signed-off-by: Rohan Patel <rp5811@att.com>
Change-Id: I197b4b40fe3d047a417479214e471ae26d51fb2b
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/Application.java b/otf-service-api/src/main/java/org/oran/otf/api/Application.java
new file mode 100644
index 0000000..8836555
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/Application.java
@@ -0,0 +1,74 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api;
+
+import static com.google.common.collect.Sets.newHashSet;
+
+import io.swagger.v3.oas.annotations.OpenAPIDefinition;
+import io.swagger.v3.oas.annotations.info.Contact;
+import io.swagger.v3.oas.annotations.info.Info;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@SpringBootApplication
+@Configuration
+@EnableAutoConfiguration(
+ exclude = {
+ ErrorMvcAutoConfiguration.class,
+ DataSourceAutoConfiguration.class,
+ HibernateJpaAutoConfiguration.class,
+ })
+@ComponentScan(basePackages = "org.oran.otf")
+@EnableSwagger2
+@OpenAPIDefinition(
+ info =
+ @Info(
+ title = "Open Test Framework API",
+ version = "1.0",
+ description = "A RESTful API used to communicate with the OTF test control unit.",
+ contact = @Contact(url = "https://localhost:32524", name = "OTF")))
+public class Application {
+ private static final Log log = LogFactory.getLog(Application.class);
+
+ public static void main(String[] args) {
+ ApplicationContext ctx = SpringApplication.run(Application.class, args);
+ }
+
+ @Bean
+ public Docket testInstanceApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .select()
+ // .apis(testInstancePath())
+ .paths(PathSelectors.any())
+ .build()
+ .protocols(newHashSet("https"));
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/Utilities.java b/otf-service-api/src/main/java/org/oran/otf/api/Utilities.java
new file mode 100644
index 0000000..1279688
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/Utilities.java
@@ -0,0 +1,394 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api;
+
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.repository.UserRepository;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.bson.types.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public class Utilities {
+
+ public static JsonObject parseJson(String str) {
+ try {
+ return new JsonParser().parse(str).getAsJsonObject();
+ } catch (JsonParseException jpe) {
+ logger.error("Cannot parse string as Json.");
+ return null;
+ }
+ }
+
+ public static class Http {
+ public static class BuildResponse {
+ public static Response badRequest() {
+ return Response.status(400).build();
+ }
+
+ public static Response badRequestWithMessage(String msg) {
+ return Response.status(400)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(400, msg))
+ .build();
+ }
+
+ public static Response internalServerError() {
+ return Response.status(500).build();
+ }
+
+ public static Response internalServerErrorWithMessage(String msg) {
+ return Response.status(500)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(500, msg))
+ .build();
+ }
+
+ public static Response unauthorized() {
+ return Response.status(401).build();
+ }
+
+ public static Response unauthorizedWithMessage(String msg) {
+ return Response.status(401)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(401, msg))
+ .build();
+ }
+ }
+
+ public static HttpResponse httpPostJsonUsingAAF(String url, String body) throws Exception {
+ HttpResponse response = null;
+
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpPost post = new HttpPost(url);
+ post.setHeader("Content-Type", MediaType.APPLICATION_JSON);
+ post.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+ post.setEntity(new StringEntity(body));
+
+ HttpClient client =
+ HttpClientBuilder.create()
+ .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
+ .build();
+ response = client.execute(post);
+
+ // logger.info(String.format("[POST:%s]\n %s", url, body));
+
+ return response;
+ }
+
+ public static HttpResponse httpDeleteAAF(String url) {
+ HttpResponse response = null;
+
+ try {
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpDelete delete = new HttpDelete(url);
+ delete.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+ HttpClient client =
+ HttpClientBuilder.create()
+ .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
+ .build();
+ response = client.execute(delete);
+
+ // logger.info(String.format("[DELETE:%s]\n", url));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return response;
+ }
+
+ public static HttpResponse httpPostXmlUsingAAF(String url, String body) {
+ HttpResponse response = null;
+
+ try {
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpPost post = new HttpPost(url);
+ post.setHeader("Content-Type", MediaType.APPLICATION_JSON);
+ post.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+ post.setEntity(new StringEntity(body));
+
+ List<NameValuePair> urlParameters = Arrays.asList(new BasicNameValuePair("xml", body));
+ post.setEntity(new UrlEncodedFormEntity(urlParameters));
+
+ HttpClient client = HttpClientBuilder.create().build();
+ response = client.execute(post);
+
+ logger.info(String.format("[POST:%s]\n %s", url, body));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return response;
+ }
+
+ public static HttpResponse httpGetUsingAAF(String url) {
+ HttpResponse response = null;
+
+ try {
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ HttpGet get = new HttpGet(url);
+ get.setHeader("Content-Type", "application/json");
+ get.setHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()));
+
+ HttpClient client =
+ HttpClientBuilder.create()
+ .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
+ .build();
+ response = client.execute(get);
+
+ logger.info(String.format("[GET:%s]", url));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return response;
+ }
+ }
+
+ public static class Camunda {
+
+ public static boolean isCamundaOnline() {
+ final String healthUrl =
+ String.format(
+ "%s:%s/%s",
+ System.getenv("otf.camunda.host"),
+ System.getenv("otf.camunda.port"),
+ System.getenv("otf.camunda.uri.health"));
+
+ HttpResponse res = Utilities.Http.httpGetUsingAAF(healthUrl);
+ return res != null && res.getStatusLine().getStatusCode() == 200;
+ }
+
+ public static JsonObject processInstanceStatus(String executionId) {
+ // Read necessary environment variables - Avoiding using Spring dependencies (@Value)
+ String host = System.getenv("otf.camunda.host");
+ String path = System.getenv("otf.camunda.uri.process-instance-completion-check");
+ int port = Utilities.TryGetEnvironmentVariable("otf.camunda.port");
+
+ if (!Utilities.isHostValid(host)) {
+ logger.error("Host (%s) must use either the http or https protocol.", host);
+ return null;
+ }
+
+ if (!Utilities.isPortValid(port)) {
+ logger.error(
+ "Invalid port (%s) specified as environment variable 'otf.camunda.port'.",
+ System.getenv("otf.camunda.port"));
+ return null;
+ }
+ try {
+ String getUrl = String.format("%s:%s/%s/%s", host, port, path, executionId);
+ HttpResponse response = Utilities.Http.httpGetUsingAAF(getUrl);
+ HttpEntity entity = response.getEntity();
+ String result = EntityUtils.toString(entity);
+
+ return parseJson(result);
+ } catch (IOException ioe) {
+ Utilities.printStackTrace(ioe, Utilities.LogLevel.ERROR);
+ logger.error("Cannot convert http entity to String.");
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, Utilities.LogLevel.ERROR);
+ }
+ // conversion was unsuccessful
+ return null;
+ }
+ }
+
+ private static final Logger logger = LoggerFactory.getLogger(Utilities.class);
+
+ public static void printStackTrace(Exception exception, LogLevel logLevel) {
+ String stackTrace = getStackTrace(exception);
+
+ switch (logLevel) {
+ case INFO:
+ logger.info(stackTrace);
+ break;
+ case WARN:
+ logger.warn(stackTrace);
+ break;
+ case DEBUG:
+ logger.debug(stackTrace);
+ break;
+ case ERROR:
+ logger.error(stackTrace);
+ break;
+ }
+ }
+
+ public static int TryGetEnvironmentVariable(String variable) {
+ String value = System.getenv(variable);
+ int result = 0x80000000;
+
+ try {
+ result = Integer.parseInt(value);
+ } catch (NumberFormatException error) {
+ error.printStackTrace();
+ logger.error(error.getMessage());
+ }
+
+ return result;
+ }
+
+ public static String getStackTrace(Exception exception) {
+ StringWriter stringWriter = new StringWriter();
+ exception.printStackTrace(new PrintWriter(stringWriter));
+ return stringWriter.toString();
+ }
+
+ public static boolean isObjectIdValid(String input) {
+ ObjectId id = null;
+ try {
+ id = new ObjectId(input); // check if an ObjectId can be created from the string
+ if (id.toString().equalsIgnoreCase(input)) return true;
+ logger.warn("The input string does not have the same value as it's string representation.");
+ } catch (IllegalArgumentException e) {
+ logger.error(String.format("An ObjectId cannot be instantiated from the string: %s", input));
+ }
+
+ return false;
+ }
+
+ public static boolean isPortValid(int port) {
+ return (port >= 0 && port <= 65535);
+ }
+
+ public static boolean isHostValid(String host) {
+ return host.startsWith("http");
+ }
+
+ public static <T> boolean identifierExistsInCollection(
+ MongoRepository<T, String> repository, ObjectId identifier) {
+ return repository.findById(identifier.toString()).isPresent();
+ }
+
+ public static <T> T findByIdGeneric(MongoRepository<T, String> repository, ObjectId identifier) {
+ Optional<T> optionalObj = repository.findById(identifier.toString());
+ return optionalObj.orElse(null);
+ }
+
+ public static String[] decodeBase64AuthorizationHeader(String encodedHeader) {
+ try {
+ byte[] decodedAuthorization = Base64.getDecoder().decode(encodedHeader.replace("Basic ", ""));
+ String credentials = new String(decodedAuthorization);
+ return credentials.split(":");
+ } catch (Exception e) {
+ logger.error("Unable to decode authorization header: " + encodedHeader);
+ return null;
+ }
+ }
+
+ public static User findUserByMechanizedId(String mechanizedId, UserRepository userRepository) {
+ Optional<User> optionalUser = userRepository.findFirstByEmail(mechanizedId);
+ return optionalUser.orElse(null);
+ }
+
+ public static User findUserByAuthHeader(String authorization, UserRepository userRepository) {
+ try {
+ if (Strings.isNullOrEmpty(authorization)) {
+ return null;
+ }
+ String[] credentials = Utilities.decodeBase64AuthorizationHeader(authorization);
+ return findUserByMechanizedId(credentials[0], userRepository);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static <T> T resolveOptional(Optional<T> optional) {
+ return optional.orElse(null);
+ }
+
+ public static <T> T mapRequest(Class<T> targetType, String input) {
+ logger.info(targetType.getName());
+
+ ObjectMapper mapper =
+ new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ try {
+ return mapper.readValue(input, targetType);
+ } catch (IOException e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return null;
+ }
+ }
+
+ public enum LogLevel {
+ WARN,
+ DEBUG,
+ INFO,
+ ERROR
+ }
+
+ public static Date getCurrentDate() {
+ return new Date(System.currentTimeMillis());
+ }
+
+ public static Map<String, Object> replaceObjectId(Map<String, Object> map, String objectIdKey) {
+ if (map.containsKey(objectIdKey)) {
+ ObjectId id = (ObjectId) map.get(objectIdKey);
+ map.replace(objectIdKey, id.toString());
+ }
+
+ return map;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/CadiFilterConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/CadiFilterConfiguration.java
new file mode 100644
index 0000000..d98b9ed
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/CadiFilterConfiguration.java
@@ -0,0 +1,119 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import javax.servlet.Filter;
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.config.Config;
+import org.onap.aaf.cadi.filter.CadiFilter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+@PropertySource("classpath:application.properties")
+@Component
+@ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true",matchIfMissing = true)
+public class CadiFilterConfiguration {
+
+ @Value("${aaf.call-timeout}")
+ private String AAF_CALL_TIMEOUT;
+
+ @Value("${aaf.conn-timeout}")
+ private String AAF_CONN_TIMEOUT;
+
+ @Value("${aaf.default-realm}")
+ private String AAF_DEFAULT_REALM;
+
+ @Value("${aaf.env}")
+ private String AAF_ENV;
+
+ @Value("${aaf.locate-url}")
+ private String AAF_LOCATE_URL;
+
+ @Value("${aaf.lur-class}")
+ private String AAF_LUR_CLASS;
+
+ @Value("${aaf.url}")
+ private String AAF_URL;
+
+ @Value("${basic-realm}")
+ private String BASIC_REALM;
+
+ @Value("${basic-warn}")
+ private String BASIC_WARN;
+
+ @Value("${cadi-latitude}")
+ private String CADI_LATITUDE;
+
+ @Value("${cadi-longitude}")
+ private String CADI_LONGITUDE;
+
+ @Value("${cadi-protocols}")
+ private String CADI_PROTOCOLS;
+
+ @Value("${cadi-noauthn}")
+ private String CADI_NOAUTHN;
+
+ @Bean(name = "cadiFilterRegistrationBean")
+ @ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true",matchIfMissing = true)
+ public FilterRegistrationBean<Filter> cadiFilterRegistration() {
+ FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
+ // set cadi configuration properties
+ initCadiProperties(registration);
+
+ registration.addUrlPatterns("/otf/api/testInstance/*", "/otf/api/testExecution/*", "/otf/api/testStrategy/*", "/otf/api/virtualTestHead/*");
+ registration.setFilter(cadiFilter());
+ registration.setName("otfCadiFilter");
+ registration.setOrder(0);
+ return registration;
+ }
+
+ public Filter cadiFilter() {
+ return new CadiFilter();
+ }
+
+ private void initCadiProperties(FilterRegistrationBean<Filter> registration) {
+ registration.addInitParameter(Config.AAF_APPID, System.getenv("AAF_ID"));
+ registration.addInitParameter(Config.AAF_APPPASS, System.getenv("AAF_PASSWORD"));
+ registration.addInitParameter(Config.AAF_CALL_TIMEOUT, AAF_CALL_TIMEOUT);
+ registration.addInitParameter(Config.AAF_CONN_TIMEOUT, AAF_CONN_TIMEOUT);
+ registration.addInitParameter(Config.AAF_DEFAULT_REALM, AAF_DEFAULT_REALM);
+ registration.addInitParameter(Config.AAF_ENV, AAF_ENV);
+ registration.addInitParameter(Config.AAF_LOCATE_URL, AAF_LOCATE_URL);
+ registration.addInitParameter(Config.AAF_LUR_CLASS, AAF_LUR_CLASS);
+ registration.addInitParameter(
+ Config.AAF_URL, AAF_URL);
+
+ registration.addInitParameter(Config.BASIC_REALM, BASIC_REALM);
+ registration.addInitParameter(Config.BASIC_WARN, BASIC_WARN);
+
+ registration.addInitParameter(Config.CADI_KEYFILE, System.getenv("CADI_KEYFILE"));
+ registration.addInitParameter(Config.CADI_LATITUDE, CADI_LATITUDE);
+ //registration.addInitParameter(Config.CADI_LOGLEVEL, Access.Level.DEBUG.name());
+ registration.addInitParameter(Config.CADI_LONGITUDE, CADI_LONGITUDE);
+ registration.addInitParameter(Config.CADI_NOAUTHN, CADI_NOAUTHN);
+ registration.addInitParameter(Config.CADI_PROTOCOLS, CADI_PROTOCOLS);
+ registration.addInitParameter(Config.CADI_KEYSTORE, System.getenv("OTF_CERT_PATH"));
+ registration.addInitParameter(Config.CADI_KEYSTORE_PASSWORD, System.getenv("OTF_CERT_PASS"));
+
+ registration.addInitParameter(Config.HOSTNAME, System.getenv("CADI_HOSTNAME"));
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/CombinedResourceProvider.java b/otf-service-api/src/main/java/org/oran/otf/api/config/CombinedResourceProvider.java
new file mode 100644
index 0000000..ef7fae5
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/CombinedResourceProvider.java
@@ -0,0 +1,46 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.annotation.Resource;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+import springfox.documentation.swagger.web.InMemorySwaggerResourcesProvider;
+import springfox.documentation.swagger.web.SwaggerResource;
+import springfox.documentation.swagger.web.SwaggerResourcesProvider;
+
+@Component
+@Primary
+public class CombinedResourceProvider implements SwaggerResourcesProvider {
+
+ @Resource private InMemorySwaggerResourcesProvider inMemorySwaggerResourcesProvider;
+
+ public List<SwaggerResource> get() {
+
+ SwaggerResource jerseySwaggerResource = new SwaggerResource();
+ jerseySwaggerResource.setLocation("/otf/api/openapi.json");
+ jerseySwaggerResource.setSwaggerVersion("2.0");
+ jerseySwaggerResource.setName("Service API");
+
+ return Stream.concat(
+ Stream.of(jerseySwaggerResource), inMemorySwaggerResourcesProvider.get().stream())
+ .collect(Collectors.toList());
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/DataConfig.java b/otf-service-api/src/main/java/org/oran/otf/api/config/DataConfig.java
new file mode 100644
index 0000000..0546a7d
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/DataConfig.java
@@ -0,0 +1,83 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoClientOptions;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import java.util.ArrayList;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+@Configuration
+@EnableMongoRepositories(basePackages = "org.oran.otf.common.repository")
+@Profile("!test")
+public class DataConfig extends AbstractMongoConfiguration {
+
+ @Value("${otf.mongo.hosts}")
+ private String hosts;
+
+ @Value("${otf.mongo.username}")
+ private String username;
+
+ @Value("${otf.mongo.password}")
+ private String password;
+
+ @Value("${otf.mongo.replicaSet}")
+ private String replicaSet;
+
+ @Value("${otf.mongo.database}")
+ private String database;
+
+ public DataConfig() {}
+
+ @Override
+ protected String getDatabaseName() {
+ return database;
+ }
+
+ @Override
+ public MongoClient mongoClient() {
+ MongoCredential credential =
+ MongoCredential.createScramSha1Credential(username, database, password.toCharArray());
+
+ MongoClientOptions options =
+ MongoClientOptions.builder().sslEnabled(false).requiredReplicaSetName(replicaSet).build();
+
+ String[] hostArray = hosts.split(",");
+ ArrayList<ServerAddress> hosts = new ArrayList<>();
+
+ for (String host : hostArray) {
+ String[] hostSplit = host.split(":");
+ hosts.add(new ServerAddress(hostSplit[0], Integer.parseInt(hostSplit[1])));
+ }
+
+ return new MongoClient(hosts, credential, options);
+ }
+
+ @Override
+ @Bean
+ public MongoTemplate mongoTemplate() {
+ return new MongoTemplate(mongoClient(), database);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/HttpSecurityConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/HttpSecurityConfiguration.java
new file mode 100644
index 0000000..2646431
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/HttpSecurityConfiguration.java
@@ -0,0 +1,68 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.connector.Connector;
+import org.apache.tomcat.util.descriptor.web.SecurityCollection;
+import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties
+public class HttpSecurityConfiguration {
+ @Value("${server.port.http}")
+ private int httpPort;
+
+ @Value("${server.port}")
+ private int httpsPort;
+
+ @Value("${ssl.flag}")
+ private boolean httpsOnly;
+
+ @Bean
+ public ServletWebServerFactory servletContainer() {
+ TomcatServletWebServerFactory tomcat =
+ new TomcatServletWebServerFactory(){
+ @Override
+ protected void postProcessContext(Context context) {
+ SecurityConstraint securityConstraint = new SecurityConstraint();
+ if(httpsOnly){ securityConstraint.setUserConstraint("CONFIDENTIAL");}
+ SecurityCollection collection = new SecurityCollection();
+ collection.addPattern("/*");
+ securityConstraint.addCollection(collection);
+ context.addConstraint(securityConstraint);
+ }
+ };
+ tomcat.addAdditionalTomcatConnectors(redirectConnector());
+ return tomcat;
+ }
+
+ private Connector redirectConnector() {
+ Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
+ connector.setScheme("http");
+ connector.setPort(httpPort);
+ connector.setSecure(false);
+ if(httpsOnly) { connector.setRedirectPort(httpsPort); }
+ return connector;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/JerseyConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/JerseyConfiguration.java
new file mode 100644
index 0000000..6d06ac7
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/JerseyConfiguration.java
@@ -0,0 +1,99 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import org.oran.otf.api.service.impl.*;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.ws.rs.ApplicationPath;
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.servlet.ServletProperties;
+import org.oran.otf.api.service.impl.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Component;
+
+@Component
+@ApplicationPath("/otf/api")
+public class JerseyConfiguration extends ResourceConfig {
+ private static final Logger log = Logger.getLogger(JerseyConfiguration.class.getName());
+
+ // @Value("${spring.jersey.application-path}")
+ // private String apiPath;
+
+ // @Value("${springfox.documentation.swagger.v2.path}")
+ // private String swagger2Endpoint;
+
+ @Autowired
+ public JerseyConfiguration() {
+ registerFeatures();
+ registerEndpoints();
+ setProperties();
+
+ configureSwagger();
+ }
+
+
+ private void registerFeatures() {
+ register(MultiPartFeature.class);
+ register(new OTFLoggingFeature(Logger.getLogger(getClass().getName()), Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 8192));
+
+ }
+
+ private void registerEndpoints() {
+ register(TestInstanceServiceImpl.class);
+ register(HealthServiceImpl.class);
+ register(TestStrategyServiceImpl.class);
+ register(TestExecutionServiceImpl.class);
+ register(VirtualTestHeadServiceImpl.class);
+
+ register(OtfOpenServiceImpl.class);
+ }
+
+ private void setProperties() {
+ property(ServletProperties.FILTER_FORWARD_ON_404, true);
+ property(ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
+ }
+
+ private void configureSwagger() {
+ OpenApiResource openApiResource = new OpenApiResource();
+
+ register(openApiResource);
+ }
+
+ @Bean
+ @Primary
+ public ObjectMapper objectMapper() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
+ objectMapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
+ return objectMapper;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilter.java b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilter.java
new file mode 100644
index 0000000..aba17f0
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilter.java
@@ -0,0 +1,134 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.onap.aaf.cadi.Access;
+import org.onap.aaf.cadi.Access.Level;
+import org.onap.aaf.cadi.ServletContextAccess;
+import org.onap.aaf.cadi.util.Split;
+
+public class OTFApiEnforcementFilter implements Filter {
+ private static final Log log = LogFactory.getLog(OTFApiEnforcementFilter.class);
+ private String type;
+ private Map<String, List<String>> publicPaths;
+ private Access access = null;
+
+ public OTFApiEnforcementFilter(Access access, String enforce) throws ServletException {
+ this.access = access;
+ init(enforce);
+ }
+
+ @Override
+ public void init(FilterConfig fc) throws ServletException {
+ init(fc.getInitParameter("aaf_perm_type"));
+ // need the Context for Logging, instantiating ClassLoader, etc
+ ServletContextAccess sca = new ServletContextAccess(fc);
+ if (access == null) {
+ access = sca;
+ }
+ }
+
+ private void init(final String ptypes) throws ServletException {
+ if (Strings.isNullOrEmpty(ptypes)) {
+ throw new ServletException("OTFApiEnforcement requires aaf_perm_type property");
+ }
+ String[] full = Split.splitTrim(';', ptypes);
+ if (full.length <= 0) {
+ throw new ServletException("aaf_perm_type property is empty");
+ }
+
+ type = full[0];
+ publicPaths = new TreeMap<>();
+ if (full.length > 1) {
+ for (int i = 1; i < full.length; ++i) {
+ String[] pubArray = Split.split(':', full[i]);
+ if (pubArray.length == 2) {
+ List<String> ls = publicPaths.get(pubArray[0]);
+ if (ls == null) {
+ ls = new ArrayList<>();
+ publicPaths.put(pubArray[0], ls);
+ }
+ ls.add(pubArray[1]);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc)
+ throws IOException, ServletException {
+ HttpServletRequest hreq = (HttpServletRequest) req;
+ final String meth = hreq.getMethod();
+ String path = hreq.getContextPath(); // + hreq.getPathInfo();
+
+ if (Strings.isNullOrEmpty(path) || "null".equals(path)) {
+ path = hreq.getRequestURI().substring(hreq.getContextPath().length());
+ }
+
+ List<String> list = publicPaths.get(meth);
+ if (list != null) {
+ for (String p : publicPaths.get(meth)) {
+ if (path.startsWith(p)) {
+ access.printf(
+ Level.INFO,
+ "%s accessed public API %s %s\n",
+ hreq.getUserPrincipal().getName(),
+ meth,
+ path);
+ fc.doFilter(req, resp);
+ return;
+ }
+ }
+ }
+ if (hreq.isUserInRole(type + '|' + path + '|' + meth)) {
+ access.printf(
+ Level.INFO,
+ "%s is allowed access to %s %s\n",
+ hreq.getUserPrincipal().getName(),
+ meth,
+ path);
+ fc.doFilter(req, resp);
+ } else {
+ access.printf(
+ Level.AUDIT,
+ "%s is denied access to %s %s\n",
+ hreq.getUserPrincipal().getName(),
+ meth,
+ path);
+ ((HttpServletResponse) resp).sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+ }
+
+ @Override
+ public void destroy() {}
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilterConfiguration.java b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilterConfiguration.java
new file mode 100644
index 0000000..cd37067
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFApiEnforcementFilterConfiguration.java
@@ -0,0 +1,60 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import org.onap.aaf.cadi.Access;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+@PropertySource("classpath:application.properties")
+@Configuration
+@ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true")
+public class OTFApiEnforcementFilterConfiguration {
+
+ private Access access;
+ private FilterConfig fc;
+
+ @Bean(name = "otfApiEnforcementFilterRegistrationBean")
+ @ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true")
+ public FilterRegistrationBean<Filter> otfApiEnforcementFilterRegistration()
+ throws ServletException {
+ FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
+ initFilterParameters(registration);
+ registration.addUrlPatterns("/otf/api/testInstance/*", "/otf/api/testExecution/*", "/otf/api/testStrategy/*", "/otf/api/virtualTestHead/*");
+ registration.setFilter(otfApiEnforcementFilter());
+ registration.setName("otfApiEnforcementFilter");
+ registration.setOrder(1);
+ return registration;
+ }
+
+ @Bean(name = "otfApiEnforcementFilter")
+ @ConditionalOnProperty(prefix = "aaf",name ="enabled",havingValue = "true")
+ public Filter otfApiEnforcementFilter() throws ServletException {
+ return new OTFApiEnforcementFilter(access, System.getenv("AAF_PERM_TYPE"));
+ }
+
+ private void initFilterParameters(FilterRegistrationBean<Filter> registration) {
+ registration.addInitParameter("aaf_perm_type", System.getenv("AAF_PERM_TYPE"));
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/config/OTFLoggingFeature.java b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFLoggingFeature.java
new file mode 100644
index 0000000..c13caab
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/config/OTFLoggingFeature.java
@@ -0,0 +1,238 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.config;
+
+import org.glassfish.jersey.logging.LoggingFeature;
+import org.glassfish.jersey.message.MessageUtils;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.WriterInterceptor;
+import javax.ws.rs.ext.WriterInterceptorContext;
+import java.io.*;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class OTFLoggingFeature extends LoggingFeature implements ContainerRequestFilter, ContainerResponseFilter,
+ ClientRequestFilter, ClientResponseFilter, WriterInterceptor {
+
+ private static final boolean printEntity = true;
+ private static final int maxEntitySize = 8 * 1024;
+ private final Logger logger = Logger.getLogger("OTFLoggingFeature");
+ private static final String ENTITY_LOGGER_PROPERTY = OTFLoggingFeature.class.getName();
+ private static final String NOTIFICATION_PREFIX = "* ";
+ private static final String REQUEST_PREFIX = "> ";
+ private static final String RESPONSE_PREFIX = "< ";
+ private static final String AUTHORIZATION = "Authorization";
+ private static final String EQUAL = " = ";
+ private static final String HEADERS_SEPARATOR = ", ";
+ private static List<String> requestHeaders;
+
+ static {
+ requestHeaders = new ArrayList<>();
+ requestHeaders.add(AUTHORIZATION);
+ }
+
+ public OTFLoggingFeature(Logger logger, Level level, Verbosity verbosity, Integer maxEntitySize) {
+ super(logger, level, verbosity, maxEntitySize);
+ }
+
+ @Override
+ public boolean configure(FeatureContext context) {
+ context.register(this);
+ return true;
+ }
+
+ private Object getEmail(Object authorization){
+ try{
+ String encoded = ((String) authorization).split(" ")[1];
+ String decoded = new String(Base64.getDecoder().decode(encoded));
+ return decoded.split(":")[0];
+ }
+ catch (Exception e){
+ return authorization;
+ }
+ }
+
+ @Override
+ public void filter(final ClientRequestContext context) {
+ final StringBuilder b = new StringBuilder();
+ printHeaders(b, context.getStringHeaders());
+ printRequestLine(b, "Sending client request", context.getMethod(), context.getUri());
+
+ if (printEntity && context.hasEntity()) {
+ final OutputStream stream = new LoggingStream(b, context.getEntityStream());
+ context.setEntityStream(stream);
+ context.setProperty(ENTITY_LOGGER_PROPERTY, stream);
+ // not calling log(b) here - it will be called by the interceptor
+ } else {
+ log(b);
+ }
+ }
+
+ @Override
+ public void filter(final ClientRequestContext requestContext, final ClientResponseContext responseContext) throws IOException {
+ final StringBuilder b = new StringBuilder();
+ printResponseLine(b, "Client response received", responseContext.getStatus());
+
+ if (printEntity && responseContext.hasEntity()) {
+ responseContext.setEntityStream(logInboundEntity(b, responseContext.getEntityStream(),
+ MessageUtils.getCharset(responseContext.getMediaType())));
+ }
+ log(b);
+ }
+
+ @Override
+ public void filter(final ContainerRequestContext context) throws IOException {
+ final StringBuilder b = new StringBuilder();
+ printHeaders(b, context.getHeaders());
+ printRequestLine(b, "Server has received a request", context.getMethod(), context.getUriInfo().getRequestUri());
+
+ if (printEntity && context.hasEntity()) {
+ context.setEntityStream(logInboundEntity(b, context.getEntityStream(), MessageUtils.getCharset(context.getMediaType())));
+ }
+ log(b);
+ }
+
+ @Override
+ public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) {
+ final StringBuilder b = new StringBuilder();
+ printResponseLine(b, "Server responded with a response", responseContext.getStatus());
+
+ if (printEntity && responseContext.hasEntity()) {
+ final OutputStream stream = new LoggingStream(b, responseContext.getEntityStream());
+ responseContext.setEntityStream(stream);
+ requestContext.setProperty(ENTITY_LOGGER_PROPERTY, stream);
+ // not calling log(b) here - it will be called by the interceptor
+ } else {
+ log(b);
+ }
+ }
+
+ @Override
+ public void aroundWriteTo(final WriterInterceptorContext writerInterceptorContext) throws IOException, WebApplicationException {
+ final LoggingStream stream = (LoggingStream) writerInterceptorContext.getProperty(ENTITY_LOGGER_PROPERTY);
+ writerInterceptorContext.proceed();
+ if (stream != null) {
+ log(stream.getStringBuilder(MessageUtils.getCharset(writerInterceptorContext.getMediaType())));
+ }
+ }
+
+ private static class LoggingStream extends FilterOutputStream {
+ private final StringBuilder b;
+ private final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+
+ LoggingStream(final StringBuilder b, final OutputStream inner) {
+ super(inner);
+
+ this.b = b;
+ }
+
+ StringBuilder getStringBuilder(Charset charset) {
+ // write entity to the builder
+ final byte[] entity = byteArrayOutputStream.toByteArray();
+
+ b.append(new String(entity, 0, Math.min(entity.length, maxEntitySize), charset));
+ if (entity.length > maxEntitySize) {
+ b.append("...more...");
+ }
+ b.append('\n');
+
+ return b;
+ }
+
+ public void write(final int i) throws IOException {
+ if (byteArrayOutputStream.size() <= maxEntitySize) {
+ byteArrayOutputStream.write(i);
+ }
+ out.write(i);
+ }
+ }
+
+ private void printHeaders(StringBuilder b, MultivaluedMap<String, String> headers) {
+ for (String header : requestHeaders) {
+ if (Objects.nonNull(headers.get(header))) {
+ if(header.equalsIgnoreCase("Authorization")){
+ b.append(header).append(EQUAL).append(getEmail(headers.get(header).get(0))).append(HEADERS_SEPARATOR);
+ }
+ else{
+ b.append(header).append(EQUAL).append(headers.get(header)).append(HEADERS_SEPARATOR);
+ }
+ }
+ }
+ int lastIndex = b.lastIndexOf(HEADERS_SEPARATOR);
+ if (lastIndex != -1) {
+ b.delete(lastIndex, lastIndex + HEADERS_SEPARATOR.length());
+ b.append("\n");
+ }
+ }
+
+ private void log(final StringBuilder b) {
+ String message = b.toString();
+ if (logger != null) {
+ logger.info(message);
+ }
+ }
+
+ private void printRequestLine(final StringBuilder b, final String note, final String method, final URI uri) {
+ b.append(NOTIFICATION_PREFIX)
+ .append(note)
+ .append(" on thread ").append(Thread.currentThread().getId())
+ .append(REQUEST_PREFIX).append(method).append(" ")
+ .append(uri.toASCIIString()).append("\n");
+ }
+
+ private void printResponseLine(final StringBuilder b, final String note, final int status) {
+ b.append(NOTIFICATION_PREFIX)
+ .append(note)
+ .append(" on thread ").append(Thread.currentThread().getId())
+ .append(RESPONSE_PREFIX)
+ .append(Integer.toString(status))
+ .append("\n");
+ }
+
+ private InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) throws IOException {
+ if (!stream.markSupported()) {
+ stream = new BufferedInputStream(stream);
+ }
+ stream.mark(maxEntitySize + 1);
+ final byte[] entity = new byte[maxEntitySize + 1];
+ final int entitySize = stream.read(entity);
+ b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset));
+ if (entitySize > maxEntitySize) {
+ b.append("...more...");
+ }
+ b.append('\n');
+ stream.reset();
+ return stream;
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/exception/TestHeadNotFoundException.java b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestHeadNotFoundException.java
new file mode 100644
index 0000000..7132a88
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestHeadNotFoundException.java
@@ -0,0 +1,33 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.exception;
+
+public class TestHeadNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public TestHeadNotFoundException(String message) {
+ super(message);
+ }
+
+ public TestHeadNotFoundException(Throwable cause) {
+ super(cause);
+ }
+
+ public TestHeadNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/exception/TestParametersException.java b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestParametersException.java
new file mode 100644
index 0000000..2029f5c
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/exception/TestParametersException.java
@@ -0,0 +1,33 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.exception;
+
+public class TestParametersException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public TestParametersException(String message) {
+ super(message);
+ }
+
+ public TestParametersException(Throwable cause) {
+ super(cause);
+ }
+
+ public TestParametersException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/exception/UserNotFoundException.java b/otf-service-api/src/main/java/org/oran/otf/api/exception/UserNotFoundException.java
new file mode 100644
index 0000000..d319bcb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/exception/UserNotFoundException.java
@@ -0,0 +1,33 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.exception;
+
+public class UserNotFoundException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public UserNotFoundException(String message) {
+ super(message);
+ }
+
+ public UserNotFoundException(Throwable cause) {
+ super(cause);
+ }
+
+ public UserNotFoundException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessDeploymentHandler.java b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessDeploymentHandler.java
new file mode 100644
index 0000000..25c06b3
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessDeploymentHandler.java
@@ -0,0 +1,131 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.handler;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import java.io.InputStream;
+import java.util.Base64;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CamundaProcessDeploymentHandler {
+ private static final Logger logger =
+ LoggerFactory.getLogger(CamundaProcessDeploymentHandler.class);
+
+ private CamundaProcessDeploymentHandler() {
+ // prevent instantiation
+ }
+
+ public Response start(InputStream bpmn, InputStream compressedResources) {
+ // Read necessary environment variables - Avoiding using Spring dependencies (@Value)
+ String host = System.getenv("otf.camunda.host");
+ String path = System.getenv("otf.camunda.uri.deploy-test-strategy-zip");
+ int port = Utilities.TryGetEnvironmentVariable("otf.camunda.port");
+ String aafCredentialsDecoded =
+ System.getenv("AAF_ID") + ":" + System.getenv("AAF_MECH_PASSWORD");
+
+ if (!Utilities.isHostValid(host)) {
+ logger.error("Host (%s) must use either the http or https protocol.", host);
+ return null;
+ }
+
+ if (!Utilities.isPortValid(port)) {
+ logger.error(
+ "Invalid port (%s) specified as environment variable 'otf.camunda.port'.",
+ System.getenv("otf.camunda.port"));
+ return null;
+ }
+
+ // Form the full url
+ String postUrl = String.format("%s:%s/%s", host, port, path);
+
+ try (CloseableHttpClient httpclient =
+ HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build()) {
+
+ // build multipart upload request
+ MultipartEntityBuilder builder =
+ MultipartEntityBuilder.create()
+ .addBinaryBody("bpmn", bpmn, ContentType.DEFAULT_BINARY, "bpmn");
+
+ // add resources to the request if they were supplied
+ if (compressedResources != null) {
+ builder.addBinaryBody(
+ "resources", compressedResources, ContentType.DEFAULT_BINARY, "resources");
+ }
+
+ HttpEntity data = builder.build();
+
+ // build http request and assign multipart upload data
+ HttpUriRequest request =
+ RequestBuilder.post(postUrl)
+ .addHeader(
+ "Authorization",
+ "Basic " + Base64.getEncoder().encodeToString(aafCredentialsDecoded.getBytes()))
+ .setEntity(data)
+ .build();
+
+ System.out.println("Executing request " + request.getRequestLine());
+
+ // Create a custom response handler
+ ResponseHandler<Response> responseHandler =
+ response -> {
+ int status = response.getStatusLine().getStatusCode();
+ if (status >= 200 && status < 300) {
+ HttpEntity entity = response.getEntity();
+ String message = entity != null ? EntityUtils.toString(entity) : null;
+ return Response.ok(message).build();
+ } else if (status == 400) {
+ HttpEntity entity = response.getEntity();
+ String message =
+ entity != null
+ ? EntityUtils.toString(entity)
+ : "Supplied bpmn file is not deployable.";
+ return Utilities.Http.BuildResponse.badRequestWithMessage(message);
+ } else {
+ throw new ClientProtocolException("Unexpected response status: " + status);
+ }
+ };
+
+ Response responseBody = httpclient.execute(request, responseHandler);
+ System.out.println("----------------------------------------");
+ System.out.println(responseBody.getEntity().toString());
+
+ return responseBody;
+ } catch (HttpHostConnectException e) {
+ return ResponseUtility.Build.serviceUnavailableWithMessage(e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return ResponseUtility.Build.internalServerErrorWithMessage("Unable to deploy definition.");
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessExecutionHandler.java b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessExecutionHandler.java
new file mode 100644
index 0000000..00e26d7
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/handler/CamundaProcessExecutionHandler.java
@@ -0,0 +1,105 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.handler;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.Utilities.LogLevel;
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.model.local.WorkflowRequest;
+import org.oran.otf.common.utility.gson.Convert;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CamundaProcessExecutionHandler {
+ private static final Logger logger =
+ LoggerFactory.getLogger(CamundaProcessExecutionHandler.class);
+
+ private CamundaProcessExecutionHandler() {
+ // prevent instantiation
+ }
+
+ public Response startProcessInstance(WorkflowRequest request) throws Exception {
+ try {
+ // if (!Utilities.Camunda.isCamundaOnline()) {
+ // Utilities.Http.BuildResponse.internalServerErrorWithMessage(
+ // "Unable to start process instance because the test control unit is
+ // unavailable.");
+ // }
+
+ // Read necessary environment variables - Avoiding using Spring dependencies (@Value)
+ String host = System.getenv("otf.camunda.host");
+ String path = System.getenv("otf.camunda.uri.execute-test");
+ int port = Utilities.TryGetEnvironmentVariable("otf.camunda.port");
+
+ if (!Utilities.isHostValid(host)) {
+ logger.error(String.format("Host (%s) must use either the http or https protocol.", host));
+ return null;
+ }
+
+ if (!Utilities.isPortValid(port)) {
+ logger.error(
+ String.format(
+ "Invalid port (%s) specified as environment variable 'otf.camunda.port'.",
+ System.getenv("otf.camunda.port")));
+ return null;
+ }
+
+ // Form the URL
+ String postUrl = String.format("%s:%s/%s", host, port, path);
+
+ // Send and store the response
+ HttpResponse response = Utilities.Http.httpPostJsonUsingAAF(postUrl, request.toString());
+ // Get the entity and attempt to convert it to a TestExecution object.
+ HttpEntity entity = response.getEntity();
+ String rawEntity = EntityUtils.toString(entity);
+ ObjectMapper mapper = new ObjectMapper();
+ OTFApiResponse otfApiResponse = mapper.readValue(rawEntity, OTFApiResponse.class);
+
+ if (otfApiResponse.getStatusCode() == 400) {
+ return Response.status(400)
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(otfApiResponse.toString())
+ .build();
+ }
+
+ String jsonMessage = otfApiResponse.getMessage();
+ TestExecution testExecution =
+ Convert.jsonToObject(jsonMessage, new TypeReference<TestExecution>() {});
+ return Response.status(otfApiResponse.getStatusCode())
+ .entity(testExecution.toString())
+ .build();
+
+ } catch (HttpHostConnectException e) {
+ return ResponseUtility.Build.serviceUnavailableWithMessage(e.getMessage());
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/HealthService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/HealthService.java
new file mode 100644
index 0000000..4bd2378
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/HealthService.java
@@ -0,0 +1,54 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.local.OTFApiResponse;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Api
+@Path("/health")
+@Tag(name = "Health Service", description = "Query the availability of the API")
+@Produces({MediaType.APPLICATION_JSON})
+public interface HealthService {
+
+ @GET
+ @Path("/v1")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ summary = "Checks if the test control unit is available",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The test control unit is available",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class)))
+ })
+ Response getHealth();
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/OtfOpenService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/OtfOpenService.java
new file mode 100644
index 0000000..ec32e47
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/OtfOpenService.java
@@ -0,0 +1,35 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.springframework.stereotype.Service;
+
+@Hidden
+@Path("/")
+public interface OtfOpenService {
+ @GET
+ @Hidden
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/demo/openapi.json")
+ Response convertSwaggerFile();
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/TestExecutionService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/TestExecutionService.java
new file mode 100644
index 0000000..b1d5d5e
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/TestExecutionService.java
@@ -0,0 +1,92 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.springframework.stereotype.Component;
+
+@Component
+@Api
+@Path("/testExecution")
+@Tag(name = "Test Services", description = "")
+@Produces(MediaType.APPLICATION_JSON)
+public interface TestExecutionService {
+ @GET
+ @Path("v1/status/executionId/{executionId}")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ description = "Respond with a test execution object if it exists",
+ summary = "Find test execution log by processInstanceId",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))
+ })
+ })
+ Response getExecutionStatus(
+ @HeaderParam("Authorization") String authorization,
+ @PathParam("executionId") String executionId);
+
+ @GET
+ @Path("v1/executionId/{executionId}")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ description =
+ "Respond with a test execution object, and state of the process instance if it exists.",
+ summary = "Find test execution log by executionId",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))
+ }),
+ @ApiResponse(
+ responseCode = "404",
+ description =
+ "No process instance was found with the executionId used to query the service",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class))
+ })
+ })
+ Response getExecution(
+ @HeaderParam("Authorization") String authorization,
+ @PathParam("executionId") String executionId);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/TestInstanceService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/TestInstanceService.java
new file mode 100644
index 0000000..6b60801
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/TestInstanceService.java
@@ -0,0 +1,374 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.TestInstance;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.model.local.TestInstanceCreateRequest;
+import org.oran.otf.common.model.local.WorkflowRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.ArraySchema;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.springframework.stereotype.Component;
+
+@Component
+@Path("/testInstance")
+@Tag(name = "Test Services", description = "")
+@Produces(MediaType.APPLICATION_JSON)
+public interface TestInstanceService {
+ @POST
+ @Path("/execute/v1/id/{testInstanceId}")
+ @Operation(
+ description =
+ "Execute a test instance by it's unique identifier. Test instances can be executed"
+ + " either both synchronously and asynchronously.",
+ summary = "Execute test instance by id",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description =
+ "A successful synchronously executed test returns a test execution object",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))),
+ @ApiResponse(
+ responseCode = "201",
+ description =
+ "A successful asynchronously executed test instance returns a base test execution.",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestExecution.class))),
+ @ApiResponse(
+ responseCode = "401",
+ description =
+ "The mechanized identifier used with the request is prohibited from accessing the resource.",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ Response execute(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "objectid",
+ description = "The UUID of the test instance"))
+ @PathParam("testInstanceId")
+ String testInstanceId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ WorkflowRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the latest version of the test definition.",
+ summary = "Create test instance by test definition id",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/testDefinitionId/{testDefinitionId}")
+ Response createByTestDefinitionId(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "uuid",
+ description = "The UUID of the test definition"))
+ @PathParam("testDefinitionId")
+ String testDefinitionId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the specified version of the test definition",
+ summary = "Create test instance by test definition id and version",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/testDefinitionId/{testDefinitionId}/version/{version}")
+ Response createByTestDefinitionId(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "uuid",
+ description = "The UUID of the test definition."))
+ @PathParam("testDefinitionId")
+ String testDefinitionId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The version of the test definition used to create the instance",
+ example = "2",
+ required = true)
+ @PathParam("version")
+ int version,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the latest version of the test definition",
+ summary = "Create test instance by process definition key",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/processDefinitionKey/{processDefinitionKey}")
+ Response createByProcessDefinitionKey(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @POST
+ @Operation(
+ description = "Create a test instance using the unique process definition key and version",
+ summary = "Create test instance by process definition key and version",
+ responses = {
+ @ApiResponse(
+ responseCode = "201",
+ description = "The created Test Instance object is returned when it is created",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create/v1/processDefinitionKey/{processDefinitionKey}/version/{version}")
+ Response createByProcessDefinitionKey(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The version of the test definition used to create the instance",
+ example = "2",
+ required = true)
+ @PathParam("version")
+ int version,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization,
+ TestInstanceCreateRequest request);
+
+ @GET
+ @Operation(
+ description = "Finds a test instance by it's unique identifier",
+ summary = "Find test instance by id",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "A Test Instance object is returned if it exists",
+ content = {
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = TestInstance.class))
+ })
+ })
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/v1/id/{id}")
+ Response findById(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "A string representation of a BSON ObjectId",
+ example = "12345678912345678912345f",
+ required = true,
+ schema =
+ @Schema(
+ type = "string",
+ format = "uuid",
+ description = "The UUID of the test instance"))
+ @PathParam("id")
+ String testInstanceId,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization);
+
+ @GET
+ @Operation(
+ description = "Finds all test instance belonging to the unique process definition key",
+ summary = "Find test instance(s) by process definition key",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "An array of found Test Instance objects are returned",
+ content = {
+ @Content(
+ array = @ArraySchema(schema = @Schema(implementation = TestInstance.class)),
+ mediaType = "application/json")
+ })
+ })
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/v1/processDefinitionKey/{processDefinitionKey}")
+ Response findByProcessDefinitionKey(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization);
+
+ @GET
+ @Operation(
+ description =
+ "Finds all test instance belonging to the unique process definition key and version",
+ summary = "Find test instance(s) by process definition key and version",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "An array of found Test Instance objects are returned",
+ content = {
+ @Content(
+ array = @ArraySchema(schema = @Schema(implementation = TestInstance.class)),
+ mediaType = "application/json")
+ })
+ })
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/v1/processDefinitionKey/{processDefinitionKey}/version/{version}")
+ Response findByProcessDefinitionKeyAndVersion(
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The process definition key associated with the test definition",
+ example = "someUniqueProcessDefinitionKey",
+ required = true)
+ @PathParam("processDefinitionKey")
+ String processDefinitionKey,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "The version of the test definition used to create the instance",
+ example = "2",
+ required = true)
+ @PathParam("version")
+ String version,
+ @Parameter(
+ allowEmptyValue = false,
+ description = "Base64 encoded Application Authorization Framework credentials",
+ example = "Basic b3RmQGF0dC5jb206cGFzc3dvcmQxMjM=",
+ required = true)
+ @HeaderParam("Authorization")
+ String authorization);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/TestStrategyService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/TestStrategyService.java
new file mode 100644
index 0000000..84b2535
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/TestStrategyService.java
@@ -0,0 +1,66 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import java.io.InputStream;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+@Api
+@Hidden
+@Path("/testStrategy")
+@Tag(name = "Test Service", description = "Deploy and delete test strategies to and from the test control unit. (This documentation will only be available to the development team)")
+@Produces({MediaType.APPLICATION_JSON})
+public interface TestStrategyService {
+ @POST
+ @Hidden
+ @Path("/deploy/v1")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @Produces(MediaType.APPLICATION_JSON)
+ Response deployTestStrategy(
+ @FormDataParam("bpmn") InputStream bpmn,
+ @FormDataParam("resources") InputStream compressedResources,
+ @FormDataParam("testDefinitionId") String testDefinitionId,
+ @FormDataParam("testDefinitionDeployerId") String testDefinitionDeployerId,
+ @FormDataParam("definitionId") String definitionId,
+ @HeaderParam("Authorization") String authorization);
+
+ @DELETE
+ @Hidden
+ @Path("/delete/v1/testDefinitionId/{testDefinitionId}")
+ Response deleteByTestDefinitionId(
+ @PathParam("testDefinitionId") String testDefinitionId,
+ @HeaderParam("authorization") String authorization);
+
+ @DELETE
+ @Hidden
+ @Path("/delete/v1/deploymentId/{deploymentId}")
+ Response deleteByDeploymentId(
+ @PathParam("deploymentId") String deploymentId,
+ @HeaderParam("authorization") String authorization);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/VirtualTestHeadService.java b/otf-service-api/src/main/java/org/oran/otf/api/service/VirtualTestHeadService.java
new file mode 100644
index 0000000..9c6ed6f
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/VirtualTestHeadService.java
@@ -0,0 +1,55 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service;
+
+import org.oran.otf.common.model.TestHead;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import io.swagger.annotations.Api;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+
+@Api
+@Path("/virtualTestHead")
+@Tag(name = "Health Service", description = "Query the availability of the API")
+@Produces({MediaType.APPLICATION_JSON})
+public interface VirtualTestHeadService {
+
+ @PATCH
+ @Path("/v1/{testHeadName}")
+ @Produces({MediaType.APPLICATION_JSON})
+ @Operation(
+ summary = "Used to update fields in the virtual test head",
+ responses = {
+ @ApiResponse(
+ responseCode = "200",
+ description = "The response will include the new vth object",
+ content =
+ @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = OTFApiResponse.class)))
+ })
+ Response updateVirtualTestHead(@HeaderParam(HttpHeaders.AUTHORIZATION) String authorization, @PathParam("testHeadName") String testHeadName, TestHead newTestHead);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/HealthServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/HealthServiceImpl.java
new file mode 100644
index 0000000..ed4755a
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/HealthServiceImpl.java
@@ -0,0 +1,34 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.service.HealthService;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import javax.ws.rs.core.Response;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class HealthServiceImpl implements HealthService {
+
+ public HealthServiceImpl() {}
+
+ @Override
+ public Response getHealth() {
+ return Response.ok(new OTFApiResponse(200, "UP")).build();
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/OtfOpenServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/OtfOpenServiceImpl.java
new file mode 100644
index 0000000..bfff6bb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/OtfOpenServiceImpl.java
@@ -0,0 +1,49 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.Utilities.LogLevel;
+import org.oran.otf.api.service.OtfOpenService;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpResponse;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Service;
+
+@Service
+public class OtfOpenServiceImpl implements OtfOpenService {
+
+ @Override
+ public Response convertSwaggerFile() {
+ try {
+ HttpResponse res =
+ Utilities.Http.httpGetUsingAAF("https://localhost:8443/otf/api/openapi.json");
+ String resStr = EntityUtils.toString(res.getEntity());
+ JsonObject resJson = new JsonParser().parse(resStr).getAsJsonObject();
+ if (resJson.has("openapi")) {
+ resJson.addProperty("openapi", "3.0.0");
+ return Response.ok(resJson.toString()).build();
+ }
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ }
+
+ return Utilities.Http.BuildResponse.internalServerError();
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestExecutionServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestExecutionServiceImpl.java
new file mode 100644
index 0000000..e758c6b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestExecutionServiceImpl.java
@@ -0,0 +1,160 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.service.TestExecutionService;
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.TestExecution;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestExecutionRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.permissions.PermissionChecker;
+import org.oran.otf.common.utility.permissions.UserPermission;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import java.util.Optional;
+import java.util.UUID;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TestExecutionServiceImpl implements TestExecutionService {
+ private static final Logger logger = LoggerFactory.getLogger(TestExecutionServiceImpl.class);
+ @Autowired
+ private UserRepository userRepository;
+ @Autowired private TestExecutionRepository testExecutionRepository;
+ @Autowired private GroupRepository groupRepository;
+
+ @Override
+ public Response getExecutionStatus(String authorization, String executionId) {
+ if (authorization == null) {
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage("Missing authorization header.");
+ }
+ // check if the executionId is a valid UUID
+ try {
+ UUID.fromString(executionId);
+ } catch (IllegalArgumentException e) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Invalid execution identifier. Expected type is UUID (v4).");
+ }
+
+ // try to find the test execution
+ Optional<TestExecution> optionalTestExecution =
+ testExecutionRepository.findFirstByProcessInstanceId(executionId);
+ TestExecution testExecution = Utilities.resolveOptional(optionalTestExecution);
+ if (testExecution == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("An execution with identifier %s was not found.", executionId));
+ }
+
+ // try to find the group of the test execution
+ String testExecutionGroupId = testExecution.getGroupId().toString();
+ Optional<Group> optionalGroup = groupRepository.findById(testExecutionGroupId);
+ Group group = Utilities.resolveOptional(optionalGroup);
+ if (group == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "The group (id: %s) associated with the test execution does not exist.",
+ testExecutionGroupId));
+ }
+
+ // try to find the user for the mechanizedId used to make this request
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (user == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "No user associated with mechanized identifier used for this request.");
+ }
+ // if it doesnt have read permission then return bad request
+ if (!PermissionChecker.hasPermissionTo(user,group, UserPermission.Permission.READ,groupRepository)){
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage(
+ "Unauthorized to view this test execution.");
+ }
+ // Used the build the final response to be returned
+ JsonObject res = new JsonObject();
+ try {
+ // Parsing is required to prevent Gson from escaping all the characters of the json
+ JsonElement testExecutionParsed = new JsonParser().parse(testExecution.toString());
+ res.add("testExecution", testExecutionParsed);
+ // Get the state of the process instance using the Camunda REST API
+ JsonObject procInstStatus = Utilities.Camunda.processInstanceStatus(executionId);
+ // Extract the state of the process instance from the JSON response
+ String processInstanceState =
+ procInstStatus.getAsJsonObject("historicProcessInstance").get("state").getAsString();
+ // Add the result to the final response
+ res.addProperty("state", processInstanceState);
+ } catch (NullPointerException npe) {
+ // In the case of a null pointer exception, make it clear that the state was not able
+ // to be determined using the Camunda API.
+ logger.error("Unable to determine the live status of the test execution.");
+ res.addProperty("state", "Unable to determine");
+ }
+ // Send the response
+ return Response.ok(res.toString()).build();
+ }
+
+ @Override
+ public Response getExecution(String authorization, String processInstanceId) {
+ try {
+ UUID.fromString(processInstanceId);
+ } catch (IllegalArgumentException e) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Invalid execution identifier. Expected type is UUID (v4).");
+ }
+
+ // try to find the test execution
+ Optional<TestExecution> optionalTestExecution =
+ testExecutionRepository.findFirstByProcessInstanceId(processInstanceId);
+ TestExecution testExecution = Utilities.resolveOptional(optionalTestExecution);
+ if (testExecution == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("An execution with identifier %s was not found.", processInstanceId));
+ }
+
+ // try to find the group of the test execution
+ String testExecutionGroupId = testExecution.getGroupId().toString();
+ Optional<Group> optionalGroup = groupRepository.findById(testExecutionGroupId);
+ Group group = Utilities.resolveOptional(optionalGroup);
+ if (group == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "The group (id: %s) associated with the test execution does not exist.",
+ testExecutionGroupId));
+ }
+
+ // try to find the user for the mechanizedId used to make this request
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (user == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "No user associated with mechanized identifier used" + " for this request.");
+ }
+
+ // if it doesnt have read permission then return bad request
+ if (!PermissionChecker.hasPermissionTo(user,group,UserPermission.Permission.READ,groupRepository)){
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage(
+ "Unauthorized to view this test execution.");
+ }
+
+ return Response.ok(testExecution.toString()).build();
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java
new file mode 100644
index 0000000..d171206
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestInstanceServiceImpl.java
@@ -0,0 +1,807 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.Utilities.LogLevel;
+import org.oran.otf.api.handler.CamundaProcessExecutionHandler;
+import org.oran.otf.api.service.TestInstanceService;
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.TestDefinition;
+import org.oran.otf.common.model.TestInstance;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.model.local.TestInstanceCreateRequest;
+import org.oran.otf.common.model.local.WorkflowRequest;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestDefinitionRepository;
+import org.oran.otf.common.repository.TestInstanceRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.Utility;
+import org.oran.otf.common.utility.database.Generic;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import org.oran.otf.common.utility.permissions.PermissionChecker;
+import org.oran.otf.common.utility.permissions.UserPermission;
+import com.google.common.base.Strings;
+import org.bson.types.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.*;
+
+@Service
+public class TestInstanceServiceImpl implements TestInstanceService {
+ @Autowired
+ CamundaProcessExecutionHandler camundaProcessExecutionHandler;
+ @Autowired
+ UserRepository userRepository;
+ @Autowired
+ TestInstanceRepository testInstanceRepository;
+ @Autowired
+ TestDefinitionRepository testDefinitionRepository;
+ @Autowired
+ GroupRepository groupRepository;
+
+ private static final Logger logger = LoggerFactory.getLogger(TestInstanceServiceImpl.class);
+ private static final String logPrefix = Utility.getLoggerPrefix();
+
+ @Override
+ public Response execute(String testInstanceId, String authorization, WorkflowRequest request) {
+ try {
+ if (request == null) {
+ return ResponseUtility.Build.badRequestWithMessage("Request body is null.");
+ }
+
+ // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request
+ // response.
+ if (!Utilities.isObjectIdValid(testInstanceId)) {
+ String error =
+ String.format(
+ "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",
+ logPrefix, testInstanceId);
+ return ResponseUtility.Build.badRequestWithMessage(error);
+ }
+
+ // Create an ObjectId now that we know the provided String was valid.
+ ObjectId oiTestInstanceId = new ObjectId(testInstanceId);
+ // Check if the testInstance exists, otherwise return a not found response.
+ TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);
+ if (testInstance == null) {
+ String error =
+ String.format(
+ "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);
+ return ResponseUtility.Build.notFoundWithMessage(error);
+ }
+ // Check if the testDefinition exists.
+ TestDefinition testDefinition =
+ Generic.findByIdGeneric(testDefinitionRepository, testInstance.getTestDefinitionId());
+ if (testDefinition == null) {
+ String error =
+ String.format(
+ "%sThe testDefinition with _id, %s, was not found.",
+ logPrefix, testInstance.getTestDefinitionId().toString());
+ return ResponseUtility.Build.notFoundWithMessage(error);
+ }
+
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // If the mechanizedId is not an OTF mechanizedId, check if the user is authorized to
+ // execute
+ // the test instance. This is required because the executorId only needs to be read from the
+ // otf-frontend component. The user/group system is not fully integrated with AAF, so this
+ // is
+ // required. A better way might be to use certificates to check identities.
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ // if we cant find the test instance group then we cant check the permission
+ if (testInstanceGroup == null) {
+ return ResponseUtility.Build.
+ badRequestWithMessage(
+ String.format("Can not find test instance group, id:%s", testInstance.getGroupId().toString()));
+ }
+ // If the mechanizedId is authorized, set the executorId in the WorkflowRequest to the
+ // mechanizedId's ObjectId to make sure that the executorId isn't spoofed. Only use the
+ // executorId sent with the request if it uses the OTF mechanizedId because we "trust" it.
+ if (isOtfMechanizedIdentifier(mechanizedIdUser.getEmail()) && request.getExecutorId() != null) {
+ mechanizedIdUser = Utilities.resolveOptional(userRepository.findById(request.getExecutorId().toString()));
+ } else {
+ request.setExecutorId(mechanizedIdUser.get_id());
+ }
+ if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup, UserPermission.Permission.EXECUTE,groupRepository)) {
+ String error =
+ String.format(
+ "%sUnauthorized the execute test instance with _id, %s.",
+ logPrefix, testInstanceId);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Set the test instance _id after authorization.
+ request.setTestInstanceId(testInstance.get_id());
+
+ // Check if the test instance is disabled.
+ if (testInstance.isDisabled()) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("The test instance with identifier %s is disabled.", testInstanceId));
+ }
+ // Check if the test definition is disabled.
+ if (testDefinition.isDisabled()) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format(
+ "The test definition with identifier %s is disabled.",
+ testInstance.getTestDefinitionId().toString()));
+ }
+
+ // Send the request to Camunda.
+ return camundaProcessExecutionHandler.startProcessInstance(request);
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByTestDefinitionId(
+ String testDefinitionId, String authorization, TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (!Utilities.isObjectIdValid(testDefinitionId)) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format(
+ "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));
+ }
+ ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format("Test definition with id, %s, was not found.", testDefinitionId));
+ }
+ // Check if the mechanizedId has access to the test definition.
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have write access to the group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, true);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinitionId));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByTestDefinitionId(
+ String testDefinitionId,
+ int version,
+ String authorization,
+ TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (!Utilities.isObjectIdValid(testDefinitionId)) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format(
+ "The testDefinitionId %s is not a valid BSON ObjectId.", testDefinitionId));
+ }
+ ObjectId oiTestDefintionId = new ObjectId(testDefinitionId);
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ Generic.findByIdGeneric(testDefinitionRepository, oiTestDefintionId);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format("Test definition with id, %s, was not found.", testDefinitionId));
+ }
+ // permission checking
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+ // if not otf email and is not authorized
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+//// return ResponseUtility.Build.unauthorizedWithMessage(
+//// String.format(
+//// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+//// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+//// }
+//// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+//// return ResponseUtility.Build.unauthorizedWithMessage(
+//// String.format(
+//// "MechanizedId, %s, does not have write access to the group with name, %s",
+//// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+//// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinitionId));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByProcessDefinitionKey(
+ String processDefinitionKey, String authorization, TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (Strings.isNullOrEmpty(processDefinitionKey)) {
+ return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");
+ }
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with processDefinitionKey, %s, was not found.",
+ processDefinitionKey));
+ }
+
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+ // if not otf email and is not authorized
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have write access to the group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, Integer.MIN_VALUE, false);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinition.get_id().toString()));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response createByProcessDefinitionKey(
+ String processDefinitionKey,
+ int version,
+ String authorization,
+ TestInstanceCreateRequest request) {
+ try {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format(
+ "%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the String correctly parses as an ObjectId.
+ if (Strings.isNullOrEmpty(processDefinitionKey)) {
+ return ResponseUtility.Build.badRequestWithMessage("The processDefinitionKey is required.");
+ }
+
+ // Find the testDefinition
+ TestDefinition testDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey).orElse(null);
+ if (testDefinition == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with processDefinitionKey, %s, was not found.",
+ processDefinitionKey));
+ }
+
+ Group testDefGroup = Utilities.resolveOptional(groupRepository.findById(testDefinition.getGroupId().toString()));
+ if (testDefGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test definition's group, id: %s", testDefinition.getGroupId().toString()));
+ }
+ // if not otf email and is not authorized
+// if (PermissionChecker.hasReadPermission(mechanizedIdUser, testDefGroup, groupRepository)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have read access to test definition in group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+// if (PermissionChecker.hasWritePermission(mechanizedIdUser, testDefGroup)) {
+// return ResponseUtility.Build.unauthorizedWithMessage(
+// String.format(
+// "MechanizedId, %s, does not have write access to the group with name, %s",
+// mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+// }
+ if (PermissionChecker.hasPermissionTo(mechanizedIdUser, testDefGroup,
+ Arrays.asList(UserPermission.Permission.READ,UserPermission.Permission.WRITE),groupRepository))
+ {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "MechanizedId, %s, does not have access (read/write) to the group with name, %s",
+ mechanizedIdUser.getEmail(), testDefGroup.getGroupName()));
+ }
+ // Get the latest version of the test definition to link it with the test instance
+ BpmnInstance bpmnInstance = findBpmnInstance(testDefinition, version, false);
+ if (bpmnInstance == null) {
+ return ResponseUtility.Build.notFoundWithMessage(
+ String.format(
+ "Test definition with id, %s, does not have any versions associated with it.",
+ testDefinition.get_id().toString()));
+ }
+
+ TestInstance testInstance =
+ new TestInstance(
+ new ObjectId(),
+ request.getTestInstanceName(),
+ request.getTestInstanceDescription(),
+ testDefinition.getGroupId(),
+ testDefinition.get_id(),
+ bpmnInstance.getProcessDefinitionId(),
+ request.isUseLatestTestDefinition(),
+ false,
+ request.isSimulationMode(),
+ request.getMaxExecutionTimeInMillis(),
+ request.getPfloInput(),
+ new HashMap<>(),
+ request.getSimulationVthInput(),
+ request.getTestData(),
+ request.getVthInput(),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ mechanizedIdUser.get_id(),
+ mechanizedIdUser.get_id());
+
+ return Response.ok()
+ .type(MediaType.APPLICATION_JSON_TYPE)
+ .entity(testInstance.toString())
+ .build();
+ } catch (Exception e) {
+ Utilities.printStackTrace(e, LogLevel.ERROR);
+ return ResponseUtility.Build.internalServerError();
+ }
+ }
+
+ @Override
+ public Response findById(String testInstanceId, String authorization) {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ // Check if the testInstanceId is a valid BSON ObjectI, otherwise return a bad request
+ // response.
+ if (!Utilities.isObjectIdValid(testInstanceId)) {
+ String error =
+ String.format(
+ "%sThe testInstanceId, %s, is not a valid ObjectId (BSON).",
+ logPrefix, testInstanceId);
+ return ResponseUtility.Build.badRequestWithMessage(error);
+ }
+
+ // Create an ObjectId now that we know the provided String was valid.
+ ObjectId oiTestInstanceId = new ObjectId(testInstanceId);
+ // Check if the testInstance exists, otherwise return a not found response.
+ TestInstance testInstance = Generic.findByIdGeneric(testInstanceRepository, oiTestInstanceId);
+ if (testInstance == null) {
+ String error =
+ String.format(
+ "%sThe testInstance with _id, %s, was not found.", logPrefix, testInstanceId);
+ return ResponseUtility.Build.notFoundWithMessage(error);
+ }
+
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ if (testInstanceGroup == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Can not find test instance's group, group name :%s", testInstance.get_id().toString()));
+ }
+ if (!PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {
+ return ResponseUtility.Build.unauthorizedWithMessage(
+ String.format(
+ "User %s does not have read access to test instance group, group name: %s.",
+ mechanizedIdUser.getEmail(), testInstanceGroup.getGroupName()));
+ }
+ return Response.ok(testInstance.toString(), MediaType.APPLICATION_JSON_TYPE).build();
+ }
+
+ @Override
+ public Response findByProcessDefinitionKey(String processDefinitionKey, String authorization) {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ Optional<TestDefinition> optionalTestDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);
+ TestDefinition testDefinition = optionalTestDefinition.orElse(null);
+ if (testDefinition == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "Cannot find test instance because a test"
+ + " definition with the process definition key (%s) does not exist.",
+ processDefinitionKey));
+ }
+
+ List<TestInstance> testInstances =
+ testInstanceRepository.findAllByTestDefinitionId(testDefinition.get_id());
+ if (testInstances.isEmpty()) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "No test instances found with process " + "definition key (%s).",
+ processDefinitionKey));
+ }
+
+ List<TestInstance> result = new ArrayList<>();
+ for (TestInstance testInstance : testInstances) {
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {
+ result.add(testInstance);
+ }
+ }
+
+ return Response.ok(result.toString()).build();
+ }
+
+ @Override
+ public Response findByProcessDefinitionKeyAndVersion(
+ String processDefinitionKey, String version, String authorization) {
+ // Check if a user associated with the mechanizedId used in the authorization header exists in
+ // the database.
+ User mechanizedIdUser = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (mechanizedIdUser == null) {
+ String[] decodedAuth = Utilities.decodeBase64AuthorizationHeader(authorization);
+ if (decodedAuth == null) {
+ return ResponseUtility.Build.badRequestWithMessage(
+ String.format("Unable to decode authorization header: %s", authorization));
+ }
+ String error =
+ String.format("%sMechanizedId is not onboarded with OTF. %s.", logPrefix, decodedAuth[0]);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ Optional<TestDefinition> optionalTestDefinition =
+ testDefinitionRepository.findByProcessDefinitionKey(processDefinitionKey);
+ TestDefinition testDefinition = optionalTestDefinition.orElse(null);
+
+ if (testDefinition == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "Cannot find test instance because a test"
+ + " definition with the process definition key (%s) does not exist.",
+ processDefinitionKey));
+ }
+
+ int iVersion;
+ try {
+ iVersion = Integer.parseInt(version);
+ } catch (NumberFormatException nfe) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage("Version must be a valid integer.");
+ }
+
+ BpmnInstance bpmnInstance =
+ testDefinition.getBpmnInstances().stream()
+ .filter(_bpmnInstance -> _bpmnInstance.getVersion() == iVersion)
+ .findAny()
+ .orElse(null);
+
+ if (bpmnInstance == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("Cannot find any test instances using " + "version %s.", version));
+ }
+
+ List<TestInstance> testInstances =
+ testInstanceRepository.findAllByTestDefinitionIdAndPDId(
+ testDefinition.get_id(), bpmnInstance.getProcessDefinitionId());
+
+ if (testInstances.isEmpty()) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "No test instances found with process " + "definition key (%s).",
+ processDefinitionKey));
+ }
+
+ List<TestInstance> result = new ArrayList<>();
+ for (TestInstance testInstance : testInstances) {
+ Group testInstanceGroup = Utilities.resolveOptional(groupRepository.findById(testInstance.getGroupId().toString()));
+ if (testInstanceGroup != null && PermissionChecker.hasPermissionTo(mechanizedIdUser,testInstanceGroup,UserPermission.Permission.READ,groupRepository)) {
+ result.add(testInstance);
+ }
+ }
+
+ return Response.ok(result.toString()).build();
+ }
+
+ private boolean isOtfMechanizedIdentifier(String email) {
+ return email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost")
+ || email.equalsIgnoreCase("email@localhost");
+ }
+
+ private BpmnInstance findBpmnInstance(TestDefinition testDefinition, int version, boolean latest)
+ throws Exception {
+ BpmnInstance bpmnInstance = null;
+ int maxVersion = Integer.MIN_VALUE;
+ // Check if the version exists
+ for (BpmnInstance bi : testDefinition.getBpmnInstances()) {
+ // If this field is null or empty, it means the bpmn hasn't been deployed, or there was a
+ // creation error on the Test Definition page (UI). Skip the field so the user isn't allowed
+ // to create a test instance based off this bpmn instance.
+ if (Strings.isNullOrEmpty(bi.getProcessDefinitionId())) {
+ continue;
+ }
+
+ // Split the processDefinitionId based on it's format:
+ // {processDefinitionKey}:{version}:{processDefinitionId}.
+ String processDefinitionId = bi.getProcessDefinitionId();
+ String[] processDefinitionIdSplit = processDefinitionId.split(":");
+ if (processDefinitionIdSplit.length != 3) {
+ throw new Exception(
+ String.format(
+ "testDefinition[%s].bpmnInstances.processDefinitionId[%s] is invalid.",
+ testDefinition.get_id().toString(), bi.getProcessDefinitionId()));
+ }
+
+ String sVersion = processDefinitionIdSplit[1];
+ int currentVersion = Integer.parseInt(sVersion);
+ if (latest && currentVersion > maxVersion) {
+ bpmnInstance = bi;
+ } else if (currentVersion == version) {
+ bpmnInstance = bi;
+ break;
+ }
+ }
+
+ return bpmnInstance;
+ }
+
+// private boolean isAuthorized(User user, Group group, String permission, GroupRepository groupRepository) {
+// if (isOtfMechanizedIdentifier(user.getEmail())) {
+// return true;
+// }
+// return PermissionChecker.isAuthorized(user, group, permission.toUpperCase(), groupRepository);
+// }
+}
+/*
+ PermissionChecker.hasReadPermission(mechanizedIdUser,testInstanceGroup,groupRepository)
+
+ PermissionChecker.hasPermission(mechanizedIdUser,testInstanceGroup,groupRepository, [READ, WRITE])
+ PermissionsMAp = PermissionChecker.Build.hasRead
+ */
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestStrategyServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestStrategyServiceImpl.java
new file mode 100644
index 0000000..13d125a
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/TestStrategyServiceImpl.java
@@ -0,0 +1,228 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.handler.CamundaProcessDeploymentHandler;
+import org.oran.otf.api.service.TestStrategyService;
+import org.oran.otf.common.model.TestDefinition;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.model.local.DeployTestStrategyRequest;
+import org.oran.otf.common.model.local.OTFApiResponse;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestDefinitionRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.v3.oas.annotations.Hidden;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Base64;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.http.HttpResponse;
+import org.apache.http.conn.HttpHostConnectException;
+import org.apache.http.util.EntityUtils;
+import org.bson.types.ObjectId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+@Hidden
+public class TestStrategyServiceImpl implements TestStrategyService {
+
+ private static final Logger logger = LoggerFactory.getLogger(TestStrategyServiceImpl.class);
+
+ @Autowired private TestDefinitionRepository testDefinitionRepository;
+
+ @Autowired private UserRepository userRepository;
+
+ @Autowired private CamundaProcessDeploymentHandler camundaProcessDeploymentHandler;
+
+ @Autowired private GroupRepository groupRepository;
+
+ public Response deployTestStrategy(
+ InputStream bpmn,
+ InputStream compressedResources,
+ String testDefinitionId,
+ String testDefinitionDeployerId,
+ String definitionId,
+ String authorization) {
+ if (bpmn == null)
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "BPMN input stream cannot be null.");
+
+ // Decode the authorization header.
+ byte[] decodedAuthorization = Base64.getDecoder().decode(authorization.replace("Basic ", ""));
+ String credentials = new String(decodedAuthorization);
+ String[] credentialsArray = credentials.split(":");
+
+ /* Check if the request came from the system specified mechanized identifier. The request goes through AAF
+ * authorization before reaching this code, therefore, assume the headers aren't spoofed. */
+ if (!credentialsArray[0].equals(System.getenv("AAF_ID")))
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Unauthorized to use this service.");
+
+ // Map to a POJO model2.
+ ObjectId _testDefinitionDeployerId = null;
+ ObjectId _testDefinitionId = null;
+
+ if (testDefinitionDeployerId != null && ObjectId.isValid(testDefinitionDeployerId))
+ _testDefinitionDeployerId = new ObjectId(testDefinitionDeployerId);
+ if (testDefinitionId != null && ObjectId.isValid(testDefinitionId))
+ _testDefinitionId = new ObjectId(testDefinitionId);
+
+ DeployTestStrategyRequest request =
+ new DeployTestStrategyRequest(_testDefinitionDeployerId, _testDefinitionId, definitionId);
+
+ // String bpmnContents = null;
+ // try (final Reader reader = new InputStreamReader(bpmn)) {
+ // bpmnContents = CharStreams.toString(reader);
+ // } catch (Exception e) {
+ // e.printStackTrace();
+ // }
+
+ // Check if the request actually contains a bpmn string.
+ // try {
+ // if (bpmnContents == null || bpmnContents.trim().length() == 0)
+ // return Utilities.Http.BuildResponse.badRequestWithMessage("BPMN contents are null.");
+ // } catch (Exception e) {
+ // logger.error(Utilities.getStackTrace(e));
+ // }
+
+ // If a test definition id is supplied, the request intends to update an existing test
+ // definition.
+ if (request.getTestDefinitionId() != null) {
+ // Check if the test definition exists in the database.
+ Optional<TestDefinition> testDefinitionOptional =
+ testDefinitionRepository.findById(request.getTestDefinitionId().toString());
+
+ if (!testDefinitionOptional.isPresent())
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("Test definition (%s) was not found.", request.getTestDefinitionId()));
+
+ // Check if a user to update the definition was supplied.
+ if (request.getTestDefinitionDeployerId() == null)
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "Must specify testDefinitionDeployerId.");
+
+ // Check if the user requesting to update the definition is the user who originally created
+ // the definition.
+ TestDefinition testDefinition = testDefinitionOptional.get();
+
+ if (!testDefinition
+ .getCreatedBy()
+ .toString()
+ .equals(request.getTestDefinitionDeployerId().toString()))
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "User (%s) is not authorized to update this test definition.",
+ request.getTestDefinitionDeployerId()));
+
+ // Check if the version to deploy already exists
+ for (BpmnInstance bpmnInstance : testDefinition.getBpmnInstances()) {
+ if (bpmnInstance.getProcessDefinitionId().equalsIgnoreCase(request.getDefinitionId()))
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "A deployment with the definitionId %s already exists.",
+ request.getDefinitionId()));
+ }
+ }
+
+ // Make the deployment request to Camunda. Relay the response received by Camunda.
+ return camundaProcessDeploymentHandler.start(bpmn, compressedResources);
+ }
+
+ public Response deleteByDeploymentId(String deploymentId, String authorization) {
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (!isAuthorized(authorization)) {
+ return Utilities.Http.BuildResponse.unauthorized();
+ }
+
+ String url =
+ String.format(
+ "%s:%s/%s/%s",
+ System.getenv("otf.camunda.host"),
+ System.getenv("otf.camunda.port"),
+ System.getenv("otf.camunda.deploymentDeletionUri"),
+ deploymentId);
+
+ try {
+ HttpResponse res = Utilities.Http.httpDeleteAAF(url);
+ String resStr = EntityUtils.toString(res.getEntity());
+ int status = res.getStatusLine().getStatusCode();
+ return Response.status(status)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(status, resStr))
+ .build();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return Utilities.Http.BuildResponse.internalServerError();
+ }
+ }
+
+ public Response deleteByTestDefinitionId(String testDefinitionId, String authorization) {
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (!isAuthorized(authorization)) {
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage("Authorization headers not set.");
+ }
+
+ String url =
+ String.format(
+ "%s:%s/%s/%s",
+ System.getenv("otf.camunda.host"),
+ System.getenv("otf.camunda.port"),
+ System.getenv("otf.camunda.testDefinitionDeletionUri"),
+ testDefinitionId);
+
+ try {
+ HttpResponse res = Utilities.Http.httpDeleteAAF(url);
+ String resStr = EntityUtils.toString(res.getEntity());
+ int status = res.getStatusLine().getStatusCode();
+ return Response.status(status)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(status, resStr))
+ .build();
+ } catch (HttpHostConnectException e) {
+ return ResponseUtility.Build.serviceUnavailableWithMessage(e.getMessage());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return Utilities.Http.BuildResponse.internalServerError();
+ }
+ }
+
+ private boolean isAuthorized(String authorization) {
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ return (user.getEmail().equalsIgnoreCase("email@localhost")
+ || user.getEmail().equalsIgnoreCase("email@localhost"));
+ }
+
+ private DeployTestStrategyRequest mapToDeployTestStrategyRequest(String body) {
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ return mapper.readValue(body, DeployTestStrategyRequest.class); // Perform the mapping
+ } catch (IOException e) { // Indicates an unknown request body
+ logger.error(e.getMessage());
+ return null;
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/api/service/impl/VirtualTestHeadServiceImpl.java b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/VirtualTestHeadServiceImpl.java
new file mode 100644
index 0000000..d2a662b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/api/service/impl/VirtualTestHeadServiceImpl.java
@@ -0,0 +1,164 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.api.service.impl;
+
+import org.oran.otf.api.Utilities;
+import org.oran.otf.api.service.VirtualTestHeadService;
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.TestHead;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+import org.oran.otf.common.repository.TestHeadRepository;
+import org.oran.otf.common.repository.UserRepository;
+import org.oran.otf.common.utility.Utility;
+import org.oran.otf.common.utility.database.Generic;
+import org.oran.otf.common.utility.http.ResponseUtility;
+import org.oran.otf.common.utility.permissions.PermissionChecker;
+import org.oran.otf.common.utility.permissions.UserPermission;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Service;
+
+import javax.ws.rs.core.Response;
+import java.util.Date;
+import java.util.Optional;
+
+@Service
+public class VirtualTestHeadServiceImpl implements VirtualTestHeadService {
+
+ @Autowired
+ private UserRepository userRepository;
+ @Autowired
+ private GroupRepository groupRepository;
+
+ @Autowired
+ TestHeadRepository testHeadRepository;
+
+ @Autowired
+ MongoTemplate mongoTemplate;
+
+ private static final String logPrefix = Utility.getLoggerPrefix();
+
+ @Override
+ public Response updateVirtualTestHead(String authorization, String testHeadName, TestHead newTestHead) {
+ if (authorization == null) {
+ return Utilities.Http.BuildResponse.unauthorizedWithMessage("Missing authorization header.");
+ }
+
+ // try to find the test head
+ Optional<TestHead> optionalTestHead =
+ testHeadRepository.findByTestHeadName(testHeadName);
+ TestHead testHead = Utilities.resolveOptional(optionalTestHead);
+ if (testHead == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format("A test head with identifier %s was not found.", testHeadName));
+ }
+
+ // try to find the group of the test head
+ String testHeadGroupId = testHead.getGroupId().toString();
+ Group testHeadGroup = Generic.findByIdGeneric(groupRepository, testHead.getGroupId());
+ if (testHeadGroup == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ String.format(
+ "The group (id: %s) associated with the test head does not exist.",
+ testHeadGroupId));
+ }
+
+ // try to find the user for the mechanizedId used to make this request
+ User user = Utilities.findUserByAuthHeader(authorization, userRepository);
+ if (user == null) {
+ return Utilities.Http.BuildResponse.badRequestWithMessage(
+ "No user associated with mechanized identifier used for this request.");
+ }
+
+ if (!PermissionChecker.hasPermissionTo(user, testHeadGroup, UserPermission.Permission.WRITE, groupRepository)) {
+ String error =
+ String.format(
+ "Unauthorized the write to test head with name, %s.",
+ testHeadGroupId);
+ return ResponseUtility.Build.unauthorizedWithMessage(error);
+ }
+
+ return updateTestHeadFields(testHead, newTestHead, user);
+ }
+
+ private Response updateTestHeadFields(TestHead testHead, TestHead newTestHead, User user) {
+ Query select = Query.query(Criteria.where("_id").is(testHead.get_id()));
+ Update update = new Update();
+
+ if (newTestHead.getTestHeadName() != null) {
+ if (doesTestHeadWithNameExist(newTestHead.getTestHeadName())) {
+ String error =
+ String.format(
+ "Cant change testHeadName to %s since it already exists.",
+ newTestHead.getTestHeadName());
+ return ResponseUtility.Build.badRequestWithMessage(error);
+ }
+ testHead.setTestHeadName(newTestHead.getTestHeadName());
+ update.set("testHeadName", newTestHead.getTestHeadName());
+ }
+ if (newTestHead.getTestHeadDescription() != null) {
+ testHead.setTestHeadDescription(newTestHead.getTestHeadDescription());
+ update.set("testHeadDescription", newTestHead.getTestHeadDescription());
+ }
+ if (newTestHead.getHostname() != null) {
+ testHead.setHostname(newTestHead.getHostname());
+ update.set("hostname", newTestHead.getHostname());
+ }
+ if (newTestHead.getPort() != null) {
+ testHead.setPort(newTestHead.getPort());
+ update.set("port", newTestHead.getPort());
+ }
+ if (newTestHead.getResourcePath() != null) {
+ testHead.setResourcePath(newTestHead.getResourcePath());
+ update.set("resourcePath", newTestHead.getResourcePath());
+ }
+ if (newTestHead.getAuthorizationType() != null) {
+ testHead.setAuthorizationType(newTestHead.getAuthorizationType());
+ update.set("authorizationType", newTestHead.getAuthorizationType());
+ }
+ if (newTestHead.getAuthorizationCredential() != null) {
+ testHead.setAuthorizationCredential(newTestHead.getAuthorizationCredential());
+ update.set("authorizationCredential", newTestHead.getAuthorizationCredential());
+ }
+ if (newTestHead.getAuthorizationEnabled() != null) {
+ testHead.setAuthorizationEnabled(newTestHead.getAuthorizationEnabled());
+ update.set("authorizationEnabled", newTestHead.getAuthorizationEnabled());
+ }
+ if (newTestHead.getVthInputTemplate() != null) {
+ testHead.setVthInputTemplate(newTestHead.getVthInputTemplate());
+ update.set("vthInputTemplate", newTestHead.getVthInputTemplate());
+ }
+ testHead.setUpdatedAt(new Date());
+ update.set("updatedAt", testHead.getUpdatedAt());
+ testHead.setUpdatedBy(user.get_id());
+ update.set("updatedBy", user.get_id());
+
+ mongoTemplate.updateFirst(select, update, "testHeads");
+ return ResponseUtility.Build.okRequestWithObject(testHead);
+ }
+
+ // check if test head exists in database by name
+ private boolean doesTestHeadWithNameExist(String name) {
+ Optional<TestHead> optionalTestHead =
+ testHeadRepository.findByTestHeadName(name);
+ return optionalTestHead.isPresent();
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/Group.java b/otf-service-api/src/main/java/org/oran/otf/common/model/Group.java
new file mode 100644
index 0000000..9214407
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/Group.java
@@ -0,0 +1,110 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.List;
+
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "groups")
+public class Group implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private ObjectId _id;
+ private String groupName;
+ private String groupDescription;
+ private List<ObjectId> mechanizedIds;
+ private ObjectId ownerId;
+ private List<Role> roles;
+ private List<GroupMember> members;
+ private ObjectId parentGroupId;
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getGroupName() {
+ return groupName;
+ }
+
+ public void setGroupName(String groupName) {
+ this.groupName = groupName;
+ }
+
+ public String getGroupDescription() {
+ return groupDescription;
+ }
+
+ public void setGroupDescription(String groupDescription) {
+ this.groupDescription = groupDescription;
+ }
+
+ public List<ObjectId> getMechanizedIds() {
+ return mechanizedIds;
+ }
+
+ public void setMechanizedIds(List<ObjectId> mechanizedIds) {
+ this.mechanizedIds = mechanizedIds;
+ }
+
+ public ObjectId getOwnerId() {
+ return ownerId;
+ }
+
+ public void setOwnerId(ObjectId ownerId) {
+ this.ownerId = ownerId;
+ }
+
+ public List<Role> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List<Role> roles) {
+ this.roles = roles;
+ }
+
+ public List<GroupMember> getMembers() {
+ return members;
+ }
+
+ public void setMembers(List<GroupMember> members) {
+ this.members = members;
+ }
+
+ public ObjectId getParentGroupId() {
+ return parentGroupId;
+ }
+
+ public void setParentGroupId(ObjectId parentGroupId) {
+ this.parentGroupId = parentGroupId;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/GroupMember.java b/otf-service-api/src/main/java/org/oran/otf/common/model/GroupMember.java
new file mode 100644
index 0000000..583c213
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/GroupMember.java
@@ -0,0 +1,43 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.bson.types.ObjectId;
+
+import java.util.List;
+import java.util.Map;
+
+public class GroupMember {
+ private ObjectId userId;
+ private List<String> roles;//this is name of roles assigned to user that are created within the group i.e admin,dev,.. etc
+
+ public ObjectId getUserId() {
+ return userId;
+ }
+
+ public void setUserId(ObjectId userId) {
+ this.userId = userId;
+ }
+
+ public List<String> getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List<String> roles) {
+ this.roles = roles;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/Role.java b/otf-service-api/src/main/java/org/oran/otf/common/model/Role.java
new file mode 100644
index 0000000..aca09f1
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/Role.java
@@ -0,0 +1,41 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import java.util.List;
+
+public class Role {
+
+ private String roleName;
+ private List<String> permissions;
+
+ public String getRoleName() {
+ return roleName;
+ }
+
+ public void setRoleName(String roleName) {
+ this.roleName = roleName;
+ }
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(List<String> permissions) {
+ this.permissions = permissions;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestDefinition.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestDefinition.java
new file mode 100644
index 0000000..2a66fa2
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestDefinition.java
@@ -0,0 +1,137 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testDefinitions")
+public class TestDefinition implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id private ObjectId _id;
+ private String testName;
+ private String testDescription;
+ private String processDefinitionKey;
+ private List<BpmnInstance> bpmnInstances;
+ private ObjectId groupId;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+ private boolean disabled;
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestName() {
+ return testName;
+ }
+
+ public void setTestName(String testName) {
+ this.testName = testName;
+ }
+
+ public String getTestDescription() {
+ return testDescription;
+ }
+
+ public void setTestDescription(String testDescription) {
+ this.testDescription = testDescription;
+ }
+
+ public String getProcessDefinitionKey() {
+ return processDefinitionKey;
+ }
+
+ public void setProcessDefinitionKey(String processDefinitionKey) {
+ this.processDefinitionKey = processDefinitionKey;
+ }
+
+ public List<BpmnInstance> getBpmnInstances() {
+ return bpmnInstances;
+ }
+
+ public void setBpmnInstances(List<BpmnInstance> bpmnInstances) {
+ this.bpmnInstances = bpmnInstances;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestExecution.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestExecution.java
new file mode 100644
index 0000000..8f02e0b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestExecution.java
@@ -0,0 +1,245 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.historic.TestDefinitionHistoric;
+import org.oran.otf.common.model.historic.TestInstanceHistoric;
+import org.oran.otf.common.model.local.TestHeadResult;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testExecutions")
+public class TestExecution implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private ObjectId _id;
+ private ObjectId groupId;
+ private ObjectId executorId;
+
+ private boolean async;
+ private Date startTime;
+ private Date endTime;
+ private String asyncTopic;
+ private String businessKey;
+ private String processInstanceId;
+ private String testResult;
+ private String testResultMessage;
+ private Map<String, Object> testDetails;
+ private List<TestHeadResult> testHeadResults;
+ private List<TestExecution> testInstanceResults;
+ // Stores historic information of associated
+ private String historicEmail;
+ private TestInstanceHistoric historicTestInstance;
+ private TestDefinitionHistoric historicTestDefinition;
+
+ public TestExecution() {
+ }
+
+ public TestExecution(
+ ObjectId _id,
+ ObjectId groupId,
+ ObjectId executorId,
+ boolean async,
+ Date startTime,
+ Date endTime,
+ String asyncTopic,
+ String businessKey,
+ String processInstanceId,
+ String testResult,
+ String testResultMessage,
+ Map<String, Object> testDetails,
+ List<TestHeadResult> testHeadResults,
+ List<TestExecution> testInstanceResults,
+ String historicEmail,
+ TestInstanceHistoric historicTestInstance,
+ TestDefinitionHistoric historicTestDefinition) {
+ this._id = _id;
+ this.groupId = groupId;
+ this.executorId = executorId;
+ this.async = async;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ this.asyncTopic = asyncTopic;
+ this.businessKey = businessKey;
+ this.processInstanceId = processInstanceId;
+ this.testResult = testResult;
+ this.testDetails = testDetails;
+ this.testHeadResults = testHeadResults;
+ this.testInstanceResults = testInstanceResults;
+ this.historicEmail = historicEmail;
+ this.historicTestInstance = historicTestInstance;
+ this.historicTestDefinition = historicTestDefinition;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public ObjectId getExecutorId() {
+ return executorId;
+ }
+
+ public void setExecutorId(ObjectId executorId) {
+ this.executorId = executorId;
+ }
+
+ public boolean isAsync() {
+ return async;
+ }
+
+ public void setAsync(boolean async) {
+ this.async = async;
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+
+ public String getAsyncTopic() {
+ return asyncTopic;
+ }
+
+ public void setAsyncTopic(String asyncTopic) {
+ this.asyncTopic = asyncTopic;
+ }
+
+ public String getBusinessKey() {
+ return businessKey;
+ }
+
+ public void setBusinessKey(String businessKey) {
+ this.businessKey = businessKey;
+ }
+
+ public String getProcessInstanceId() {
+ return processInstanceId;
+ }
+
+ public void setProcessInstanceId(String processInstanceId) {
+ this.processInstanceId = processInstanceId;
+ }
+
+ public String getTestResult() {
+ return testResult;
+ }
+
+ public void setTestResult(String testResult) {
+ this.testResult = testResult;
+ }
+
+ public String getTestResultMessage() {
+ return testResultMessage;
+ }
+
+ public void setTestResultMessage(String testResultMessage) {
+ this.testResultMessage = testResultMessage;
+ }
+
+ public Map<String, Object> getTestDetails() {
+ return testDetails;
+ }
+
+ public void setTestDetails(Map<String, Object> testDetails) {
+ this.testDetails = testDetails;
+ }
+
+ public List<TestHeadResult> getTestHeadResults() {
+ synchronized (testHeadResults) {
+ return testHeadResults;
+ }
+ }
+
+ public void setTestHeadResults(List<TestHeadResult> testHeadResults) {
+ synchronized (testHeadResults) {
+ this.testHeadResults = testHeadResults;
+ }
+ }
+
+ public List<TestExecution> getTestInstanceResults() {
+ synchronized (testInstanceResults) {
+ return testInstanceResults;
+ }
+ }
+
+ public void setTestInstanceResults(List<TestExecution> testInstanceResults) {
+ synchronized (testInstanceResults) {
+ this.testInstanceResults = testInstanceResults;
+ }
+ }
+
+ public String getHistoricEmail() {
+ return historicEmail;
+ }
+
+ public void setHistoricEmail(String historicEmail) {
+ this.historicEmail = historicEmail;
+ }
+
+ public TestInstanceHistoric getHistoricTestInstance() {
+ return historicTestInstance;
+ }
+
+ public void setHistoricTestInstance(TestInstanceHistoric historicTestInstance) {
+ this.historicTestInstance = historicTestInstance;
+ }
+
+ public TestDefinitionHistoric getHistoricTestDefinition() {
+ return historicTestDefinition;
+ }
+
+ public void setHistoricTestDefinition(
+ TestDefinitionHistoric historicTestDefinition) {
+ this.historicTestDefinition = historicTestDefinition;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestHead.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestHead.java
new file mode 100644
index 0000000..7f4bcbc
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestHead.java
@@ -0,0 +1,224 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testHeads")
+public class TestHead implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private ObjectId _id;
+
+ @Indexed(unique = true)
+ private String testHeadName;
+
+ private String testHeadDescription;
+ private String hostname;
+ private String port;
+ private String resourcePath;
+ private ObjectId creatorId;
+ private ObjectId groupId;
+ private String authorizationType;
+ private String authorizationCredential;
+ private Boolean authorizationEnabled;
+ private Map<String, Object> vthInputTemplate;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId updatedBy;
+ private Boolean isPublic;
+ public TestHead() {
+ }
+
+ public TestHead(
+ ObjectId _id,
+ String testHeadName,
+ String testHeadDescription,
+ String hostname,
+ String port,
+ String resourcePath,
+ ObjectId creatorId,
+ ObjectId groupId,
+ String authorizationType,
+ String authorizationCredential,
+ boolean authorizationEnabled,
+ Map<String, Object> vthInputTemplate,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId updatedBy,
+ Boolean isPublic) {
+ this._id = _id;
+ this.testHeadName = testHeadName;
+ this.testHeadDescription = testHeadDescription;
+ this.hostname = hostname;
+ this.port = port;
+ this.resourcePath = resourcePath;
+ this.creatorId = creatorId;
+ this.groupId = groupId;
+ this.authorizationType = authorizationType;
+ this.authorizationCredential = authorizationCredential;
+ this.authorizationEnabled = authorizationEnabled;
+ this.vthInputTemplate = vthInputTemplate;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.updatedBy = updatedBy;
+ this.isPublic = isPublic;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestHeadName() {
+ return testHeadName;
+ }
+
+ public void setTestHeadName(String testHeadName) {
+ this.testHeadName = testHeadName;
+ }
+
+ public String getTestHeadDescription() {
+ return testHeadDescription;
+ }
+
+ public void setTestHeadDescription(String testHeadDescription) {
+ this.testHeadDescription = testHeadDescription;
+ }
+
+ public String getHostname() {
+ return hostname;
+ }
+
+ public void setHostname(String hostname) {
+ this.hostname = hostname;
+ }
+
+ public String getPort() {
+ return port;
+ }
+
+ public void setPort(String port) {
+ this.port = port;
+ }
+
+ public String getResourcePath() {
+ return resourcePath;
+ }
+
+ public void setResourcePath(String resourcePath) {
+ this.resourcePath = resourcePath;
+ }
+
+ public ObjectId getCreatorId() {
+ return creatorId;
+ }
+
+ public void setCreatorId(ObjectId creatorId) {
+ this.creatorId = creatorId;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public String getAuthorizationCredential() {
+ return authorizationCredential;
+ }
+
+ public String getAuthorizationType() {
+ return authorizationType;
+ }
+
+ public void setAuthorizationType(String authorizationType) {
+ this.authorizationType = authorizationType;
+ }
+
+ public void setAuthorizationCredential(String authorizationCredential) {
+ this.authorizationCredential = authorizationCredential;
+ }
+
+ public Boolean getAuthorizationEnabled() {
+ return authorizationEnabled;
+ }
+
+ public void setAuthorizationEnabled(Boolean authorizationEnabled) {
+ this.authorizationEnabled = authorizationEnabled;
+ }
+
+ public Map<String, Object> getVthInputTemplate() {
+ return vthInputTemplate;
+ }
+
+ public void setVthInputTemplate(Map<String, Object> vthInputTemplate) {
+ this.vthInputTemplate = vthInputTemplate;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public Boolean isPublic() {
+ return isPublic;
+ }
+
+ public void setPublic(Boolean aPublic) {
+ isPublic = aPublic;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/TestInstance.java b/otf-service-api/src/main/java/org/oran/otf/common/model/TestInstance.java
new file mode 100644
index 0000000..9b11fa4
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/TestInstance.java
@@ -0,0 +1,256 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.local.ParallelFlowInput;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "testInstances")
+public class TestInstance implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private @Id ObjectId _id;
+ private String testInstanceName;
+ private String testInstanceDescription;
+ private ObjectId groupId;
+ private ObjectId testDefinitionId;
+ private String processDefinitionId;
+ private boolean useLatestTestDefinition;
+ private boolean disabled;
+ private boolean simulationMode;
+ private long maxExecutionTimeInMillis;
+ private HashMap<String, ParallelFlowInput> pfloInput;
+ private HashMap<String, Object> internalTestData;
+ private HashMap<String, Object> simulationVthInput;
+ private HashMap<String, Object> testData;
+ private HashMap<String, Object> vthInput;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+
+ public TestInstance() {}
+
+ public TestInstance(
+ ObjectId _id,
+ String testInstanceName,
+ String testInstanceDescription,
+ ObjectId groupId,
+ ObjectId testDefinitionId,
+ String processDefinitionId,
+ boolean useLatestTestDefinition,
+ boolean disabled,
+ boolean simulationMode,
+ long maxExecutionTimeInMillis,
+ HashMap<String, ParallelFlowInput> pfloInput,
+ HashMap<String, Object> internalTestData,
+ HashMap<String, Object> simulationVthInput,
+ HashMap<String, Object> testData,
+ HashMap<String, Object> vthInput,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId createdBy,
+ ObjectId updatedBy) {
+ this._id = _id;
+ this.testInstanceName = testInstanceName;
+ this.testInstanceDescription = testInstanceDescription;
+ this.groupId = groupId;
+ this.testDefinitionId = testDefinitionId;
+ this.processDefinitionId = processDefinitionId;
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ this.disabled = disabled;
+ this.simulationMode = simulationMode;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ this.pfloInput = pfloInput;
+ this.internalTestData = internalTestData;
+ this.simulationVthInput = simulationVthInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestInstanceName() {
+ return testInstanceName;
+ }
+
+ public void setTestInstanceName(String testInstanceName) {
+ this.testInstanceName = testInstanceName;
+ }
+
+ public String getTestInstanceDescription() {
+ return testInstanceDescription;
+ }
+
+ public void setTestInstanceDescription(String testInstanceDescription) {
+ this.testInstanceDescription = testInstanceDescription;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public String getProcessDefinitionId() {
+ return processDefinitionId;
+ }
+
+ public void setProcessDefinitionId(String processDefinitionId) {
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public boolean isUseLatestTestDefinition() {
+ return useLatestTestDefinition;
+ }
+
+ public void setUseLatestTestDefinition(boolean useLatestTestDefinition) {
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public boolean isSimulationMode() {
+ return simulationMode;
+ }
+
+ public void setSimulationMode(boolean simulationMode) {
+ this.simulationMode = simulationMode;
+ }
+
+ public long getMaxExecutionTimeInMillis() {
+ return maxExecutionTimeInMillis;
+ }
+
+ public void setMaxExecutionTimeInMillis(long maxExecutionTimeInMillis) {
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ }
+
+ public HashMap<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(HashMap<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public HashMap<String, Object> getInternalTestData() {
+ return internalTestData;
+ }
+
+ public void setInternalTestData(HashMap<String, Object> internalTestData) {
+ this.internalTestData = internalTestData;
+ }
+
+ public HashMap<String, Object> getSimulationVthInput() {
+ return simulationVthInput;
+ }
+
+ public void setSimulationVthInput(HashMap<String, Object> simulationVthInput) {
+ this.simulationVthInput = simulationVthInput;
+ }
+
+ public HashMap<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(HashMap<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public HashMap<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(HashMap<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/User.java b/otf-service-api/src/main/java/org/oran/otf/common/model/User.java
new file mode 100644
index 0000000..2c56b85
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/User.java
@@ -0,0 +1,142 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model;
+
+import org.oran.otf.common.model.local.UserGroup;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "users")
+public class User implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId _id;
+ private List<String> permissions;
+ private String firstName;
+ private String lastName;
+ private String email;
+ private String password;
+ private List<UserGroup> groups;
+ private Date createdAt;
+ private Date updatedAt;
+
+ //Added User for testing
+ public User(){};
+
+ public User(
+ ObjectId _id,
+ List<String> permissions,
+ String firstName,
+ String lastName,
+ String email,
+ String password,
+ List<UserGroup> groups,
+ Date createdAt,
+ Date updatedAt) {
+ this._id = _id;
+ this.permissions = permissions;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.email = email;
+ this.password = password;
+ this.groups = groups;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(List<String> permissions) {
+ this.permissions = permissions;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public List<UserGroup> getGroups() {
+ return groups;
+ }
+
+ public void setGroups(List<UserGroup> groups) {
+ this.groups = groups;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestDefinitionHistoric.java b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestDefinitionHistoric.java
new file mode 100644
index 0000000..fe2be4b
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestDefinitionHistoric.java
@@ -0,0 +1,185 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.historic;
+
+import org.oran.otf.common.model.TestDefinition;
+import org.oran.otf.common.model.local.BpmnInstance;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import org.bson.types.ObjectId;
+
+public class TestDefinitionHistoric implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId _id;
+ private String testName;
+ private String testDescription;
+ private String processDefinitionKey;
+ private List<BpmnInstance> bpmnInstances;
+ private ObjectId groupId;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+
+ public TestDefinitionHistoric() {
+ }
+
+ public TestDefinitionHistoric(TestDefinition testDefinition, String processDefinitionId) {
+ this._id = testDefinition.get_id();
+ this.testName = testDefinition.getTestName();
+ this.testDescription = testDefinition.getTestDescription();
+ this.processDefinitionKey = testDefinition.getProcessDefinitionKey();
+ this.bpmnInstances =
+ getHistoricBpmnInstanceAsList(testDefinition.getBpmnInstances(), processDefinitionId);
+ this.groupId = testDefinition.getGroupId();
+ this.createdAt = testDefinition.getCreatedAt();
+ this.updatedAt = testDefinition.getUpdatedAt();
+ this.createdBy = testDefinition.getCreatedBy();
+ this.updatedBy = testDefinition.getUpdatedBy();
+ }
+
+ public TestDefinitionHistoric(
+ ObjectId _id,
+ String testName,
+ String testDescription,
+ String processDefinitionKey,
+ List<BpmnInstance> bpmnInstances,
+ ObjectId groupId,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId createdBy,
+ ObjectId updatedBy) {
+ this._id = _id;
+ this.testName = testName;
+ this.testDescription = testDescription;
+ this.processDefinitionKey = processDefinitionKey;
+ this.bpmnInstances = bpmnInstances;
+ this.groupId = groupId;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ }
+
+ private List<BpmnInstance> getHistoricBpmnInstanceAsList(
+ List<BpmnInstance> bpmnInstances, String processDefinitionId) {
+ BpmnInstance bpmnInstance =
+ bpmnInstances.stream()
+ .filter(
+ _bpmnInstance ->
+ _bpmnInstance.getProcessDefinitionId().equalsIgnoreCase(processDefinitionId))
+ .findFirst()
+ .orElse(null);
+
+ List<BpmnInstance> historicBpmnInstance = new ArrayList<>();
+ if (bpmnInstance != null) {
+ historicBpmnInstance.add(bpmnInstance);
+ }
+
+ return historicBpmnInstance;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestName() {
+ return testName;
+ }
+
+ public void setTestName(String testName) {
+ this.testName = testName;
+ }
+
+ public String getTestDescription() {
+ return testDescription;
+ }
+
+ public void setTestDescription(String testDescription) {
+ this.testDescription = testDescription;
+ }
+
+ public String getProcessDefinitionKey() {
+ return processDefinitionKey;
+ }
+
+ public void setProcessDefinitionKey(String processDefinitionKey) {
+ this.processDefinitionKey = processDefinitionKey;
+ }
+
+ public List<BpmnInstance> getBpmnInstances() {
+ return bpmnInstances;
+ }
+
+ public void setBpmnInstances(List<BpmnInstance> bpmnInstances) {
+ this.bpmnInstances = bpmnInstances;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestInstanceHistoric.java b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestInstanceHistoric.java
new file mode 100644
index 0000000..1263893
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/historic/TestInstanceHistoric.java
@@ -0,0 +1,234 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.historic;
+
+import org.oran.otf.common.model.TestInstance;
+import org.oran.otf.common.model.local.ParallelFlowInput;
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import org.bson.types.ObjectId;
+import org.springframework.data.annotation.Id;
+
+public class TestInstanceHistoric implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private @Id
+ ObjectId _id;
+ private String testInstanceName;
+ private String testInstanceDescription;
+ private ObjectId groupId;
+ private ObjectId testDefinitionId;
+ private String processDefinitionId;
+ private Map<String, ParallelFlowInput> pfloInput;
+ private Map<String, Object> simulationVthInput;
+ private Map<String, Object> testData;
+ private Map<String, Object> vthInput;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+ private boolean simulationMode;
+
+ public TestInstanceHistoric() {
+ }
+
+ public TestInstanceHistoric(TestInstance testInstance) {
+ this._id = testInstance.get_id();
+ this.testInstanceName = testInstance.getTestInstanceName();
+ this.testInstanceDescription = testInstance.getTestInstanceDescription();
+ this.groupId = testInstance.getGroupId();
+ this.testDefinitionId = testInstance.getTestDefinitionId();
+ this.pfloInput = testInstance.getPfloInput();
+ this.processDefinitionId = testInstance.getProcessDefinitionId();
+ this.simulationVthInput = testInstance.getSimulationVthInput();
+ this.testData = testInstance.getTestData();
+ this.vthInput = testInstance.getVthInput();
+ this.createdAt = testInstance.getCreatedAt();
+ this.updatedAt = testInstance.getUpdatedAt();
+ this.createdBy = testInstance.getCreatedBy();
+ this.updatedBy = testInstance.getUpdatedBy();
+ this.simulationMode = testInstance.isSimulationMode();
+ }
+
+ public TestInstanceHistoric(
+ ObjectId _id,
+ String testInstanceName,
+ String testInstanceDescription,
+ ObjectId groupId,
+ ObjectId testDefinitionId,
+ String processDefinitionId,
+ HashMap<String, ParallelFlowInput> pfloInput,
+ HashMap<String, Object> simulationVthInput,
+ HashMap<String, Object> testData,
+ HashMap<String, Object> vthInput,
+ Date createdAt,
+ Date updatedAt,
+ ObjectId createdBy,
+ ObjectId updatedBy,
+ boolean simulationMode) {
+ this._id = _id;
+ this.testInstanceName = testInstanceName;
+ this.testInstanceDescription = testInstanceDescription;
+ this.groupId = groupId;
+ this.testDefinitionId = testDefinitionId;
+ this.processDefinitionId = processDefinitionId;
+ this.pfloInput = pfloInput;
+ this.simulationVthInput = simulationVthInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ this.simulationMode = simulationMode;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public ObjectId get_id() {
+ return _id;
+ }
+
+ public void set_id(ObjectId _id) {
+ this._id = _id;
+ }
+
+ public String getTestInstanceName() {
+ return testInstanceName;
+ }
+
+ public void setTestInstanceName(String testInstanceName) {
+ this.testInstanceName = testInstanceName;
+ }
+
+ public String getTestInstanceDescription() {
+ return testInstanceDescription;
+ }
+
+ public void setTestInstanceDescription(String testInstanceDescription) {
+ this.testInstanceDescription = testInstanceDescription;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public String getProcessDefinitionId() {
+ return processDefinitionId;
+ }
+
+ public void setProcessDefinitionId(String processDefinitionId) {
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public Map<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(
+ HashMap<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public Map<String, Object> getSimulationVthInput() {
+ return simulationVthInput;
+ }
+
+ public void setSimulationVthInput(
+ HashMap<String, Object> simulationVthInput) {
+ this.simulationVthInput = simulationVthInput;
+ }
+
+ public Map<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(HashMap<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public Map<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(HashMap<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ public boolean isSimulationMode() {
+ return simulationMode;
+ }
+
+ public void setSimulationMode(boolean simulationMode) {
+ this.simulationMode = simulationMode;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/ApiRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ApiRequest.java
new file mode 100644
index 0000000..05ec6a9
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ApiRequest.java
@@ -0,0 +1,19 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+public class ApiRequest {}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/BpmnInstance.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/BpmnInstance.java
new file mode 100644
index 0000000..c4440b0
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/BpmnInstance.java
@@ -0,0 +1,191 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+public class BpmnInstance implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private String processDefinitionId;
+ private String deploymentId;
+ private int version;
+ private ObjectId bpmnFileId;
+ private ObjectId resourceFileId;
+ private boolean isDeployed;
+ private List<TestHeadNode> testHeads;
+ private List<PfloNode> pflos;
+ private Map<String, Object> testDataTemplate;
+ private Date createdAt;
+ private Date updatedAt;
+ private ObjectId createdBy;
+ private ObjectId updatedBy;
+
+ public BpmnInstance() {
+ }
+
+ @JsonCreator
+ public BpmnInstance(
+ @JsonProperty("processDefinitionId") String processDefinitionId,
+ @JsonProperty("deploymentId") String deploymentId,
+ @JsonProperty("version") int version,
+ @JsonProperty("bpmnFileId") ObjectId bpmnFileId,
+ @JsonProperty("resourceFileId") ObjectId resourceFileId,
+ @JsonProperty("isDeployed") boolean isDeployed,
+ @JsonProperty("testHeads") List<TestHeadNode> testHeads,
+ @JsonProperty("plfos") List<PfloNode> pflos,
+ @JsonProperty("testDataTemplate") Map<String, Object> testDataTemplate,
+ @JsonProperty("createdAt") Date createdAt,
+ @JsonProperty("updateAt") Date updatedAt,
+ @JsonProperty("createdBy") ObjectId createdBy,
+ @JsonProperty("updatedBy") ObjectId updatedBy) {
+ this.processDefinitionId = processDefinitionId;
+ this.deploymentId = deploymentId;
+ this.version = version;
+ this.bpmnFileId = bpmnFileId;
+ this.resourceFileId = resourceFileId;
+ this.isDeployed = isDeployed;
+ this.testHeads = testHeads;
+ this.testDataTemplate = testDataTemplate;
+ this.createdAt = createdAt;
+ this.updatedAt = updatedAt;
+ this.createdBy = createdBy;
+ this.updatedBy = updatedBy;
+ }
+
+ public String getProcessDefinitionId() {
+ return processDefinitionId;
+ }
+
+ public void setProcessDefinitionId(String processDefinitionId) {
+ this.processDefinitionId = processDefinitionId;
+ }
+
+ public String getDeploymentId() {
+ return deploymentId;
+ }
+
+ public void setDeploymentId(String deploymentId) {
+ this.deploymentId = deploymentId;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public ObjectId getBpmnFileId() {
+ return bpmnFileId;
+ }
+
+ public void setBpmnFileId(ObjectId bpmnFileId) {
+ this.bpmnFileId = bpmnFileId;
+ }
+
+ public ObjectId getResourceFileId() {
+ return resourceFileId;
+ }
+
+ public void setResourceFileId(ObjectId resourceFileId) {
+ this.resourceFileId = resourceFileId;
+ }
+
+ @JsonProperty(value="isDeployed")
+ public boolean isDeployed() {
+ return isDeployed;
+ }
+
+ public void setDeployed(boolean deployed) {
+ isDeployed = deployed;
+ }
+
+ public List<TestHeadNode> getTestHeads() {
+ return testHeads;
+ }
+
+ public void setTestHeads(List<TestHeadNode> testHeads) {
+ this.testHeads = testHeads;
+ }
+
+ public List<PfloNode> getPflos() {
+ return pflos;
+ }
+
+ public void setPflos(List<PfloNode> pflos) {
+ this.pflos = pflos;
+ }
+
+ public Map<String, Object> getTestDataTemplate() {
+ return testDataTemplate;
+ }
+
+ public void setTestDataTemplate(Map<String, Object> testDataTemplate) {
+ this.testDataTemplate = testDataTemplate;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public void setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public void setUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public ObjectId getUpdatedBy() {
+ return updatedBy;
+ }
+
+ public void setUpdatedBy(ObjectId updatedBy) {
+ this.updatedBy = updatedBy;
+ }
+
+ private String getObjectIdString(ObjectId value) {
+ return value == null ? "\"\"" : "\"" + value.toString() + "\"";
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/DeployTestStrategyRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/DeployTestStrategyRequest.java
new file mode 100644
index 0000000..16040e7
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/DeployTestStrategyRequest.java
@@ -0,0 +1,73 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.bson.types.ObjectId;
+
+public class DeployTestStrategyRequest {
+ private ObjectId testDefinitionDeployerId;
+ private ObjectId testDefinitionId;
+ private String definitionId;
+
+ public DeployTestStrategyRequest() {}
+
+ public DeployTestStrategyRequest(
+ ObjectId testDefinitionDeployerId, ObjectId testDefinitionId, String definitionId) {
+ this.testDefinitionDeployerId = testDefinitionDeployerId;
+ this.testDefinitionId = testDefinitionId;
+ this.definitionId = definitionId;
+ }
+
+ public ObjectId getTestDefinitionDeployerId() {
+ return testDefinitionDeployerId;
+ }
+
+ public void setTestDefinitionDeployerId(ObjectId testDefinitionDeployerId) {
+ this.testDefinitionDeployerId = testDefinitionDeployerId;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public String getDefinitionId() {
+ return definitionId;
+ }
+
+ public void setDefinitionId(String definitionId) {
+ this.definitionId = definitionId;
+ }
+
+ @Override
+ public String toString() {
+ return "{\"DeployTestStrategyRequest\":{"
+ + "\"testDefinitionDeployerId\":\""
+ + testDefinitionDeployerId
+ + "\""
+ + ", \"testDefinitionId\":\""
+ + testDefinitionId
+ + "\""
+ + ", \"definitionId\":\""
+ + definitionId
+ + "\""
+ + "}}";
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/OTFApiResponse.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/OTFApiResponse.java
new file mode 100644
index 0000000..e4f959e
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/OTFApiResponse.java
@@ -0,0 +1,66 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+
+import java.util.Date;
+
+public class OTFApiResponse {
+
+ private int statusCode;
+ private String message;
+ private Date time;
+
+ public OTFApiResponse() {
+ }
+
+ public OTFApiResponse(int statusCode, String message) {
+ this.statusCode = statusCode;
+ this.message = message;
+ this.time = new Date(System.currentTimeMillis());
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Date getTime() {
+ return time;
+ }
+
+ public void setTime(Date time) {
+ this.time = time;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/ParallelFlowInput.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ParallelFlowInput.java
new file mode 100644
index 0000000..2ac94e1
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/ParallelFlowInput.java
@@ -0,0 +1,83 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class ParallelFlowInput implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private List<WorkflowRequest> args;
+ private boolean interruptOnFailure;
+ private int maxFailures;
+ private int threadPoolSize;
+
+ public ParallelFlowInput() {}
+
+ public ParallelFlowInput(
+ List<WorkflowRequest> args, boolean interruptOnFailure, int maxFailures, int threadPoolSize) {
+ this.args = args;
+ this.interruptOnFailure = interruptOnFailure;
+ this.maxFailures = maxFailures;
+ this.threadPoolSize = threadPoolSize;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public List<WorkflowRequest> getArgs() {
+ return args;
+ }
+
+ public void setArgs(List<WorkflowRequest> args) {
+ this.args = args;
+ }
+
+ public boolean isInterruptOnFailure() {
+ return interruptOnFailure;
+ }
+
+ public void setInterruptOnFailure(boolean interruptOnFailure) {
+ this.interruptOnFailure = interruptOnFailure;
+ }
+
+ public int getMaxFailures() {
+ return maxFailures;
+ }
+
+ public void setMaxFailures(int maxFailures) {
+ this.maxFailures = maxFailures;
+ }
+
+ public int getThreadPoolSize() {
+ return threadPoolSize;
+ }
+
+ public void setThreadPoolSize(int threadPoolSize) {
+ this.threadPoolSize = threadPoolSize;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/PfloNode.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/PfloNode.java
new file mode 100644
index 0000000..d8a8bd5
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/PfloNode.java
@@ -0,0 +1,61 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+
+import java.io.Serializable;
+
+public class PfloNode implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private String bpmnPlfoTaskId;
+ private String label;
+
+ public PfloNode() {}
+
+ public PfloNode(String bpmnPlfoTaskId, String label) {
+ this.bpmnPlfoTaskId = bpmnPlfoTaskId;
+ this.label = label;
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public String getBpmnPlfoTaskId() {
+ return bpmnPlfoTaskId;
+ }
+
+ public void setBpmnPlfoTaskId(String bpmnPlfoTaskId) {
+ this.bpmnPlfoTaskId = bpmnPlfoTaskId;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadNode.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadNode.java
new file mode 100644
index 0000000..99ed995
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadNode.java
@@ -0,0 +1,58 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import org.bson.types.ObjectId;
+
+public class TestHeadNode implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId testHeadId;
+ private String bpmnVthTaskId;
+
+ public TestHeadNode() {
+ }
+
+ public TestHeadNode(ObjectId testHeadId, String taskId) {
+ this.testHeadId = testHeadId;
+ this.bpmnVthTaskId = taskId;
+ }
+
+ public ObjectId getTestHeadId() {
+ return testHeadId;
+ }
+
+ public void setTestHeadId(ObjectId testHeadId) {
+ this.testHeadId = testHeadId;
+ }
+
+ public String getBpmnVthTaskId() {
+ return bpmnVthTaskId;
+ }
+
+ public void setBpmnVthTaskId(String bpmnVthTaskId) {
+ this.bpmnVthTaskId = bpmnVthTaskId;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadRequest.java
new file mode 100644
index 0000000..89c7457
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadRequest.java
@@ -0,0 +1,53 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import java.io.Serializable;
+import java.util.Map;
+
+public class TestHeadRequest implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private Map<String, String> headers;
+ private Map<String, Object> body;
+
+ public TestHeadRequest(){}
+
+ public TestHeadRequest(Map<String, String> headers,
+ Map<String, Object> body) {
+ this.headers = headers;
+ this.body = body;
+ }
+
+ public Map<String, String> getHeaders() {
+ return headers;
+ }
+
+ public void setHeaders(Map<String, String> headers) {
+ this.headers = headers;
+ }
+
+ public Map<String, Object> getBody() {
+ return body;
+ }
+
+ public void setBody(Map<String, Object> body) {
+ this.body = body;
+ }
+
+
+
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadResult.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadResult.java
new file mode 100644
index 0000000..55f82e9
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestHeadResult.java
@@ -0,0 +1,146 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import org.bson.types.ObjectId;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+public class TestHeadResult implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId testHeadId;
+ private String testHeadName;
+ private ObjectId testHeadGroupId;
+ private String bpmnVthTaskId;
+
+ //TODO: RG Remove maps below, setters and getters to return to normal
+ //private Map<String, String> testHeadHeaders;
+ //private int testHeadCode;
+ private int statusCode;
+
+ private TestHeadRequest testHeadRequest;
+ private Map<String, Object> testHeadResponse;
+ private Date startTime;
+ private Date endTime;
+
+ public TestHeadResult() {
+ }
+
+ public TestHeadResult(
+ ObjectId testHeadId,
+ String testHeadName,
+ ObjectId testHeadGroupId,
+ String bpmnVthTaskId,
+
+ //TODO: RG changed code to int and changed testHeadRequest from Map<String, String> to RequestContent
+ int statusCode,
+
+ TestHeadRequest testHeadRequest,
+ Map<String, Object> testHeadResponse,
+ Date startTime,
+ Date endTime) {
+ this.testHeadId = testHeadId;
+ this.testHeadName = testHeadName;
+ this.testHeadGroupId = testHeadGroupId;
+ this.bpmnVthTaskId = bpmnVthTaskId;
+
+ //this.testHeadHeaders = testHeadHeaders;
+ this.statusCode = statusCode;
+
+ this.testHeadRequest = testHeadRequest;
+ this.testHeadResponse = testHeadResponse;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ }
+
+ public int getStatusCode(){return statusCode;}
+ public void setStatusCode(int testHeadCode){this.statusCode = statusCode;}
+
+ public ObjectId getTestHeadId() {
+ return testHeadId;
+ }
+
+ public void setTestHeadId(ObjectId testHeadId) {
+ this.testHeadId = testHeadId;
+ }
+
+ public String getTestHeadName() {
+ return testHeadName;
+ }
+
+ public void setTestHeadName(String testHeadName) {
+ this.testHeadName = testHeadName;
+ }
+
+ public ObjectId getTestHeadGroupId() {
+ return testHeadGroupId;
+ }
+
+ public void setTestHeadGroupId(ObjectId testHeadGroupId) {
+ this.testHeadGroupId = testHeadGroupId;
+ }
+
+ public String getBpmnVthTaskId() {
+ return bpmnVthTaskId;
+ }
+
+ public void setBpmnVthTaskId(String bpmnVthTaskId) {
+ this.bpmnVthTaskId = bpmnVthTaskId;
+ }
+
+ public TestHeadRequest getTestHeadRequest() {
+ return testHeadRequest;
+ }
+
+ public void setTestHeadRequest(TestHeadRequest testHeadRequest) {
+ this.testHeadRequest = testHeadRequest;
+ }
+
+ public Map<String, Object> getTestHeadResponse() {
+ return testHeadResponse;
+ }
+
+ public void setTestHeadResponse(Map<String, Object> testHeadResponse) {
+ this.testHeadResponse = testHeadResponse;
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestInstanceCreateRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestInstanceCreateRequest.java
new file mode 100644
index 0000000..b497477
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/TestInstanceCreateRequest.java
@@ -0,0 +1,215 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import com.google.common.base.Strings;
+import java.io.Serializable;
+import java.util.HashMap;
+import org.bson.types.ObjectId;
+
+public class TestInstanceCreateRequest implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId testDefinitionId = null;
+ private int version = Integer.MIN_VALUE;
+ private String processDefinitionKey = null;
+
+ private String testInstanceName;
+ private String testInstanceDescription;
+ private HashMap<String, ParallelFlowInput> pfloInput;
+ private HashMap<String, Object> simulationVthInput;
+ private HashMap<String, Object> testData;
+ private HashMap<String, Object> vthInput;
+ private ObjectId createdBy;
+ private boolean useLatestTestDefinition = true;
+ private boolean simulationMode = false;
+ private long maxExecutionTimeInMillis = 0L;
+
+ public TestInstanceCreateRequest() throws Exception {
+ this.validate();
+ }
+
+ public TestInstanceCreateRequest(
+ String testInstanceName,
+ String testInstanceDescription,
+ HashMap<String, ParallelFlowInput> pfloInput,
+ HashMap<String, Object> simulationVthInput,
+ HashMap<String, Object> testData,
+ HashMap<String, Object> vthInput,
+ ObjectId createdBy,
+ boolean useLatestTestDefinition,
+ boolean simulationMode,
+ long maxExecutionTimeInMillis) throws Exception {
+ this.testInstanceName = testInstanceName;
+ this.testInstanceDescription = testInstanceDescription;
+ this.pfloInput = pfloInput;
+ this.simulationVthInput = simulationVthInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.createdBy = createdBy;
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ this.simulationMode = simulationMode;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+
+ this.validate();
+ }
+
+ private void validate() throws Exception {
+ String missingFieldFormat = "The field %s is required.";
+ if (Strings.isNullOrEmpty(testInstanceName)) {
+ throw new Exception(String.format(missingFieldFormat, "testInstanceName"));
+ }
+
+ if (Strings.isNullOrEmpty(testInstanceDescription)) {
+ throw new Exception(String.format(missingFieldFormat, "testInstanceDescription"));
+ }
+
+ if (pfloInput == null) {
+ pfloInput = new HashMap<>();
+ }
+
+ if (simulationVthInput == null) {
+ simulationVthInput = new HashMap<>();
+ }
+
+ if (testData == null) {
+ testData = new HashMap<>();
+ }
+
+ if (vthInput == null) {
+ vthInput = new HashMap<>();
+ }
+
+ if (this.maxExecutionTimeInMillis < 0L) {
+ this.maxExecutionTimeInMillis = 0L;
+ }
+ }
+
+ public static long getSerialVersionUID() {
+ return serialVersionUID;
+ }
+
+ public ObjectId getTestDefinitionId() {
+ return testDefinitionId;
+ }
+
+ public void setTestDefinitionId(ObjectId testDefinitionId) {
+ this.testDefinitionId = testDefinitionId;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public String getProcessDefinitionKey() {
+ return processDefinitionKey;
+ }
+
+ public void setProcessDefinitionKey(String processDefinitionKey) {
+ this.processDefinitionKey = processDefinitionKey;
+ }
+
+ public String getTestInstanceName() {
+ return testInstanceName;
+ }
+
+ public void setTestInstanceName(String testInstanceName) {
+ this.testInstanceName = testInstanceName;
+ }
+
+ public String getTestInstanceDescription() {
+ return testInstanceDescription;
+ }
+
+ public void setTestInstanceDescription(String testInstanceDescription) {
+ this.testInstanceDescription = testInstanceDescription;
+ }
+
+ public HashMap<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(HashMap<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public HashMap<String, Object> getSimulationVthInput() {
+ return simulationVthInput;
+ }
+
+ public void setSimulationVthInput(HashMap<String, Object> simulationVthInput) {
+ this.simulationVthInput = simulationVthInput;
+ }
+
+ public HashMap<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(HashMap<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public HashMap<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(HashMap<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public ObjectId getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(ObjectId createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public boolean isUseLatestTestDefinition() {
+ return useLatestTestDefinition;
+ }
+
+ public void setUseLatestTestDefinition(boolean useLatestTestDefinition) {
+ this.useLatestTestDefinition = useLatestTestDefinition;
+ }
+
+ public boolean isSimulationMode() {
+ return simulationMode;
+ }
+
+ public void setSimulationMode(boolean simulationMode) {
+ this.simulationMode = simulationMode;
+ }
+
+ public long getMaxExecutionTimeInMillis() {
+ return maxExecutionTimeInMillis;
+ }
+
+ public void setMaxExecutionTimeInMillis(long maxExecutionTimeInMillis) {
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/UserGroup.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/UserGroup.java
new file mode 100644
index 0000000..536bc67
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/UserGroup.java
@@ -0,0 +1,57 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import java.io.Serializable;
+import java.util.List;
+import org.bson.types.ObjectId;
+
+public class UserGroup implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private ObjectId groupId;
+ private List<String> permissions;
+
+ public UserGroup(){}
+ public UserGroup(ObjectId groupId, List<String> permissions) {
+ this.groupId = groupId;
+ this.permissions = permissions;
+ }
+
+ public ObjectId getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(ObjectId groupId) {
+ this.groupId = groupId;
+ }
+
+ public List<String> getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(List<String> permissions) {
+ this.permissions = permissions;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/model/local/WorkflowRequest.java b/otf-service-api/src/main/java/org/oran/otf/common/model/local/WorkflowRequest.java
new file mode 100644
index 0000000..f7089a0
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/model/local/WorkflowRequest.java
@@ -0,0 +1,163 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.model.local;
+
+import org.oran.otf.common.utility.gson.Convert;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import java.io.Serializable;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class WorkflowRequest implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private boolean async = false;
+ private ObjectId executorId = null;
+ private ObjectId testInstanceId = null;
+ private Map<String, ParallelFlowInput> pfloInput = null;
+ private Map<String, Object> testData = null;
+ private Map<String, Object> vthInput = null;
+ private long maxExecutionTimeInMillis = 0L;
+
+ public WorkflowRequest() throws Exception {
+ this.validate();
+ }
+
+ public WorkflowRequest(
+ boolean async,
+ ObjectId executorId,
+ ObjectId testInstanceId,
+ Map<String, ParallelFlowInput> pfloInput,
+ Map<String, Object> testData,
+ Map<String, Object> vthInput,
+ int maxExecutionTimeInMillis)
+ throws Exception {
+ this.async = async;
+ this.executorId = executorId;
+ this.testInstanceId = testInstanceId;
+ this.pfloInput = pfloInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+
+ this.validate();
+ }
+
+ public WorkflowRequest(
+ boolean async,
+ String executorId,
+ String testInstanceId,
+ Map<String, ParallelFlowInput> pfloInput,
+ Map<String, Object> testData,
+ Map<String, Object> vthInput,
+ int maxExecutionTimeInMillis)
+ throws Exception {
+ this.async = async;
+ this.executorId = new ObjectId(executorId);
+ this.testInstanceId = new ObjectId(testInstanceId);
+ this.pfloInput = pfloInput;
+ this.testData = testData;
+ this.vthInput = vthInput;
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+
+ this.validate();
+ }
+
+ private void validate() throws Exception {
+ String missingFieldFormat = "Missing required field %s.";
+ // if (this.async && this.asyncTopic == null) {
+ // throw new Exception(String.format(missingFieldFormat, "asyncTopic"));
+ // }
+
+ // Only required on the Camunda engine
+ // if (this.executorId == null) {
+ // throw new Exception(String.format(missingFieldFormat, "executorId"));
+ // }
+
+ // Only required on the Camunda engine
+ // if (this.testInstanceId == null) {
+ // throw new Exception(String.format(missingFieldFormat, "testInstanceId"));
+ // }
+
+ if (this.maxExecutionTimeInMillis < 0L) {
+ this.maxExecutionTimeInMillis = 0L;
+ }
+ }
+
+ public boolean isAsync() {
+ return async;
+ }
+
+ public void setAsync(boolean async) {
+ this.async = async;
+ }
+
+ public ObjectId getExecutorId() {
+ return executorId;
+ }
+
+ public void setExecutorId(ObjectId executorId) {
+ this.executorId = executorId;
+ }
+
+ public ObjectId getTestInstanceId() {
+ return testInstanceId;
+ }
+
+ public void setTestInstanceId(ObjectId testInstanceId) {
+ this.testInstanceId = testInstanceId;
+ }
+
+ public Map<String, ParallelFlowInput> getPfloInput() {
+ return pfloInput;
+ }
+
+ public void setPfloInput(Map<String, ParallelFlowInput> pfloInput) {
+ this.pfloInput = pfloInput;
+ }
+
+ public Map<String, Object> getTestData() {
+ return testData;
+ }
+
+ public void setTestData(Map<String, Object> testData) {
+ this.testData = testData;
+ }
+
+ public Map<String, Object> getVthInput() {
+ return vthInput;
+ }
+
+ public void setVthInput(Map<String, Object> vthInput) {
+ this.vthInput = vthInput;
+ }
+
+ public long getMaxExecutionTimeInMillis() {
+ return maxExecutionTimeInMillis;
+ }
+
+ public void setMaxExecutionTimeInMillis(long maxExecutionTimeInMillis) {
+ this.maxExecutionTimeInMillis = maxExecutionTimeInMillis;
+ }
+
+ @Override
+ public String toString() {
+ return Convert.objectToJson(this);
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/GroupRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/GroupRepository.java
new file mode 100644
index 0000000..69d000c
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/GroupRepository.java
@@ -0,0 +1,31 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.Group;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+
+import java.util.List;
+
+public interface GroupRepository extends MongoRepository<Group, String> {
+ @Query("{ 'members.userId': ?0 }")
+ public List<Group> findAllByMembersId(ObjectId membersUserId);
+ public Group findFirstByGroupName(String groupName);
+}
+
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestDefinitionRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestDefinitionRepository.java
new file mode 100644
index 0000000..ecd2bab
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestDefinitionRepository.java
@@ -0,0 +1,26 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestDefinition;
+import java.util.Optional;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface TestDefinitionRepository extends MongoRepository<TestDefinition, String> {
+
+ Optional<TestDefinition> findByProcessDefinitionKey(String processDefinitionKey);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestExecutionRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestExecutionRepository.java
new file mode 100644
index 0000000..ee86a82
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestExecutionRepository.java
@@ -0,0 +1,26 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestExecution;
+import java.util.Optional;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface TestExecutionRepository extends MongoRepository<TestExecution, String> {
+
+ Optional<TestExecution> findFirstByProcessInstanceId(String processInstanceId);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestHeadRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestHeadRepository.java
new file mode 100644
index 0000000..09ab4ac
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestHeadRepository.java
@@ -0,0 +1,28 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestHead;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.Optional;
+
+public interface TestHeadRepository extends MongoRepository<TestHead, String> {
+ Optional<TestHead> findByTestHeadName(String testHeadName);
+
+
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/TestInstanceRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestInstanceRepository.java
new file mode 100644
index 0000000..16d1dcb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/TestInstanceRepository.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.TestInstance;
+import java.util.List;
+import java.util.Optional;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.data.mongodb.repository.Query;
+
+public interface TestInstanceRepository extends MongoRepository<TestInstance, String> {
+
+ Optional<TestInstance> findByTestInstanceName(String testInstanceName);
+
+ @Query("{ 'testDefinitionId': ?0 }")
+ List<TestInstance> findAllByTestDefinitionId(ObjectId testDefinitionId);
+
+ @Query("{ 'testDefinitionId': ?0, 'processDefinitionId': ?1 }")
+ List<TestInstance> findAllByTestDefinitionIdAndPDId(
+ ObjectId testDefinitionId, String processDefinitionId);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/repository/UserRepository.java b/otf-service-api/src/main/java/org/oran/otf/common/repository/UserRepository.java
new file mode 100644
index 0000000..5dd669f
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/repository/UserRepository.java
@@ -0,0 +1,25 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.repository;
+
+import org.oran.otf.common.model.User;
+import java.util.Optional;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface UserRepository extends MongoRepository<User, String> {
+ Optional<User> findFirstByEmail(String email);
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/util/HttpUtils.java b/otf-service-api/src/main/java/org/oran/otf/common/util/HttpUtils.java
new file mode 100644
index 0000000..b5e3a39
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/util/HttpUtils.java
@@ -0,0 +1,19 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.util;
+
+public class HttpUtils {}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/RSAEncryptDecrypt.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/RSAEncryptDecrypt.java
new file mode 100644
index 0000000..1309d6d
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/RSAEncryptDecrypt.java
@@ -0,0 +1,54 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import org.springframework.stereotype.Service;
+
+@Service
+public class RSAEncryptDecrypt {
+
+ private KeyPair keyPair;
+
+ public RSAEncryptDecrypt() throws NoSuchAlgorithmException {
+ this.keyPair = buildKeyPair();
+ }
+
+ private KeyPair buildKeyPair() throws NoSuchAlgorithmException {
+ final int keySize = 2048;
+ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(keySize);
+ return keyPairGenerator.genKeyPair();
+ }
+
+ public byte[] encrypt(String message) throws Exception {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, this.keyPair.getPrivate());
+
+ return cipher.doFinal(message.getBytes());
+ }
+
+ public byte[] decrypt(byte[] encrypted) throws Exception {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.DECRYPT_MODE, this.keyPair.getPublic());
+
+ return cipher.doFinal(encrypted);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/Utility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/Utility.java
new file mode 100644
index 0000000..c781ffb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/Utility.java
@@ -0,0 +1,84 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class Utility {
+
+ public static String getLoggerPrefix() {
+ return "[" + Thread.currentThread().getStackTrace()[2].getMethodName() + "]: ";
+ }
+
+ public static Map<?, ?> toMap(Object obj) throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ return mapper.convertValue(obj, HashMap.class);
+ }
+
+ public static boolean isCollection(Object obj) {
+ return obj.getClass().isArray() || obj instanceof Collection;
+ }
+
+ public static List<?> toList(Object obj) {
+ if (obj == null) {
+ throw new NullPointerException("Argument cannot be null.");
+ }
+
+ List<?> list = new ArrayList<>();
+ if (obj.getClass().isArray()) {
+ list = Arrays.asList((Object[]) obj);
+ } else if (obj instanceof Collection) {
+ list = new ArrayList<>((Collection<?>) obj);
+ }
+
+ return list;
+ }
+
+ public static boolean isValidUuid(String str) {
+ if (Strings.isNullOrEmpty(str)) {
+ return false;
+ }
+ try {
+ UUID uuid = UUID.fromString(str);
+ return uuid.toString().equalsIgnoreCase(str);
+ } catch (IllegalArgumentException iae) {
+ return false;
+ }
+ }
+
+ // check a name type pair to see if it matches field in class
+ public static boolean isTypeVariablePairInClass(String variableName, Object variableValue, Class javaClass){
+ List<Field> testHeadFields = Arrays.asList(javaClass.getFields());
+ for(int i = 0; i < testHeadFields.size(); i++){
+ Field field = testHeadFields.get(i);
+ if(field.getName().equals(variableName) && field.getType().isInstance(variableValue)){
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/database/Generic.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/Generic.java
new file mode 100644
index 0000000..5de5043
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/Generic.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.database;
+
+import java.util.Optional;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public class Generic {
+
+ public static <T> boolean identifierExistsInCollection(
+ MongoRepository<T, String> repository, ObjectId identifier) {
+ return repository.findById(identifier.toString()).isPresent();
+ }
+
+ public static <T> T findByIdGeneric(MongoRepository<T, String> repository, ObjectId identifier) {
+ Optional<T> optionalObj = repository.findById(identifier.toString());
+ return optionalObj.orElse(null);
+ }
+
+
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/database/TestExecutionUtility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/TestExecutionUtility.java
new file mode 100644
index 0000000..c54359f
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/database/TestExecutionUtility.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.database;
+
+import org.oran.otf.common.model.TestExecution;
+import com.mongodb.client.result.UpdateResult;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+public class TestExecutionUtility {
+
+ public static void saveTestResult(
+ MongoTemplate mongoOperation, TestExecution execution, String testResult) {
+ Query query = new Query();
+ query.addCriteria(Criteria.where("businessKey").is(execution.getBusinessKey()));
+ Update update = new Update();
+ update.set("testResult", testResult);
+ UpdateResult result = mongoOperation.updateFirst(query, update, TestExecution.class);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/Convert.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/Convert.java
new file mode 100644
index 0000000..bc1d0af
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/Convert.java
@@ -0,0 +1,95 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.gson;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+public class Convert {
+
+ private static final GsonBuilder gsonBuilder =
+ new GsonBuilder()
+ .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
+ .registerTypeAdapter(
+ ObjectId.class,
+ new JsonSerializer<ObjectId>() {
+ @Override
+ public JsonElement serialize(
+ ObjectId src, Type typeOfSrc, JsonSerializationContext context) {
+ return new JsonPrimitive(src.toHexString());
+ }
+ })
+ .registerTypeAdapter(
+ ObjectId.class,
+ new JsonDeserializer<ObjectId>() {
+ @Override
+ public ObjectId deserialize(
+ JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ return new ObjectId(json.getAsString());
+ }
+ });
+
+ public static Gson getGson() {
+ return gsonBuilder.create();
+ }
+
+ public static String mapToJson(Map map) {
+ if (map.isEmpty()) {
+ return "{}";
+ }
+ return getGson().toJson(map);
+ }
+
+ public static Map<String, Object> jsonToMap(String json) {
+ Type type = new TypeToken<HashMap<String, Object>>() {
+ }.getType();
+ return getGson().fromJson(json, type);
+ }
+
+ public static String objectToJson(Object obj) {
+ return getGson().toJson(obj);
+ }
+
+ public static<T> T mapToObject(Map map, TypeReference<T> typeReference) throws IOException {
+ return jsonToObject(mapToJson(map), typeReference);
+ }
+
+ public static <T> T jsonToObject(String json, TypeReference<T> typeReference) throws IOException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper
+ .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
+ return objectMapper.readValue(json, typeReference);
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/GsonUtils.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/GsonUtils.java
new file mode 100644
index 0000000..1b224fc
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/gson/GsonUtils.java
@@ -0,0 +1,69 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.gson;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import com.google.gson.reflect.TypeToken;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import org.bson.types.ObjectId;
+
+public class GsonUtils {
+ private static final GsonBuilder gsonBuilder =
+ new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
+ .registerTypeAdapter(ObjectId.class, new JsonSerializer<ObjectId>() {
+ @Override
+ public JsonElement serialize(ObjectId src, Type typeOfSrc,
+ JsonSerializationContext context) {
+ return new JsonPrimitive(src.toHexString());
+ }
+ }).registerTypeAdapter(ObjectId.class, new JsonDeserializer<ObjectId>() {
+ @Override
+ public ObjectId deserialize(JsonElement json, Type typeOfT,
+ JsonDeserializationContext context) throws JsonParseException {
+ return new ObjectId(json.getAsString());
+ }
+ });
+
+ public static Gson getGson() {
+ return gsonBuilder.create();
+ }
+
+ private static final Gson gson = getGson();
+ private static final Type TT_mapStringString = new TypeToken<Map<String,String>>(){}.getType();
+
+ public static Map<String, String> jsonToMapStringString(String json) {
+ Map<String, String> ret = new HashMap<String, String>();
+ if (json == null || json.isEmpty())
+ return ret;
+ return gson.fromJson(json, TT_mapStringString);
+ }
+ public static String mapStringObjectToJson(Map<String, Object> map) {
+ if (map == null)
+ map = new HashMap<String, Object>();
+ return gson.toJson(map);
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/http/RequestUtility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/RequestUtility.java
new file mode 100644
index 0000000..2af3f90
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/RequestUtility.java
@@ -0,0 +1,160 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.http;
+
+import com.google.common.base.Strings;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class RequestUtility {
+
+ private static Logger logger = LoggerFactory.getLogger(RequestUtility.class);
+
+ public static void postAsync(String url, String body, Map<String, String> headers)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpPost post = buildPost(url, body, headers);
+ executeAsync(post);
+ }
+
+ public static HttpResponse postSync(String url, String body, Map<String, String> headers)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpPost post = buildPost(url, body, headers);
+ return executeSync(post);
+ }
+
+ public static HttpResponse postSync(
+ String url, String body, Map<String, String> headers, int timeoutInMillis)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpPost post = buildPost(url, body, headers);
+ return executeSync(post, timeoutInMillis);
+ }
+
+ public static HttpResponse getSync(String url, Map<String, String> headers)
+ throws IOException, InterruptedException, ExecutionException {
+ HttpGet get = buildGet(url, headers);
+ return executeSync(get);
+ }
+
+ public static HttpResponse getSync(String url, Map<String, String> headers, int timeoutInMillis)
+ throws IOException, InterruptedException, ExecutionException {
+ if (timeoutInMillis < 0) {
+ throw new IllegalArgumentException("The timeoutInMillis must be a value greater than 0.");
+ }
+
+ HttpGet get = buildGet(url, headers);
+ return executeSync(get, timeoutInMillis);
+ }
+
+ public static void getAsync(String url, Map<String, String> headers) throws IOException {
+ HttpGet get = buildGet(url, headers);
+ executeAsync(get);
+ }
+
+ private static HttpPost buildPost(String url, String body, Map<String, String> headers)
+ throws UnsupportedEncodingException {
+ if (Strings.isNullOrEmpty(url) || Strings.isNullOrEmpty(body)) {
+ return null;
+ } else if (headers == null) {
+ headers = new HashMap<>();
+ }
+
+ HttpPost post = new HttpPost(url);
+ headers.forEach(post::setHeader);
+ post.setEntity(new StringEntity(body));
+ return post;
+ }
+
+ private static HttpGet buildGet(String url, Map<String, String> headers) {
+ if (Strings.isNullOrEmpty(url)) {
+ return null;
+ } else if (headers == null) {
+ headers = new HashMap<>();
+ }
+
+ HttpGet get = new HttpGet(url);
+ headers.forEach(get::setHeader);
+ return get;
+ }
+
+ private static HttpResponse executeSync(HttpRequestBase request)
+ throws IOException, InterruptedException, ExecutionException {
+ CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
+ try {
+ httpClient.start();
+ Future<HttpResponse> future = httpClient.execute(request, null);
+ return future.get();
+ } finally {
+ httpClient.close();
+ }
+ }
+
+ private static HttpResponse executeSync(HttpRequestBase request, int timeoutInMillis)
+ throws IOException, InterruptedException, ExecutionException {
+ if (timeoutInMillis < 0) {
+ throw new IllegalArgumentException("The timeoutInMillis must be a value greater than 0.");
+ }
+
+ // Create a timer task that will abort the task (the request) after the specified time. This
+ // task will run *timeoutInMillis* ms
+ TimerTask task =
+ new TimerTask() {
+ @Override
+ public void run() {
+ if (request != null) {
+ request.abort();
+ }
+ }
+ };
+
+ CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
+ try {
+ httpClient.start();
+ // Start the timer before making the request.
+ new Timer(true).schedule(task, timeoutInMillis);
+ Future<HttpResponse> future = httpClient.execute(request, null);
+ return future.get();
+ } finally {
+ httpClient.close();
+ }
+ }
+
+ private static void executeAsync(HttpRequestBase request) throws IOException {
+ CloseableHttpAsyncClient httpClient = HttpAsyncClients.createDefault();
+ try {
+ httpClient.start();
+ httpClient.execute(request, null);
+ logger.debug("Sent asynchronous request.");
+ } finally {
+ httpClient.close();
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/http/ResponseUtility.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/ResponseUtility.java
new file mode 100644
index 0000000..919897c
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/http/ResponseUtility.java
@@ -0,0 +1,107 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.http;
+
+import org.oran.otf.common.model.local.OTFApiResponse;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+public class ResponseUtility {
+
+ public static class Build {
+
+ public static Response okRequest() {
+ return Response.ok().build();
+ }
+
+ public static Response badRequest() {
+ return Response.status(400).build();
+ }
+
+ public static Response okRequestWithMessage(String msg) {
+ return Response.status(200)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(200, msg))
+ .build();
+ }
+
+ public static Response okRequestWithObject(Object obj) {
+ return Response.status(200).type(MediaType.APPLICATION_JSON).entity(obj).build();
+ }
+
+ public static Response badRequestWithMessage(String msg) {
+ return Response.status(400)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(400, msg))
+ .build();
+ }
+
+ public static Response internalServerError() {
+ return Response.status(500).build();
+ }
+
+ public static Response internalServerErrorWithMessage(String msg) {
+ return Response.status(500)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(500, msg))
+ .build();
+ }
+
+ public static Response unauthorized() {
+ return Response.status(401).build();
+ }
+ public static Response unauthorizedWithMessage(String msg) {
+ return Response.status(401)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(401, msg))
+ .build();
+ }
+
+ public static Response notFoundWithMessage(String msg) {
+ return Response.status(404)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(404, msg))
+ .build();
+ }
+
+ public static Response serviceUnavailableWithMessage(String msg) {
+ return Response.status(503)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(503, msg))
+ .build();
+ }
+
+ public static Response serviceUnavailable() {
+ return Response.status(503).build();
+ }
+
+ public static Response genericWithCode(int code) {
+ return Response.status(code).build();
+ }
+
+ public static Response genericWithMessage(int code, String msg) {
+ return Response.status(code)
+ .type(MediaType.APPLICATION_JSON)
+ .entity(new OTFApiResponse(code, msg))
+ .build();
+ }
+
+ public static Response genericWithObject(int code, Object obj) {
+ return Response.status(code).type(MediaType.APPLICATION_JSON).entity(obj).build();
+ }
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/ErrorCode.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/ErrorCode.java
new file mode 100644
index 0000000..8327a81
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/ErrorCode.java
@@ -0,0 +1,36 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.logger;
+
+public enum ErrorCode {
+ PermissionError(100),
+ AvailabilityError(200),
+ DataError(300),
+ SchemaError(400),
+ BusinessProcesssError(500),
+ UnknownError(900);
+
+ private int value;
+
+ ErrorCode(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return this.value;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/LoggerStartupListener.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/LoggerStartupListener.java
new file mode 100644
index 0000000..10c45d8
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/LoggerStartupListener.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
+ * Licensed 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 CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oran.otf.common.utility.logger;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.LoggerContextListener;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.spi.ContextAwareBase;
+import ch.qos.logback.core.spi.LifeCycle;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class LoggerStartupListener extends ContextAwareBase
+ implements LoggerContextListener, LifeCycle {
+
+ private static final Logger logger = LoggerFactory.getLogger(LoggerStartupListener.class);
+ private boolean started = false;
+
+ @Override
+ public void start() {
+ if (started) {
+ return;
+ }
+ InetAddress addr = null;
+ try {
+ addr = InetAddress.getLocalHost();
+ } catch (UnknownHostException e) {
+ logger.error("UnknownHostException", e);
+ }
+ Context context = getContext();
+ if (addr != null) {
+ context.putProperty("server.name", addr.getHostName());
+ }
+ started = true;
+ }
+
+ @Override
+ public void stop() {
+ }
+
+ @Override
+ public boolean isStarted() {
+ return started;
+ }
+
+ @Override
+ public boolean isResetResistant() {
+ return true;
+ }
+
+ @Override
+ public void onReset(LoggerContext arg0) {
+ }
+
+ @Override
+ public void onStart(LoggerContext arg0) {
+ }
+
+ @Override
+ public void onStop(LoggerContext arg0) {
+ }
+
+ @Override
+ public void onLevelChange(ch.qos.logback.classic.Logger logger, Level level) {
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/MessageEnum.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/MessageEnum.java
new file mode 100644
index 0000000..1103c53
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/logger/MessageEnum.java
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP - SO
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed 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 CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.oran.otf.common.utility.logger;
+
+
+public enum MessageEnum {
+ // Api Handler Messages
+ APIH_REQUEST_NULL, APIH_QUERY_FOUND, APIH_QUERY_NOT_FOUND, APIH_QUERY_PARAM_WRONG, APIH_DB_ACCESS_EXC, APIH_DB_ACCESS_EXC_REASON, APIH_VALIDATION_ERROR, APIH_REQUEST_VALIDATION_ERROR, APIH_SERVICE_VALIDATION_ERROR, APIH_GENERAL_EXCEPTION_ARG, APIH_GENERAL_EXCEPTION, APIH_GENERAL_WARNING, APIH_AUDIT_EXEC, APIH_GENERAL_METRICS, APIH_DUPLICATE_CHECK_EXC, APIH_DUPLICATE_FOUND, APIH_BAD_ORDER, APIH_DB_ATTRIBUTE_NOT_FOUND, APIH_BPEL_COMMUNICATE_ERROR, APIH_BPEL_RESPONSE_ERROR, APIH_WARP_REQUEST, APIH_ERROR_FROM_BPEL_SERVER, APIH_DB_INSERT_EXC, APIH_DB_UPDATE_EXC, APIH_NO_PROPERTIES, APIH_PROPERTY_LOAD_SUC, APIH_LOAD_PROPERTIES_FAIL, APIH_SDNC_COMMUNICATE_ERROR, APIH_SDNC_RESPONSE_ERROR, APIH_CANNOT_READ_SCHEMA, APIH_HEALTH_CHECK_EXCEPTION, APIH_REQUEST_VALIDATION_ERROR_REASON, APIH_JAXB_MARSH_ERROR, APIH_JAXB_UNMARSH_ERROR, APIH_VNFREQUEST_VALIDATION_ERROR, APIH_DOM2STR_ERROR, APIH_READ_VNFOUTPUT_CLOB_EXCEPTION, APIH_DUPLICATE_CHECK_EXC_ATT, APIH_GENERATED_REQUEST_ID, APIH_GENERATED_SERVICE_INSTANCE_ID, APIH_REPLACE_REQUEST_ID,
+ // Resource Adapter Messages
+ RA_GENERAL_EXCEPTION_ARG, RA_GENERAL_EXCEPTION, RA_GENERAL_WARNING, RA_MISSING_PARAM, RA_AUDIT_EXEC, RA_GENERAL_METRICS, RA_CREATE_STACK_TIMEOUT, RA_DELETE_STACK_TIMEOUT, RA_UPDATE_STACK_TIMEOUT, RA_CONNECTION_EXCEPTION, RA_PARSING_ERROR, RA_PROPERTIES_NOT_FOUND, RA_LOAD_PROPERTIES_SUC, RA_NETWORK_ALREADY_EXIST, RA_UPDATE_NETWORK_ERR, RA_CREATE_STACK_ERR, RA_UPDATE_STACK_ERR, RA_CREATE_TENANT_ERR, RA_NETWORK_NOT_FOUND, RA_NETWORK_ORCHE_MODE_NOT_SUPPORT, RA_CREATE_NETWORK_EXC, RA_NS_EXC, RA_PARAM_NOT_FOUND, RA_CONFIG_EXC, RA_UNKOWN_PARAM, RA_VLAN_PARSE, RA_DELETE_NETWORK_EXC, RA_ROLLBACK_NULL, RA_TENANT_NOT_FOUND, RA_QUERY_NETWORK_EXC, RA_CREATE_NETWORK_NOTIF_EXC, RA_ASYNC_ROLLBACK, RA_WSDL_NOT_FOUND, RA_WSDL_URL_CONVENTION_EXC, RA_INIT_NOTIF_EXC, RA_SET_CALLBACK_AUTH_EXC, RA_FAULT_INFO_EXC, RA_MARSHING_ERROR, RA_PARSING_REQUEST_ERROR, RA_SEND_REQUEST_SDNC, RA_RESPONSE_FROM_SDNC, RA_EXCEPTION_COMMUNICATE_SDNC, RA_EVALUATE_XPATH_ERROR, RA_ANALYZE_ERROR_EXC, RA_ERROR_GET_RESPONSE_SDNC, RA_CALLBACK_BPEL, RA_INIT_CALLBACK_WSDL_ERR, RA_CALLBACK_BPEL_EXC, RA_CALLBACK_BPEL_COMPLETE, RA_SDNC_MISS_CONFIG_PARAM, RA_SDNC_INVALID_CONFIG, RA_PRINT_URL, RA_ERROR_CREATE_SDNC_REQUEST, RA_ERROR_CREATE_SDNC_RESPONSE, RA_ERROR_CONVERT_XML2STR, RA_RECEIVE_SDNC_NOTIF, RA_INIT_SDNC_ADAPTER, RA_SEND_REQUEST_APPC_ERR, RA_SEND_REQUEST_SDNC_ERR, RA_RECEIVE_BPEL_REQUEST, RA_TENANT_ALREADY_EXIST, RA_UPDATE_TENANT_ERR, RA_DELETE_TEMAMT_ERR, RA_ROLLBACK_TENANT_ERR, RA_QUERY_VNF_ERR, RA_VNF_ALREADY_EXIST, RA_VNF_UNKNOWN_PARAM, RA_VNF_EXTRA_PARAM, RA_CREATE_VNF_ERR, RA_VNF_NOT_EXIST, RA_UPDATE_VNF_ERR, RA_DELETE_VNF_ERR, RA_ASYNC_CREATE_VNF, RA_SEND_VNF_NOTIF_ERR, RA_ASYNC_CREATE_VNF_COMPLETE, RA_ASYNC_UPDATE_VNF, RA_ASYNC_UPDATE_VNF_COMPLETE, RA_ASYNC_QUERY_VNF, RA_ASYNC_QUERY_VNF_COMPLETE, RA_ASYNC_DELETE_VNF, RA_ASYNC_DELETE_VNF_COMPLETE, RA_ASYNC_ROLLBACK_VNF, RA_ASYNC_ROLLBACK_VNF_COMPLETE, RA_ROLLBACK_VNF_ERR, RA_DB_INVALID_STATUS, RA_CANT_UPDATE_REQUEST, RA_DB_REQUEST_NOT_EXIST, RA_CONFIG_NOT_FOUND, RA_CONFIG_LOAD, RA_RECEIVE_WORKFLOW_MESSAGE,
+ // BPEL engine Messages
+ BPMN_GENERAL_INFO, BPMN_GENERAL_EXCEPTION_ARG, BPMN_GENERAL_EXCEPTION, BPMN_GENERAL_WARNING, BPMN_AUDIT_EXEC, BPMN_GENERAL_METRICS, BPMN_URN_MAPPING_FAIL, BPMN_VARIABLE_NULL, BPMN_CALLBACK_EXCEPTION,
+ // ASDC Messages
+ ASDC_GENERAL_EXCEPTION_ARG, ASDC_GENERAL_EXCEPTION, ASDC_GENERAL_WARNING, ASDC_GENERAL_INFO, ASDC_AUDIT_EXEC, ASDC_GENERAL_METRICS, ASDC_CREATE_SERVICE, ASDC_ARTIFACT_ALREADY_DEPLOYED, ASDC_CREATE_ARTIFACT, ASDC_ARTIFACT_INSTALL_EXC, ASDC_ARTIFACT_ALREADY_DEPLOYED_DETAIL, ASDC_ARTIFACT_NOT_DEPLOYED_DETAIL, ASDC_ARTIFACT_CHECK_EXC, ASDC_INIT_ASDC_CLIENT_EXC, ASDC_INIT_ASDC_CLIENT_SUC, ASDC_LOAD_ASDC_CLIENT_EXC, ASDC_SINGLETON_CHECKT_EXC, ASDC_SHUTDOWN_ASDC_CLIENT_EXC, ASDC_CHECK_HEAT_TEMPLATE, ASDC_START_INSTALL_ARTIFACT, ASDC_ARTIFACT_TYPE_NOT_SUPPORT, ASDC_ARTIFACT_ALREADY_EXIST, ASDC_ARTIFACT_DOWNLOAD_SUC, ASDC_ARTIFACT_DOWNLOAD_FAIL, ASDC_START_DEPLOY_ARTIFACT, ASDC_SEND_NOTIF_ASDC, ASDC_SEND_NOTIF_ASDC_EXEC, ASDC_RECEIVE_CALLBACK_NOTIF, ASDC_RECEIVE_SERVICE_NOTIF, ASDC_ARTIFACT_NULL, ASDC_SERVICE_NOT_SUPPORT, ASDC_ARTIFACT_DEPLOY_SUC, ASDC_PROPERTIES_NOT_FOUND, ASDC_PROPERTIES_LOAD_SUCCESS,
+ // Default Messages, in case Log catalog is not defined
+ GENERAL_EXCEPTION_ARG, GENERAL_EXCEPTION, GENERAL_WARNING, AUDIT_EXEC, GENERAL_METRICS, LOGGER_SETUP, LOGGER_NOT_FOUND, LOGGER_UPDATE_SUC, LOGGER_UPDATE_DEBUG, LOGGER_UPDATE_DEBUG_SUC, LOAD_PROPERTIES_SUC, NO_PROPERTIES, MADATORY_PARAM_MISSING, LOAD_PROPERTIES_FAIL, INIT_LOGGER, INIT_LOGGER_FAIL, JAXB_EXCEPTION, IDENTITY_SERVICE_NOT_FOUND
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionChecker.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionChecker.java
new file mode 100644
index 0000000..e1749bb
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionChecker.java
@@ -0,0 +1,57 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.permissions;
+
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+
+import java.util.Collection;
+
+public class PermissionChecker {
+ //check is a user have a certain permission in a group
+ public static boolean hasPermissionTo(User user,Group group,String permission, GroupRepository groupRepository){
+ UserPermission userPermission = new PermissionUtil().buildUserPermission(user,groupRepository);
+ return hasPermissionTo(userPermission,group,permission);
+ }
+ public static boolean hasPermissionTo(User user, Group group, Collection<String> permissions, GroupRepository groupRepository){
+ UserPermission userPermission = new PermissionUtil().buildUserPermission(user,groupRepository);
+ for(String permission : permissions){
+ if(!hasPermissionTo(userPermission,group,permission)){
+ return false;
+ }
+ }
+ return true;
+ }
+ // check a users list of permission in a group
+ private static boolean hasPermissionTo(UserPermission userPermission, Group group,String permission){
+ switch (permission.toUpperCase()) {
+ case (UserPermission.Permission.READ):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.READ);
+ case (UserPermission.Permission.WRITE):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.WRITE);
+ case (UserPermission.Permission.EXECUTE):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.EXECUTE);
+ case (UserPermission.Permission.DELETE):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.DELETE);
+ case (UserPermission.Permission.MANAGEMENT):
+ return userPermission.hasAccessTo(group.get_id().toString(),UserPermission.Permission.MANAGEMENT);
+ default:
+ return false;// reaches here when permission provided is not an option
+ }
+ }
+}
\ No newline at end of file
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionUtil.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionUtil.java
new file mode 100644
index 0000000..e8cdfea
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/PermissionUtil.java
@@ -0,0 +1,237 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.permissions;
+
+import org.oran.otf.common.model.Group;
+import org.oran.otf.common.model.GroupMember;
+import org.oran.otf.common.model.Role;
+import org.oran.otf.common.model.User;
+import org.oran.otf.common.repository.GroupRepository;
+
+import java.util.*;
+
+public class PermissionUtil {
+ //build userPermission object which contains all access control information of the user
+ public UserPermission buildUserPermission(User user, GroupRepository groupRepository) {
+ UserPermission userPermission = new UserPermission();
+ userPermission.setUser(user);
+ Map<String,Set<String>> userAccessMap; // map from group to permission that user have in that group
+
+ userAccessMap = mapGroupsToPermission(user,groupRepository);
+ userPermission.setUserAccessMap(userAccessMap);
+ return userPermission;
+ }
+ // return if user have specified permission in a certain group
+ // ***********only use this groups that the user is in directly (non-child and non parents)****************
+ public static boolean hasPermissionTo (String permission,User user, Group group) {
+ Set<String> possiblePermissions= getUserGroupPermissions(user,group);
+ return possiblePermissions.stream().anyMatch(p-> p.equalsIgnoreCase(permission)); //
+ }
+ // Get all the permissions the user have in a certain group
+ public static Set<String> getUserGroupPermissions(User user, Group group){
+ Set<String> permissionsAllowed = new HashSet<>();
+ Set<String> usersAssignedRoles = findUserRoles(user,group);
+ if(usersAssignedRoles.isEmpty()) // empty set permissions because the user have no roles in the group aka not a member
+ return permissionsAllowed;
+ //get every single permissions for each role that the user have.
+ for(String role : usersAssignedRoles){
+ permissionsAllowed.addAll(getRolePermissions(role,group));
+ }
+ return permissionsAllowed;
+ }
+ //get the permissions associated with the userRoleName in group
+ public static Set<String> getRolePermissions(String userRoleName,Group group)
+ {
+ for(Role role : group.getRoles())
+ {
+ if(role.getRoleName().equalsIgnoreCase(userRoleName))
+ {
+ return new HashSet<String>(role.getPermissions());
+ }
+ }
+ return new HashSet<String>(); // empty string set if the role name cant be found in the group
+ }
+ // find the user's role in the specified group
+ public static Set<String> findUserRoles(User user,Group group){
+ for(GroupMember member : group.getMembers())
+ {
+ // if userId matches then get all the user's role in the group
+ if(member.getUserId().toString().equals(user.get_id().toString()))
+ return new HashSet<String>(member.getRoles());
+ }
+ return new HashSet<String>(); //if user have no roles
+ }
+ // create map that where key is the group id and value = users permission (string) that that group
+ private Map<String,Set<String>> mapGroupsToPermission(User user, GroupRepository groupRepository){
+ Map<String,Set<String>> groupAccessMap = new HashMap<>();
+ List<Group> enrolledGroups = groupRepository.findAllByMembersId(user.get_id());// enrolledGroups = groups that user is a member of
+ Map<String,Group> allGroupMap = groupListToMap(groupRepository.findAll());
+ // get all permission in the groups the user is ia member of
+ for(Group group: enrolledGroups) {
+ Set<String> permissions = getUserGroupPermissions(user,group);
+ groupAccessMap.put(group.get_id().toString(),convertPermissions(permissions));
+ }
+ //assign add read to all parent groups
+ Set<String> parentGroupsId = getParentGroups(enrolledGroups,allGroupMap);
+ for(String parentId : parentGroupsId)
+ {
+ // if parent access role already exist in
+ // group access map cause they are a member
+ if(groupAccessMap.get(parentId)!= null)
+ groupAccessMap.get(parentId).add(UserPermission.Permission.READ);
+ else
+ groupAccessMap.put(parentId,new HashSet<String>(Arrays.asList(UserPermission.Permission.READ)));
+ }
+ // if there is management role
+ // then assign read access to children
+ if(hasManagementRole(user,enrolledGroups)){
+// Set<String>childIds = getChildrenGroupsId(enrolledGroups,allGroupMap,user);
+ for(Group enrolledGroup : enrolledGroups) {
+ // if enrolled groups is a management group
+ if(hasPermissionTo(UserPermission.Permission.MANAGEMENT,user,enrolledGroup)){
+ // if there is management role then get all the child of that group, do this for all management groups
+ Set<String> childIds= getChildrenGroupsId(Arrays.asList(enrolledGroup),allGroupMap,user);
+ Set<String> userGroupPermissions = convertPermissions(getUserGroupPermissions(user,enrolledGroup));
+ for(String childId : childIds){
+ if (groupAccessMap.get(childId) != null)
+ groupAccessMap.get(childId).addAll(userGroupPermissions);
+ else{
+ groupAccessMap.put(childId,userGroupPermissions);
+ }
+ }
+ }
+ }
+ }
+ return groupAccessMap;
+ }
+ // check is user have managementRole
+ private boolean hasManagementRole(User user, List<Group> enrolledGroups)
+ {
+ for(Group group: enrolledGroups){
+ if(hasPermissionTo(UserPermission.Permission.MANAGEMENT,user,group))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ // get the parent groups starting from the enrolled group of the user
+ private Set<String> getParentGroups(List<Group> enrolledGroup,Map<String,Group> groupMap )
+ {
+ Set<String> parentGroups = new HashSet<>();
+ return lookUp(enrolledGroup,groupMap,parentGroups);
+ }
+ //recursive lookup starting at the enrolled groups that the user is a member of
+ private Set<String> lookUp(List<Group> groupsToCheck, Map<String,Group> groupMap,Set<String> resultSet)
+ {
+ //base case: nothing to check anymore
+ if(groupsToCheck.isEmpty())
+ return resultSet;
+ //This is the parents directly above the current groups that are being checked
+ List<Group> currentParentGroups = new ArrayList<>();
+
+ for(Group group : groupsToCheck)
+ {
+ if(group.getParentGroupId() != null) // if there is a parent
+ {
+ String parentId = group.getParentGroupId().toString();
+ Group parentGroup = groupMap.get(parentId);
+ resultSet.add(parentId);
+ currentParentGroups.add(parentGroup); // add to currentParentGroup so it can be used recursively check for more parents
+ }
+ }
+ return lookUp(currentParentGroups,groupMap,resultSet);
+ }
+ // convert a list of groups to a map of group ids to group
+ private Map<String,Group> groupListToMap(List<Group> allGroups)
+ {
+ Map<String,Group> groupMap = new HashMap<>();
+ allGroups.forEach(group -> groupMap.put(group.get_id().toString(),group));
+ return groupMap;
+ }
+ //get all the child group
+ private Set<String> getChildrenGroupsId(List<Group> enrolledGroup, Map<String,Group> allGroupsMap, User user)
+ {
+ Set<String> childrenGroups = new HashSet<>();
+ Set<String> managementGroupIds = getManagementGroupIds(enrolledGroup,user);
+ return lookForChildren(managementGroupIds,allGroupsMap,childrenGroups);
+ }
+
+ private Set<String> getManagementGroupIds(List<Group> enrolledGroups,User user)
+ {
+ Set<String> parentIds = new HashSet<>();
+ for(Group group: enrolledGroups)
+ {
+ if(hasPermissionTo(UserPermission.Permission.MANAGEMENT,user,group)) // has Management permission
+ {
+ parentIds.add(group.get_id().toString());
+ }
+ }
+ return parentIds;
+ }
+ //recursive look down for childrens via breath first search
+ private Set<String> lookForChildren (Set<String> parentIds, Map<String,Group> allGroupsMap, Set<String> resultSet)
+ {
+ //base case = no groups to check anymore;
+ if (parentIds.isEmpty())
+ return resultSet;
+
+ Set<String> currentChildrenIds = new HashSet<>();
+ for(String groupId : allGroupsMap.keySet())
+ {
+ Group possibleChildGroup = allGroupsMap.get(groupId);
+ if(isChildOf(parentIds,possibleChildGroup)) // if parent id is the same
+ {
+ currentChildrenIds.add(groupId);
+ resultSet.add(groupId);
+ }
+ }
+ return lookForChildren(currentChildrenIds,allGroupsMap,resultSet);
+ }
+ //check if a group is a child of a list of parent group ids
+ private boolean isChildOf(Set<String>parentGroupIds, Group childGroup){
+ for(String parentId: parentGroupIds)
+ {
+ if(isChildOf(parentId,childGroup))
+ return true;
+ }
+ return false;
+ }
+ //check is group has parent that is specified by parentId
+ private boolean isChildOf(String parentId,Group childGroup) {
+ if(childGroup.getParentGroupId() == null)
+ return false;
+ return childGroup.getParentGroupId().toString().equals(parentId);
+ }
+
+ private Set<String> convertPermissions (Set<String> permissions){
+ Set<String> result = new HashSet<>();
+ for (String permission: permissions){
+ if(permission.equalsIgnoreCase(UserPermission.Permission.READ))
+ result.add(UserPermission.Permission.READ);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.WRITE))
+ result.add(UserPermission.Permission.WRITE);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.DELETE))
+ result.add(UserPermission.Permission.DELETE);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.EXECUTE))
+ result.add(UserPermission.Permission.EXECUTE);
+ else if (permission.equalsIgnoreCase(UserPermission.Permission.MANAGEMENT))
+ result.add(UserPermission.Permission.MANAGEMENT);
+ }
+ return result;
+ }
+}
diff --git a/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/UserPermission.java b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/UserPermission.java
new file mode 100644
index 0000000..1883721
--- /dev/null
+++ b/otf-service-api/src/main/java/org/oran/otf/common/utility/permissions/UserPermission.java
@@ -0,0 +1,58 @@
+/* Copyright (c) 2019 AT&T Intellectual Property. #
+# #
+# Licensed 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 CONDITIONS OF ANY KIND, either express or implied. #
+# See the License for the specific language governing permissions and #
+# limitations under the License. #
+##############################################################################*/
+
+
+package org.oran.otf.common.utility.permissions;
+
+import org.oran.otf.common.model.User;
+
+import java.util.Map;
+import java.util.Set;
+
+public class UserPermission {
+ private User user;
+ private Map<String,Set<String>> userAccessMap;
+
+ public User getUser() {
+ return user;
+ }
+
+ public void setUser(User user) {
+ this.user = user;
+ }
+
+ public Map<String, Set<String>> getUserAccessMap() {
+ return userAccessMap;
+ }
+
+ public void setUserAccessMap(Map<String,Set<String>> userAccessMap) {
+ this.userAccessMap = userAccessMap;
+ }
+
+ public boolean hasAccessTo(String groupId,String permission) {
+ if (userAccessMap.get(groupId) == null) {
+ return false;
+ }
+ Set<String> group = userAccessMap.get(groupId);
+ return group.stream().anyMatch(groupPermission->groupPermission.equalsIgnoreCase(permission));
+ }
+ public class Permission{
+ public static final String READ = "READ";
+ public static final String WRITE = "WRITE";
+ public static final String EXECUTE = "EXECUTE";
+ public static final String DELETE = "DELETE";
+ public static final String MANAGEMENT ="MANAGEMENT";
+ }
+}
diff --git a/otf-service-api/src/main/resources/application.properties b/otf-service-api/src/main/resources/application.properties
new file mode 100644
index 0000000..0a68a60
--- /dev/null
+++ b/otf-service-api/src/main/resources/application.properties
@@ -0,0 +1,50 @@
+# Tomcat
+server.port=8443
+server.port.http=8080
+security.require-ssl=false
+
+server.ssl.key-store-type=PKCS12
+server.ssl.key-store=${OTF_CERT_PATH}
+server.ssl.key-store-password=${OTF_CERT_PASS}
+#server.servlet.context-path=/otf/api
+#spring.jersey.application-path=/otf
+#springfox.documentation.swagger.v2.path=/otf/api/swagger.json
+
+# MongoDB
+otf.mongo.hosts=${OTF_MONGO_HOSTS}
+otf.mongo.username=${OTF_MONGO_USERNAME}
+otf.mongo.password=${OTF_MONGO_PASSWORD}
+otf.mongo.replicaSet=${OTF_MONGO_REPLICASET}
+otf.mongo.database=${OTF_MONGO_DATABASE}
+
+# Jackson
+spring.jackson.default-property-inclusion=always
+
+# Logging
+logging.level.org.springframework.web=DEBUG
+logging.level.org.hibernate=ERROR
+logging.file.max-history=5
+logging.file=otf/logs/serviceapi.log
+logging.path=otf/logs
+
+spring.resources.add-mappings=true
+
+ssl.flag =${https-only.flag:true}
+#springfox.documentation.auto-startup=false
+#springfox.documentation.swagger.v2.path=/otf/swagger.json
+
+#config
+aaf.enabled=true
+aaf.call-timeout=10000
+aaf.conn-timeout=6000
+aaf.default-realm=localhost
+aaf.env=PROD
+aaf.locate-url=https://localhost
+aaf.lur-class=org.onap.aaf.cadi.aaf.v2_0.AAFLurPerm
+aaf.url=https://localhost
+basic-realm=localhost
+basic-warn=true
+cadi-latitude=38.62782
+cadi-longitude=-90.19458
+cadi-protocols=TLSv1.1,TLSv1.2
+cadi-noauthn=/health/v1:/demo/openapi.json
\ No newline at end of file
diff --git a/otf-service-api/src/main/resources/banner.txt b/otf-service-api/src/main/resources/banner.txt
new file mode 100644
index 0000000..544bdea
--- /dev/null
+++ b/otf-service-api/src/main/resources/banner.txt
@@ -0,0 +1,8 @@
+ U ___ u _____ _____
+ \/"_ \/ |_ " _| |" ___|
+ | | | | | | U| |_ u
+ .-,_| |_| | /| |\ \| _|/
+ \_)-\___/ u |_|U |_|
+ \\ _// \\_ )(\\,-
+ (__) (__) (__) (__)(_/
+
diff --git a/otf-service-api/src/main/resources/truststore2018.jks b/otf-service-api/src/main/resources/truststore2018.jks
new file mode 100644
index 0000000..5d52914
--- /dev/null
+++ b/otf-service-api/src/main/resources/truststore2018.jks
Binary files differ