diff options
author | Jessica Wagantall <jwagantall@linuxfoundation.org> | 2020-12-08 09:33:13 -0800 |
---|---|---|
committer | Jessica Wagantall <jwagantall@linuxfoundation.org> | 2020-12-08 09:33:25 -0800 |
commit | bfc36d8cb714661eb00ba805d7858872cbce5308 (patch) | |
tree | 99052cc69000d791187d45381b4253353c77bef1 /src/main/java | |
parent | dcd4bab11134095747a90d05f97a578b7d909520 (diff) | |
parent | 1083012bb7376c63d26b7caf9e6251d736342e30 (diff) |
Merge branch 'master' of /home/jwagantall/linuxfoundation/onap/IT-21108/clamp
Signed-off-by: Jessica Wagantall <jwagantall@linuxfoundation.org>
Diffstat (limited to 'src/main/java')
139 files changed, 17796 insertions, 0 deletions
diff --git a/src/main/java/org/onap/clamp/authorization/AuthorizationController.java b/src/main/java/org/onap/clamp/authorization/AuthorizationController.java new file mode 100644 index 000000000..f4da09a2e --- /dev/null +++ b/src/main/java/org/onap/clamp/authorization/AuthorizationController.java @@ -0,0 +1,189 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.authorization; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.util.Date; +import org.apache.camel.Exchange; +import org.onap.clamp.clds.config.ClampProperties; +import org.onap.clamp.clds.exception.NotAuthorizedException; +import org.onap.clamp.clds.model.ClampInformation; +import org.onap.clamp.clds.util.LoggingUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +/** + * Verify user has right permissions. + */ +@Component +public class AuthorizationController { + + protected static final EELFLogger logger = + EELFManager.getInstance().getLogger(AuthorizationController.class); + protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + protected static final EELFLogger securityLogger = + EELFManager.getInstance().getSecurityLogger(); + + // By default we'll set it to a default handler + @Autowired + private ClampProperties refProp; + + private SecurityContext securityContext = SecurityContextHolder.getContext(); + + public static final String PERM_PREFIX = "security.permission.type."; + private static final String PERM_INSTANCE = "security.permission.instance"; + + private static String retrieveUserName(SecurityContext securityContext) { + if (securityContext == null || securityContext.getAuthentication() == null) { + return null; + } + if ((securityContext.getAuthentication().getPrincipal()) instanceof String) { + // anonymous case + return ((String) securityContext.getAuthentication().getPrincipal()); + } else { + return ((UserDetails) securityContext.getAuthentication().getPrincipal()).getUsername(); + } + } + + /** + * Get the principal name. + * + * @return The principal name + */ + public static String getPrincipalName(SecurityContext securityContext) { + String principal = AuthorizationController.retrieveUserName(securityContext); + String name = "Not found"; + if (principal != null) { + name = principal; + } + return name; + } + + /** + * Insert authorize the api based on the permission. + * + * @param camelExchange The Camel Exchange object containing the properties + * @param typeVar The type of the permissions + * @param instanceVar The instance of the permissions. e.g. dev + * @param action The action of the permissions. e.g. read + */ + public void authorize(Exchange camelExchange, String typeVar, String instanceVar, + String action) { + String type = refProp.getStringValue(PERM_PREFIX + typeVar); + String instance = refProp.getStringValue(PERM_INSTANCE); + + if (null == type || type.isEmpty()) { + // authorization is turned off, since the permission is not defined + return; + } + if (null != instanceVar && !instanceVar.isEmpty()) { + instance = instanceVar; + } + String principalName = AuthorizationController.getPrincipalName(this.securityContext); + SecureServicePermission perm = SecureServicePermission.create(type, instance, action); + Date startTime = new Date(); + LoggingUtils.setTargetContext("Clamp", "authorize"); + LoggingUtils.setTimeContext(startTime, new Date()); + securityLogger.debug("checking if {} has permission: {}", principalName, perm); + + if (!isUserPermitted(perm)) { + String msg = principalName + " does not have permission: " + perm; + LoggingUtils.setErrorContext("100", "Authorization Error"); + securityLogger.warn(msg); + throw new NotAuthorizedException(msg); + } + } + + /** + * Insert authorize the api based on the permission. + * + * @param inPermission Security permission in input + * @return True if user is permitted + */ + public boolean isUserPermitted(SecureServicePermission inPermission) { + + String principalName = AuthorizationController.getPrincipalName(this.securityContext); + // check if the user has the permission key or the permission key with a + // combination of all instance and/or all action. + if (hasRole(inPermission.getKey()) || hasRole(inPermission.getKeyAllInstance())) { + auditLogger.info("{} authorized because user has permission with * for instance: {}", + principalName, inPermission.getKey().replace("|", ":")); + return true; + // the rest of these don't seem to be required - isUserInRole method + // appears to take * as a wildcard + } else if (hasRole(inPermission.getKeyAllInstanceAction())) { + auditLogger.info( + "{} authorized because user has permission with * for instance and * for action: {}", + principalName, inPermission.getKey().replace("|", ":")); + return true; + } else if (hasRole(inPermission.getKeyAllAction())) { + auditLogger.info("{} authorized because user has permission with * for action: {}", + principalName, inPermission.getKey().replace("|", ":")); + return true; + } else { + return false; + } + } + + protected boolean hasRole(String role) { + Authentication authentication = securityContext.getAuthentication(); + if (authentication == null) { + return false; + } + for (GrantedAuthority auth : authentication.getAuthorities()) { + if (role.equals(auth.getAuthority())) { + return true; + } + } + return false; + } + + /** + * Gets clds info. CLDS IFO service will return 3 things 1. User Name 2. CLDS + * code version that is currently installed from pom.xml file 3. User + * permissions + * + * @return the clds info + */ + public ClampInformation getClampInformation() { + ClampInformation clampInfo = new ClampInformation(); + Authentication authentication = securityContext.getAuthentication(); + if (authentication == null) { + return new ClampInformation(); + } + clampInfo.setUserName(AuthorizationController.getPrincipalName(this.securityContext)); + for (GrantedAuthority auth : authentication.getAuthorities()) { + clampInfo.getAllPermissions().add(auth.getAuthority()); + } + return clampInfo; + } +} diff --git a/src/main/java/org/onap/clamp/authorization/CldsUser.java b/src/main/java/org/onap/clamp/authorization/CldsUser.java new file mode 100644 index 000000000..b50f50cb2 --- /dev/null +++ b/src/main/java/org/onap/clamp/authorization/CldsUser.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.authorization; + +import java.util.Arrays; + +/** + * The class represents the CldsUser that can be extracted from cldsusers.json. + */ +public class CldsUser { + + private String user; + private String password; + private SecureServicePermission[] permissions; + + /** + * Returns the user. + * + * @return the user + */ + public String getUser() { + return user; + } + + /** + * Sets the user. + * + * @param user + * the user to set + */ + public void setUser(String user) { + this.user = user; + } + + /** + * Returns the password. + * + * @return the password + */ + public String getPassword() { + return password; + } + + /** + * Sets the password. + * + * @param password + * the password to set + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Returns the permissions. + * + * @return the permissions + */ + public SecureServicePermission[] getPermissions() { + return Arrays.copyOf(permissions, permissions.length); + } + + public String[] getPermissionsString() { + return Arrays.stream(getPermissions()).map(SecureServicePermission::getKey).toArray(String[]::new); + } + + /** + * Sets the permissions. + * + * @param permissionsArray + * the permissions to set + */ + public void setPermissions(SecureServicePermission[] permissionsArray) { + this.permissions = Arrays.copyOf(permissionsArray, permissionsArray.length); + } +} diff --git a/src/main/java/org/onap/clamp/authorization/SecureServicePermission.java b/src/main/java/org/onap/clamp/authorization/SecureServicePermission.java new file mode 100644 index 000000000..374aab90c --- /dev/null +++ b/src/main/java/org/onap/clamp/authorization/SecureServicePermission.java @@ -0,0 +1,203 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.onap.clamp.authorization; + +/** + * Permission class that can be instantiated easily using constructor or factory + * methods. + */ +public class SecureServicePermission { + public static final String ALL = "*"; + + private String type; + private String instance; + private String action; + + /** + * Factory method to create permission given type, instance, and action. + * + * @param type type of the permission + * @param instance instance of the permission + * @param action action of the permission + * @return instance of SecureServicePermission with type, instance and action + */ + public static SecureServicePermission create(String type, String instance, String action) { + return new SecureServicePermission(type, instance, action); + } + + /** + * Factory method to create permission given type and instance. Default + * action to ALL/*. + * + * @param type type of the permission + * @param instance instance of the permission + * @return instance of SecureServicePermission with type, instance and default action + */ + public static SecureServicePermission create(String type, String instance) { + return new SecureServicePermission(type, instance, ALL); + } + + /** + * Factory method to create permission given type. Default instance and + * action to ALL/*. + * + * @param type type of the permission + * @return instance of SecureServicePermission with type and default instance and action + */ + public static SecureServicePermission create(String type) { + return new SecureServicePermission(type, ALL, ALL); + } + + /** + * Instantiate permission given type, instance, and action. + * + * @param type type of the permission + * @param instance instance of the permission + * @param action action of the permission + */ + public SecureServicePermission(String type, String instance, String action) { + this.type = type; + this.instance = instance; + this.action = action; + } + + /** + * Instantiate permission given type from concatenated string + * + * @param concatenatedString + * the string type|instance|action, less than 3 params can be + * provided (e.g. "permission-type-cl", "permission-type-cl|dev", + * "permission-type-cl|dev|update" ) + */ + public SecureServicePermission(String concatenatedString) { + String[] userInfo = concatenatedString.split("[|]"); + // We should have at least 1 string + this.type = userInfo[0]; + this.instance = (userInfo.length > 1 ? userInfo[1] : ALL); + this.action = (userInfo.length > 2 ? userInfo[2] : ALL); + } + + /** + * Override toString - return permission in key format. + */ + @Override + public String toString() { + return getKey(); + } + + /** + * Return Permission in Key format = type, instance, and action separate by + * pipe character. + * + * @return permission in key format + */ + public String getKey() { + return type + "|" + instance + "|" + action; + } + + /** + * Return Permission in Key format = type, all instance, and action separate + * by pipe character. + * + * @return permission in key format + */ + public String getKeyAllInstance() { + return type + "|" + ALL + "|" + action; + } + + /** + * Return Permission in Key format = type, all instance, and all action + * separate by pipe character. + * + * @return permission in key format + */ + public String getKeyAllInstanceAction() { + return type + "|" + ALL + "|" + ALL; + } + + /** + * Return Permission in Key format = type, instance, and all action separate + * by pipe character. + * + * @return permission in key format + */ + public String getKeyAllAction() { + return type + "|" + instance + "|" + ALL; + } + + /** + * Returns the permission type. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * Sets the type of permission. + * + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * Returns the instance of permission. + * + * @return the instance + */ + public String getInstance() { + return instance; + } + + /** + * Sets the instance of permission. + * + * @param instance the instance to set + */ + public void setInstance(String instance) { + this.instance = instance; + } + + /** + * Returns the action of permission. + * + * @return the action + */ + public String getAction() { + return action; + } + + /** + * Sets the action of permission. + * + * @param action the action to set + */ + public void setAction(String action) { + this.action = action; + } + +} diff --git a/src/main/java/org/onap/clamp/authorization/SecureServicePermissionDeserializer.java b/src/main/java/org/onap/clamp/authorization/SecureServicePermissionDeserializer.java new file mode 100644 index 000000000..026ee802c --- /dev/null +++ b/src/main/java/org/onap/clamp/authorization/SecureServicePermissionDeserializer.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.authorization; + + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import java.lang.reflect.Type; + +public class SecureServicePermissionDeserializer implements JsonDeserializer<SecureServicePermission> { + + @Override + public SecureServicePermission deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (json.isJsonPrimitive()) { + return new SecureServicePermission(json.getAsString()); + } else { + // if not string try default deserialization + return new Gson().fromJson(json, SecureServicePermission.class); + } + } +} diff --git a/src/main/java/org/onap/clamp/authorization/UserService.java b/src/main/java/org/onap/clamp/authorization/UserService.java new file mode 100644 index 000000000..b4f51c95b --- /dev/null +++ b/src/main/java/org/onap/clamp/authorization/UserService.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.authorization; + + +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Controller; + +/** + * User service used for authorization verification at the login page. Do not + * remove this class. + */ +@Controller +public class UserService { + + private SecurityContext securityContext = SecurityContextHolder.getContext(); + + /** + * REST service that returns the username. + * + * @return the user name + */ + public String getUser() { + return AuthorizationController.getPrincipalName(securityContext); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/Application.java b/src/main/java/org/onap/clamp/clds/Application.java new file mode 100644 index 000000000..e83ff3e76 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/Application.java @@ -0,0 +1,182 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import org.apache.catalina.connector.Connector; +import org.onap.clamp.clds.util.ClampVersioning; +import org.onap.clamp.clds.util.ResourceFileUtils; +import org.onap.clamp.util.PassDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.boot.web.servlet.server.ServletWebServerFactory; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@ComponentScan(basePackages = { "org.onap.clamp" }) +@SpringBootApplication(exclude = { SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class }) +@EnableJpaRepositories(basePackages = { "org.onap.clamp" }) +@EntityScan(basePackages = { "org.onap.clamp" }) +@EnableTransactionManagement +@EnableConfigurationProperties +@EnableAsync +@EnableScheduling +@EnableJpaAuditing +public class Application extends SpringBootServletInitializer { + + protected static final EELFLogger eelfLogger = EELFManager.getInstance().getLogger(Application.class); + // This settings is an additional one to Spring config, + // only if we want to have an additional port automatically redirected to + // HTTPS + @Value("${server.http-to-https-redirection.port:none}") + private String httpRedirectedPort; + /** + * This 8080 is the default port used by spring if this parameter is not + * specified in application.properties. + */ + @Value("${server.port:8080}") + private String springServerPort; + @Value("${server.ssl.key-store:none}") + private String sslKeystoreFile; + + @Autowired + private Environment env; + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(Application.class); + } + + public static void main(String[] args) { + // Start the Spring application + SpringApplication.run(Application.class, args); + } + + /** + * This method is used to declare the camel servlet. + * + * @return A servlet bean + * @throws IOException IO Exception + */ + @Bean + public ServletRegistrationBean camelServletRegistrationBean() throws IOException { + eelfLogger.info(ResourceFileUtils.getResourceAsString("boot-message.txt") + "(v" + + ClampVersioning.getCldsVersionFromProps() + ")" + System.getProperty("line.separator") + + getSslExpirationDate()); + ServletRegistrationBean registration = new ServletRegistrationBean(new ClampServlet(), "/restservices/clds/*"); + registration.setName("CamelServlet"); + return registration; + } + + /** + * This method is used by Spring to create the servlet container factory. + * + * @return The TomcatEmbeddedServletContainerFactory just created + */ + @Bean + public ServletWebServerFactory getEmbeddedServletContainerFactory() { + TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); + if (!"none".equals(httpRedirectedPort) && !"none".equals(sslKeystoreFile)) { + // Automatically redirect to HTTPS + tomcat = new TomcatEmbeddedServletContainerFactoryRedirection(); + Connector newConnector = createRedirectConnector(Integer.parseInt(springServerPort)); + if (newConnector != null) { + tomcat.addAdditionalTomcatConnectors(newConnector); + } + } + return tomcat; + } + + private Connector createRedirectConnector(int redirectSecuredPort) { + if (redirectSecuredPort <= 0) { + eelfLogger.warn("HTTP port redirection to HTTPS is disabled because the HTTPS port is 0 (random port) or -1" + + " (Connector disabled)"); + return null; + } + Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); + connector.setScheme("http"); + connector.setSecure(false); + connector.setPort(Integer.parseInt(httpRedirectedPort)); + connector.setRedirectPort(redirectSecuredPort); + return connector; + } + + private String getSslExpirationDate() throws IOException { + StringBuilder result = new StringBuilder(" :: SSL Certificates :: "); + try { + if (env.getProperty("server.ssl.key-store") != null) { + + KeyStore keystore = KeyStore.getInstance(env.getProperty("server.ssl.key-store-type")); + String password = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"), + env.getProperty("clamp.config.keyFile")); + String keyStore = env.getProperty("server.ssl.key-store"); + InputStream is = ResourceFileUtils.getResourceAsStream(keyStore.replaceAll("classpath:", "")); + keystore.load(is, password.toCharArray()); + + Enumeration<String> aliases = keystore.aliases(); + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + if ("X.509".equals(keystore.getCertificate(alias).getType())) { + result.append("* " + alias + " expires " + + ((X509Certificate) keystore.getCertificate(alias)).getNotAfter() + + System.getProperty("line.separator")); + } + } + } else { + result.append("* NONE HAS been configured"); + } + } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException e) { + eelfLogger.warn("SSL certificate access error ", e); + + } + return result.toString(); + } +} diff --git a/src/main/java/org/onap/clamp/clds/ClampInUserAuditorAware.java b/src/main/java/org/onap/clamp/clds/ClampInUserAuditorAware.java new file mode 100644 index 000000000..9351db23c --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/ClampInUserAuditorAware.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds; + +import java.util.Optional; +import org.onap.clamp.authorization.AuthorizationController; +import org.springframework.data.domain.AuditorAware; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; + +@Component +public class ClampInUserAuditorAware implements AuditorAware<String> { + + @Override + public Optional<String> getCurrentAuditor() { + return Optional.of(AuthorizationController.getPrincipalName(SecurityContextHolder.getContext())); + } + +} diff --git a/src/main/java/org/onap/clamp/clds/ClampServlet.java b/src/main/java/org/onap/clamp/clds/ClampServlet.java new file mode 100644 index 000000000..8ebc7a16b --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/ClampServlet.java @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import fj.data.Array; +import java.io.IOException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import java.util.stream.Collector; +import java.util.stream.Collectors; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.camel.component.servlet.CamelHttpTransportServlet; +import org.onap.clamp.authorization.SecureServicePermission; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.web.context.support.WebApplicationContextUtils; + +public class ClampServlet extends CamelHttpTransportServlet { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -4198841134910211542L; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(ClampServlet.class); + private static final String PERM_INSTANCE = "clamp.config.security.permission.instance"; + private static final String PERM_CL = "clamp.config.security.permission.type.cl"; + private static final String PERM_TEMPLATE = "clamp.config.security.permission.type.template"; + private static final String PERM_VF = "clamp.config.security.permission.type.filter.vf"; + private static final String PERM_MANAGE = "clamp.config.security.permission.type.cl.manage"; + private static final String PERM_TOSCA = "clamp.config.security.permission.type.tosca"; + private static final String AUTHENTICATION_CLASS = "clamp.config.security.authentication.class"; + private static final String READ = "read"; + private static final String UPDATE = "update"; + + private static List<SecureServicePermission> permissionList; + + private synchronized List<String> loadDynamicAuthenticationClasses() { + return Arrays.stream(WebApplicationContextUtils.getWebApplicationContext(getServletContext()) + .getEnvironment().getProperty(AUTHENTICATION_CLASS).split(",")).map(className -> className.trim()) + .collect(Collectors.toList()); + } + + private synchronized List<SecureServicePermission> getPermissionList() { + if (permissionList == null) { + permissionList = new ArrayList<>(); + ApplicationContext applicationContext = WebApplicationContextUtils + .getWebApplicationContext(getServletContext()); + String cldsPermissionInstance = applicationContext.getEnvironment().getProperty(PERM_INSTANCE); + permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_CL), + cldsPermissionInstance, READ)); + permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_CL), + cldsPermissionInstance, UPDATE)); + permissionList.add(SecureServicePermission.create( + applicationContext.getEnvironment().getProperty(PERM_TEMPLATE), cldsPermissionInstance, READ)); + permissionList.add(SecureServicePermission.create( + applicationContext.getEnvironment().getProperty(PERM_TEMPLATE), cldsPermissionInstance, UPDATE)); + permissionList.add(SecureServicePermission.create(applicationContext.getEnvironment().getProperty(PERM_VF), + cldsPermissionInstance, "*")); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_MANAGE), cldsPermissionInstance, "*")); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_TOSCA), cldsPermissionInstance, READ)); + permissionList.add(SecureServicePermission + .create(applicationContext.getEnvironment().getProperty(PERM_TOSCA), + cldsPermissionInstance, UPDATE)); + } + return permissionList; + } + + /** + * When AAF is enabled, request object will contain a cadi Wrapper, so queries + * to isUserInRole will invoke a http call to AAF server. + */ + @Override + protected void doService(HttpServletRequest request, HttpServletResponse response) { + Principal principal = request.getUserPrincipal(); + if (principal != null && loadDynamicAuthenticationClasses().stream() + .anyMatch(className -> className.equals(principal.getClass().getName()))) { + // When AAF is enabled, there is a need to provision the permissions to Spring + // system + List<GrantedAuthority> grantedAuths = new ArrayList<>(); + for (SecureServicePermission perm : getPermissionList()) { + String permString = perm.toString(); + if (request.isUserInRole(permString)) { + grantedAuths.add(new SimpleGrantedAuthority(permString)); + } + } + Authentication auth = new UsernamePasswordAuthenticationToken(new User(principal.getName(), "", + grantedAuths), "", grantedAuths); + SecurityContextHolder.getContext().setAuthentication(auth); + } + try { + super.doService(request, response); + } catch (ServletException | IOException ioe) { + logger.error("Exception caught when executing doService in servlet", ioe); + try { + response.sendError(HttpStatus.INTERNAL_SERVER_ERROR.value()); + } catch (IOException e) { + logger.error("Exception caught when executing HTTP sendError in servlet", e); + } + } + } +} diff --git a/src/main/java/org/onap/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java b/src/main/java/org/onap/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java new file mode 100644 index 000000000..a0109a688 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/TomcatEmbeddedServletContainerFactoryRedirection.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.onap.clamp.clds; + +import org.apache.catalina.Context; +import org.apache.tomcat.util.descriptor.web.SecurityCollection; +import org.apache.tomcat.util.descriptor.web.SecurityConstraint; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; + +/** + * This class is a factory that redirects by default all HTTP to HTTPS + * connector. It is used by the Application.java class and defined in a Spring + * Bean. + * In order to do this, the method postProcessContext has been overridden to + * provide another behavior. + */ +public class TomcatEmbeddedServletContainerFactoryRedirection extends TomcatServletWebServerFactory { + + /** + * This method is there to force the automatic redirection of all calls done + * on the tomcat server to a Secure connection. + */ + @Override + protected void postProcessContext(Context context) { + SecurityConstraint securityConstraint = new SecurityConstraint(); + securityConstraint.setUserConstraint("CONFIDENTIAL"); + SecurityCollection collection = new SecurityCollection(); + collection.addPattern("/*"); + securityConstraint.addCollection(collection); + context.addConstraint(securityConstraint); + } +} diff --git a/src/main/java/org/onap/clamp/clds/client/CdsServices.java b/src/main/java/org/onap/clamp/clds/client/CdsServices.java new file mode 100644 index 000000000..fd3b3539a --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/client/CdsServices.java @@ -0,0 +1,229 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 Huawei Technologies Co., Ltd.
+ * ================================================================================
+ * 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.onap.clamp.clds.client;
+
+import static java.lang.Boolean.parseBoolean;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.onap.clamp.clds.exception.cds.CdsParametersException;
+import org.onap.clamp.clds.model.cds.CdsBpWorkFlowListResponse;
+import org.onap.clamp.clds.util.JsonUtils;
+import org.onap.clamp.clds.util.LoggingUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class implements the communication with CDS for the service inventory.
+ */
+@Component
+public class CdsServices {
+
+ @Autowired
+ CamelContext camelContext;
+
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(CdsServices.class);
+
+ private static final String TYPE = "type";
+ private static final String PROPERTIES = "properties";
+ private static final String LIST = "list";
+
+ /**
+ * Constructor.
+ */
+ @Autowired
+ public CdsServices() {
+ }
+
+
+ /**
+ * Query CDS to get blueprint's workflow list.
+ *
+ * @param blueprintName CDS blueprint name
+ * @param blueprintVersion CDS blueprint version
+ * @return CdsBpWorkFlowListResponse CDS blueprint's workflow list
+ */
+ public CdsBpWorkFlowListResponse getBlueprintWorkflowList(String blueprintName, String blueprintVersion) {
+ LoggingUtils.setTargetContext("CDS", "getBlueprintWorkflowList");
+
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext)
+ .withProperty("blueprintName", blueprintName).withProperty("blueprintVersion", blueprintVersion)
+ .build();
+
+ Exchange exchangeResponse = camelContext.createProducerTemplate()
+ .send("direct:get-blueprint-workflow-list", myCamelExchange);
+
+ if (Integer.valueOf(200).equals(exchangeResponse.getIn().getHeader("CamelHttpResponseCode"))) {
+ String cdsResponse = (String) exchangeResponse.getIn().getBody();
+ logger.info("getBlueprintWorkflowList, response from CDS:" + cdsResponse);
+ LoggingUtils.setResponseContext("0", "Get Blueprint workflow list", this.getClass().getName());
+ Date startTime = new Date();
+ LoggingUtils.setTimeContext(startTime, new Date());
+ return JsonUtils.GSON_JPA_MODEL.fromJson(cdsResponse, CdsBpWorkFlowListResponse.class);
+ } else {
+ logger.error("CDS getBlueprintWorkflowList FAILED");
+ return null;
+ }
+
+ }
+
+ /**
+ * Query CDS to get input properties of workflow.
+ *
+ * @param blueprintName CDS blueprint name
+ * @param blueprintVersion CDS blueprint name
+ * @param workflow CDS blueprint's workflow
+ * @return input properties in json format
+ */
+ public JsonObject getWorkflowInputProperties(String blueprintName, String blueprintVersion,
+ String workflow) {
+ LoggingUtils.setTargetContext("CDS", "getWorkflowInputProperties");
+
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext)
+ .withBody(getCdsPayloadForWorkFlow(blueprintName, blueprintVersion, workflow))
+ .build();
+
+ Exchange exchangeResponse = camelContext.createProducerTemplate()
+ .send("direct:get-blueprint-workflow-input-properties", myCamelExchange);
+
+ if (Integer.valueOf(200).equals(exchangeResponse.getIn().getHeader("CamelHttpResponseCode"))) {
+ String cdsResponse = (String) exchangeResponse.getIn().getBody();
+ logger.info("getWorkflowInputProperties, response from CDS:" + cdsResponse);
+ LoggingUtils.setResponseContext("0", "Get Blueprint workflow input properties", this.getClass().getName());
+ Date startTime = new Date();
+ LoggingUtils.setTimeContext(startTime, new Date());
+ return parseCdsResponse(cdsResponse);
+ } else {
+ logger.error("CDS getWorkflowInputProperties FAILED");
+ return null;
+ }
+ }
+
+ protected JsonObject parseCdsResponse(String response) {
+ JsonObject root = JsonParser.parseString(response).getAsJsonObject();
+ JsonObject inputs = root.getAsJsonObject("workFlowData").getAsJsonObject("inputs");
+ JsonObject dataTypes = root.getAsJsonObject("dataTypes");
+
+ JsonObject workFlowProperties = new JsonObject();
+ workFlowProperties.add("inputs", getInputProperties(inputs, dataTypes, new JsonObject()));
+ return workFlowProperties;
+ }
+
+ private JsonObject getInputProperties(JsonObject inputs, JsonObject dataTypes,
+ JsonObject inputObject) {
+ if (inputs == null) {
+ return inputObject;
+ }
+
+ for (Map.Entry<String, JsonElement> entry : inputs.entrySet()) {
+ String key = entry.getKey();
+ JsonObject inputProperty = inputs.getAsJsonObject(key);
+ String type = inputProperty.get(TYPE).getAsString();
+ if (isComplexType(type, dataTypes)) {
+ inputObject.add(key, handleComplexType(type, dataTypes));
+ } else if (LIST.equalsIgnoreCase(type)) {
+ handleListType(key, inputProperty, dataTypes, inputObject);
+ } else if (isInputParam(inputProperty)) {
+ inputObject.add(key, entry.getValue());
+ }
+ }
+ return inputObject;
+ }
+
+ private void handleListType(String propertyName,
+ JsonObject inputProperty,
+ JsonObject dataTypes,
+ JsonObject inputObject) {
+ if (inputProperty.get("entry_schema") == null) {
+ throw new CdsParametersException("Entry schema is null for " + propertyName);
+ }
+
+ String type = inputProperty.get("entry_schema").getAsJsonObject().get(
+ TYPE).getAsString();
+ if (dataTypes.get(type) != null) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty(TYPE, LIST);
+ jsonObject.add(PROPERTIES, getPropertiesObject(type, dataTypes));
+ inputObject.add(propertyName, jsonObject);
+ } else if (isInputParam(inputProperty)) {
+ inputObject.add(propertyName, inputProperty);
+ }
+ }
+
+ private JsonObject handleComplexType(String key, JsonObject dataTypes) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty(TYPE, "object");
+ jsonObject.add(PROPERTIES, getPropertiesObject(key, dataTypes));
+ return jsonObject;
+ }
+
+ private JsonObject getPropertiesObject(String key, JsonObject dataTypes) {
+ JsonObject properties = dataTypes.get(key).getAsJsonObject().get(PROPERTIES).getAsJsonObject();
+ JsonObject object = new JsonObject();
+ getInputProperties(properties, dataTypes, object);
+ return object;
+ }
+
+ private boolean isComplexType(String type, JsonObject dataTypes) {
+ if (dataTypes == null) {
+ return false;
+ }
+ return dataTypes.get(type) != null;
+ }
+
+ private boolean isInputParam(JsonObject inputProperty) {
+ JsonElement inputParam = inputProperty.get("input-param");
+ if (inputParam == null) {
+ return false;
+ }
+ return parseBoolean(inputParam.getAsString());
+ }
+
+ /**
+ * Creates payload to query CDS to get workflow input properties.
+ *
+ * @param blueprintName CDS blueprint name
+ * @param version CDS blueprint version
+ * @param workflow CDS blueprint workflow
+ * @return returns payload in json format
+ */
+ public String getCdsPayloadForWorkFlow(String blueprintName, String version, String workflow) {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("blueprintName", blueprintName);
+ jsonObject.addProperty("version", version);
+ jsonObject.addProperty("returnContent", "json");
+ jsonObject.addProperty("workflowName", workflow);
+ jsonObject.addProperty("specType", "TOSCA");
+ return jsonObject.toString();
+ }
+}
diff --git a/src/main/java/org/onap/clamp/clds/client/DcaeInventoryServices.java b/src/main/java/org/onap/clamp/clds/client/DcaeInventoryServices.java new file mode 100644 index 000000000..b24bc99b2 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/client/DcaeInventoryServices.java @@ -0,0 +1,141 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2017-2018 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============================================
+ * Modifications copyright (c) 2018 Nokia
+ * ===================================================================
+ *
+ */
+
+package org.onap.clamp.clds.client;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.ExchangeBuilder;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+import org.onap.clamp.clds.config.ClampProperties;
+import org.onap.clamp.clds.model.dcae.DcaeInventoryResponse;
+import org.onap.clamp.clds.util.JsonUtils;
+import org.onap.clamp.clds.util.LoggingUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class implements the communication with DCAE for the service inventory.
+ */
+@Component
+public class DcaeInventoryServices {
+
+ @Autowired
+ CamelContext camelContext;
+
+ protected static final EELFLogger logger = EELFManager.getInstance().getLogger(DcaeInventoryServices.class);
+ protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+ protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+ public static final String DCAE_INVENTORY_URL = "dcae.inventory.url";
+ public static final String DCAE_INVENTORY_RETRY_INTERVAL = "dcae.intentory.retry.interval";
+ public static final String DCAE_INVENTORY_RETRY_LIMIT = "dcae.intentory.retry.limit";
+ private final ClampProperties refProp;
+
+ /**
+ * Constructor.
+ */
+ @Autowired
+ public DcaeInventoryServices(ClampProperties refProp) {
+ this.refProp = refProp;
+ }
+
+ private int getTotalCountFromDcaeInventoryResponse(String responseStr) throws ParseException {
+ JSONParser parser = new JSONParser();
+ Object obj0 = parser.parse(responseStr);
+ JSONObject jsonObj = (JSONObject) obj0;
+ Long totalCount = (Long) jsonObj.get("totalCount");
+ return totalCount.intValue();
+ }
+
+ private DcaeInventoryResponse getItemsFromDcaeInventoryResponse(String responseStr) throws ParseException {
+ JSONParser parser = new JSONParser();
+ Object obj0 = parser.parse(responseStr);
+ JSONObject jsonObj = (JSONObject) obj0;
+ JSONArray itemsArray = (JSONArray) jsonObj.get("items");
+ JSONObject dcaeServiceType0 = (JSONObject) itemsArray.get(0);
+ return JsonUtils.GSON.fromJson(dcaeServiceType0.toString(), DcaeInventoryResponse.class);
+ }
+
+ /**
+ * DO a query to DCAE to get some Information.
+ *
+ * @param artifactName The artifact Name
+ * @param serviceUuid The service UUID
+ * @param resourceUuid The resource UUID
+ * @return The DCAE inventory for the artifact in DcaeInventoryResponse
+ * @throws IOException In case of issues with the stream
+ * @throws ParseException In case of issues with the Json parsing
+ */
+ public DcaeInventoryResponse getDcaeInformation(String artifactName, String serviceUuid, String resourceUuid)
+ throws IOException, ParseException, InterruptedException {
+ LoggingUtils.setTargetContext("DCAE", "getDcaeInformation");
+
+ int retryInterval = 0;
+ int retryLimit = 1;
+ if (refProp.getStringValue(DCAE_INVENTORY_RETRY_LIMIT) != null) {
+ retryLimit = Integer.valueOf(refProp.getStringValue(DCAE_INVENTORY_RETRY_LIMIT));
+ }
+ if (refProp.getStringValue(DCAE_INVENTORY_RETRY_INTERVAL) != null) {
+ retryInterval = Integer.valueOf(refProp.getStringValue(DCAE_INVENTORY_RETRY_INTERVAL));
+ }
+ for (int i = 0; i < retryLimit; i++) {
+ Exchange myCamelExchange = ExchangeBuilder.anExchange(camelContext)
+ .withProperty("blueprintResourceId", resourceUuid).withProperty("blueprintServiceId", serviceUuid)
+ .withProperty("blueprintName", artifactName).build();
+ metricsLogger.info("Attempt n°" + i + " to contact DCAE inventory");
+
+ Exchange exchangeResponse = camelContext.createProducerTemplate()
+ .send("direct:get-dcae-blueprint-inventory", myCamelExchange);
+
+ if (Integer.valueOf(200).equals(exchangeResponse.getIn().getHeader("CamelHttpResponseCode"))) {
+ String dcaeResponse = (String) exchangeResponse.getIn().getBody();
+ int totalCount = getTotalCountFromDcaeInventoryResponse(dcaeResponse);
+ metricsLogger.info("getDcaeInformation complete: totalCount returned=" + totalCount);
+ if (totalCount > 0) {
+ logger.info("getDcaeInformation, answer from DCAE inventory:" + dcaeResponse);
+ LoggingUtils.setResponseContext("0", "Get Dcae Information success", this.getClass().getName());
+ Date startTime = new Date();
+ LoggingUtils.setTimeContext(startTime, new Date());
+ return getItemsFromDcaeInventoryResponse(dcaeResponse);
+ } else {
+ logger.info("Dcae inventory totalCount returned is 0, so waiting " + retryInterval
+ + "ms before retrying ...");
+ // wait for a while and try to connect to DCAE again
+ Thread.sleep(retryInterval);
+ }
+ }
+ }
+ logger.warn("Dcae inventory totalCount returned is still 0, after " + retryLimit + " attempts, returning NULL");
+ return null;
+ }
+}
diff --git a/src/main/java/org/onap/clamp/clds/client/PolicyEngineServices.java b/src/main/java/org/onap/clamp/clds/client/PolicyEngineServices.java new file mode 100644 index 000000000..c75d733a8 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/client/PolicyEngineServices.java @@ -0,0 +1,227 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.client; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import org.apache.camel.CamelContext; +import org.apache.camel.Exchange; +import org.apache.camel.builder.ExchangeBuilder; +import org.onap.clamp.clds.config.ClampProperties; +import org.onap.clamp.clds.sdc.controller.installer.BlueprintMicroService; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.loop.template.PolicyModel; +import org.onap.clamp.loop.template.PolicyModelId; +import org.onap.clamp.loop.template.PolicyModelsService; +import org.onap.clamp.policy.pdpgroup.PdpGroup; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + + +/** + * The class implements the communication with the Policy Engine to retrieve + * policy models (tosca). It mainly delegates the physical calls to Camel + * engine. + */ +@Component +public class PolicyEngineServices { + private final CamelContext camelContext; + + private final PolicyModelsService policyModelsService; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyEngineServices.class); + private static int retryInterval = 0; + private static int retryLimit = 1; + + public static final String POLICY_RETRY_INTERVAL = "policy.retry.interval"; + public static final String POLICY_RETRY_LIMIT = "policy.retry.limit"; + + /** + * Default constructor. + * + * @param camelContext Camel context bean + * @param clampProperties ClampProperties bean + * @param policyModelsService policyModel service + */ + @Autowired + public PolicyEngineServices(CamelContext camelContext, ClampProperties clampProperties, + PolicyModelsService policyModelsService) { + this.camelContext = camelContext; + this.policyModelsService = policyModelsService; + if (clampProperties.getStringValue(POLICY_RETRY_LIMIT) != null) { + retryLimit = Integer.parseInt(clampProperties.getStringValue(POLICY_RETRY_LIMIT)); + } + if (clampProperties.getStringValue(POLICY_RETRY_INTERVAL) != null) { + retryInterval = Integer.parseInt(clampProperties.getStringValue(POLICY_RETRY_INTERVAL)); + } + } + + /** + * This method query Policy engine and create a PolicyModel object with type and version. + * If the policy already exist in the db it returns the existing one. + * + * @param policyType The policyType id + * @param policyVersion The policy version of that type + * @return A PolicyModel created from policyEngine data or null if nothing is found on policyEngine + */ + public PolicyModel createPolicyModelFromPolicyEngine(String policyType, String policyVersion) { + PolicyModel policyModelFound = policyModelsService.getPolicyModel(policyType, policyVersion); + if (policyModelFound == null) { + String policyTosca = this.downloadOnePolicy(policyType, policyVersion); + if (policyTosca != null && !policyTosca.isEmpty()) { + return policyModelsService.savePolicyModelInNewTransaction( + new PolicyModel(policyType, policyTosca, policyVersion)); + } else { + logger.error("Policy not found in the Policy Engine, returning null: " + policyType + + "/" + policyVersion); + return null; + } + } else { + logger.info("Skipping policy model download as it exists already in the database " + policyType + + "/" + policyVersion); + return policyModelFound; + } + } + + /** + * This method query Policy engine and create a PolicyModel object with type and version. + * + * @param microService microservice object instance + * @return A PolicyModel created from policyEngine data + */ + public PolicyModel createPolicyModelFromPolicyEngine(BlueprintMicroService microService) { + return createPolicyModelFromPolicyEngine(microService.getModelType(), microService.getModelVersion()); + } + + /** + * This method synchronize the clamp database and the policy engine. + * So it creates the required PolicyModel. + */ + public void synchronizeAllPolicies() { + LinkedHashMap<String, Object> loadedYaml; + loadedYaml = new Yaml().load(downloadAllPolicies()); + if (loadedYaml == null || loadedYaml.isEmpty()) { + logger.warn("getAllPolicyType yaml returned by policy engine could not be decoded, as it's null or empty"); + return; + } + + LinkedHashMap<String, Object> policyTypesMap = (LinkedHashMap<String, Object>) loadedYaml + .get("policy_types"); + policyTypesMap.forEach((key, value) -> + this.createPolicyModelFromPolicyEngine(key, + ((String) ((LinkedHashMap<String, Object>) value).get("version")))); + } + + /** + * This method can be used to download all policy types + data types defined in + * policy engine. + * + * @return A yaml containing all policy Types and all data types + */ + public String downloadAllPolicies() { + return callCamelRoute(ExchangeBuilder.anExchange(camelContext).build(), "direct:get-all-policy-models", + "Get all policies"); + } + + /** + * This method can be used to download a policy tosca model on the engine. + * + * @param policyType The policy type (id) + * @param policyVersion The policy version + * @return A string with the whole policy tosca model + */ + public String downloadOnePolicy(String policyType, String policyVersion) { + logger.info("Downloading the policy model " + policyType + "/" + policyVersion); + DumperOptions options = new DumperOptions(); + options.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN); + options.setIndent(4); + options.setPrettyFlow(true); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml yamlParser = new Yaml(options); + String responseBody = callCamelRoute( + ExchangeBuilder.anExchange(camelContext).withProperty("policyModelName", policyType) + .withProperty("policyModelVersion", policyVersion).build(), "direct:get-policy-model", + "Get one policy"); + + if (responseBody == null || responseBody.isEmpty()) { + logger.warn("getPolicyModel returned by policy engine could not be decoded, as it's null or empty"); + return null; + } + + return yamlParser.dump((Map<String, Object>) yamlParser.load(responseBody)); + } + + /** + * This method can be used to download all Pdp Groups data from policy engine. + */ + public void downloadPdpGroups() { + String responseBody = + callCamelRoute(ExchangeBuilder.anExchange(camelContext).build(), "direct:get-all-pdp-groups", + "Get Pdp Groups"); + + if (responseBody == null || responseBody.isEmpty()) { + logger.warn("getPdpGroups returned by policy engine could not be decoded, as it's null or empty"); + return; + } + + JsonObject jsonObj = JsonUtils.GSON.fromJson(responseBody, JsonObject.class); + + List<PdpGroup> pdpGroupList = new LinkedList<>(); + JsonArray itemsArray = (JsonArray) jsonObj.get("groups"); + + for (com.google.gson.JsonElement jsonElement : itemsArray) { + JsonObject item = (JsonObject) jsonElement; + PdpGroup pdpGroup = JsonUtils.GSON.fromJson(item.toString(), PdpGroup.class); + pdpGroupList.add(pdpGroup); + } + + policyModelsService.updatePdpGroupInfo(pdpGroupList); + } + + private String callCamelRoute(Exchange exchange, String camelFlow, String logMsg) { + for (int i = 0; i < retryLimit; i++) { + Exchange exchangeResponse = camelContext.createProducerTemplate().send(camelFlow, exchange); + if (Integer.valueOf(200).equals(exchangeResponse.getIn().getHeader("CamelHttpResponseCode"))) { + return (String) exchangeResponse.getIn().getBody(); + } else { + logger.info(logMsg + " query " + retryInterval + "ms before retrying ..."); + // wait for a while and try to connect to DCAE again + try { + Thread.sleep(retryInterval); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + return ""; + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/AafConfiguration.java b/src/main/java/org/onap/clamp/clds/config/AafConfiguration.java new file mode 100644 index 000000000..d9178cb9a --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/AafConfiguration.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.config; + +import javax.servlet.Filter; + +import org.onap.clamp.clds.filter.ClampCadiFilter; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("clamp-aaf-authentication") +public class AafConfiguration { + + /** + * Method to return clamp cadi filter. + * + * @return Filter + */ + @Bean(name = "cadiFilter") + public Filter cadiFilter() { + return new ClampCadiFilter(); + } + + /** + * Method to register cadi filter. + * + * @return FilterRegistrationBean + */ + @Bean + public FilterRegistrationBean cadiFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean(); + registration.setFilter(cadiFilter()); + registration.addUrlPatterns("/restservices/clds/v1/user/*"); + registration.addUrlPatterns("/restservices/clds/v2/dictionary/*"); + registration.addUrlPatterns("/restservices/clds/v2/templates/*"); + registration.addUrlPatterns("/restservices/clds/v2/clampInformation/*"); + registration.addUrlPatterns("/restservices/clds/v2/policyToscaModels/*"); + registration.addUrlPatterns("/restservices/clds/v2/loop/*"); + registration.setName("cadiFilter"); + registration.setOrder(0); + return registration; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/config/CamelConfiguration.java b/src/main/java/org/onap/clamp/clds/config/CamelConfiguration.java new file mode 100644 index 000000000..36e11f64f --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/CamelConfiguration.java @@ -0,0 +1,134 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.config; + +import java.io.IOException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.http4.HttpClientConfigurer; +import org.apache.camel.component.http4.HttpComponent; +import org.apache.camel.model.rest.RestBindingMode; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.BasicHttpClientConnectionManager; +import org.onap.clamp.clds.util.ClampVersioning; +import org.onap.clamp.clds.util.ResourceFileUtils; +import org.onap.clamp.util.PassDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@Component +public class CamelConfiguration extends RouteBuilder { + + @Autowired + CamelContext camelContext; + + @Autowired + private Environment env; + + private void configureDefaultSslProperties() throws IOException { + if (env.getProperty("server.ssl.trust-store") != null) { + URL storeResource = Thread.currentThread().getContextClassLoader() + .getResource(env.getProperty("server.ssl.trust-store").replaceFirst("classpath:", "")); + System.setProperty("javax.net.ssl.trustStore", storeResource.getPath()); + String keyFile = env.getProperty("clamp.config.keyFile"); + String trustStorePass = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"), + keyFile); + System.setProperty("javax.net.ssl.trustStorePassword", trustStorePass); + System.setProperty("javax.net.ssl.trustStoreType", "jks"); + System.setProperty("ssl.TrustManagerFactory.algorithm", "PKIX"); + storeResource = Thread.currentThread().getContextClassLoader() + .getResource(env.getProperty("server.ssl.key-store").replaceFirst("classpath:", "")); + System.setProperty("javax.net.ssl.keyStore", storeResource.getPath()); + + String keyStorePass = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"), + keyFile); + System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass); + System.setProperty("javax.net.ssl.keyStoreType", env.getProperty("server.ssl.key-store-type")); + } + } + + private void registerTrustStore() + throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException, CertificateException, IOException { + if (env.getProperty("server.ssl.trust-store") != null) { + KeyStore truststore = KeyStore.getInstance("JKS"); + String keyFile = env.getProperty("clamp.config.keyFile"); + String password = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"), keyFile); + truststore.load( + ResourceFileUtils.getResourceAsStream(env.getProperty("server.ssl.trust-store")), + password.toCharArray()); + + TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("PKIX"); + trustFactory.init(truststore); + SSLContext sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init(null, trustFactory.getTrustManagers(), null); + SSLSocketFactory factory = new SSLSocketFactory(sslcontext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + SchemeRegistry registry = new SchemeRegistry(); + final Scheme scheme = new Scheme("https4", 443, factory); + registry.register(scheme); + ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory(); + HttpComponent http4 = camelContext.getComponent("https4", HttpComponent.class); + http4.setHttpClientConfigurer(new HttpClientConfigurer() { + + @Override + public void configureHttpClient(HttpClientBuilder builder) { + builder.setSSLSocketFactory(factory); + Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() + .register("https", factory).register("http", plainsf).build(); + builder.setConnectionManager(new BasicHttpClientConnectionManager(registry)); + } + }); + } + } + + @Override + public void configure() + throws KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { + restConfiguration().component("servlet").bindingMode(RestBindingMode.json).jsonDataFormat("clamp-gson") + .dataFormatProperty("prettyPrint", "true")// .enableCORS(true) + // turn on swagger api-doc + .apiContextPath("api-doc").apiVendorExtension(true).apiProperty("api.title", "Clamp Rest API") + .apiProperty("api.version", ClampVersioning.getCldsVersionFromProps()) + .apiProperty("base.path", "/restservices/clds/"); + + // camelContext.setTracing(true); + + configureDefaultSslProperties(); + registerTrustStore(); + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/ClampProperties.java b/src/main/java/org/onap/clamp/clds/config/ClampProperties.java new file mode 100644 index 000000000..0b5c951bf --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/ClampProperties.java @@ -0,0 +1,105 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.config; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * Holds Clamp properties and add some functionalities. + */ +@Component +public class ClampProperties { + + @Autowired + private ApplicationContext appContext; + @Autowired + private Environment env; + public static final String CONFIG_PREFIX = "clamp.config."; + + /** + * get property value. + * + * @param key The first key + * @return The string with the value + */ + public String getStringValue(String key) { + return env.getProperty(CONFIG_PREFIX + key); + } + + /** + * get property value for a combo key (key1 + "." + key2). If not found just use + * key1. + * + * @param key1 The first key + * @param key2 The second key after a dot + * @return The string with the value + */ + public String getStringValue(String key1, String key2) { + String value = getStringValue(key1 + "." + key2); + if (value == null || value.length() == 0) { + value = getStringValue(key1); + } + return value; + } + + /** + * Return the file content. The value obtained from the clds-reference file will + * be used as a filename. + * + * @param key The key that will be used to access the clds-reference file + * @return File content in String + * @throws IOException In case of issues with the JSON parser + */ + public String getFileContent(String key) throws IOException { + String fileReference = getStringValue(key); + return (fileReference != null) ? getFileContentFromPath(fileReference) : null; + } + + /** + * Return the file content. First try with combo key (key1 + "." + key2), + * otherwise default to just key1. The value obtained from the clds-reference + * file will be used as a filename. + * + * @param key1 The first key + * @param key2 The second key after a dot + * @return File content in String + * @throws IOException In case of issues with the JSON parser + */ + public String getFileContent(String key1, String key2) throws IOException { + String fileReference = getStringValue(key1, key2); + return (fileReference != null) ? getFileContentFromPath(fileReference) : null; + } + + private String getFileContentFromPath(String filepath) throws IOException { + URL url = appContext.getResource(filepath).getURL(); + return IOUtils.toString(url, StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/CldsUserJsonDecoder.java b/src/main/java/org/onap/clamp/clds/config/CldsUserJsonDecoder.java new file mode 100644 index 000000000..a7ef10738 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/CldsUserJsonDecoder.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.config; + +import com.google.gson.JsonParseException; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; +import org.onap.clamp.authorization.CldsUser; +import org.onap.clamp.clds.exception.CldsUsersException; +import org.onap.clamp.clds.util.JsonUtils; + +public class CldsUserJsonDecoder { + + private CldsUserJsonDecoder() { + } + + /** + * This method decodes the JSON file provided to a CldsUser Array. The stream is + * closed after this call, this is not possible to reuse it. + * + * @param cldsUsersFile + * The inputStream containing the users json file + * @return CldsUser[] Array containing a list of the user defined in the JSON + * file + */ + public static CldsUser[] decodeJson(InputStream cldsUsersFile) { + try { + return decodeJson(IOUtils.toString(cldsUsersFile, StandardCharsets.UTF_8.name())); + } catch (IOException e) { + throw new CldsUsersException("Exception occurred during the decoding of the clds-users.json", e); + } + } + + /** + * This method decodes the JSON string to a CldsUser Array. + * + * @param cldsUsersString JSON string + * @return CldsUser[] Array containing a list of the user defined in the JSON + */ + public static CldsUser[] decodeJson(String cldsUsersString) { + try { + // the ObjectMapper readValue method closes the stream no need to do + // it + return JsonUtils.GSON.fromJson(cldsUsersString, CldsUser[].class); + } catch (JsonParseException e) { + throw new CldsUsersException("Exception occurred during the decoding of the clds-users.json", e); + } + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/DefaultDictionaryElements.java b/src/main/java/org/onap/clamp/clds/config/DefaultDictionaryElements.java new file mode 100644 index 000000000..1c52e4100 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/DefaultDictionaryElements.java @@ -0,0 +1,167 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.config; + +import javax.annotation.PostConstruct; +import org.onap.clamp.tosca.Dictionary; +import org.onap.clamp.tosca.DictionaryElement; +import org.onap.clamp.tosca.DictionaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("default-dictionary-elements") +public class DefaultDictionaryElements { + + @Autowired + private DictionaryService dictionaryService; + + /** + * Init method. + */ + @PostConstruct + public void init() { + preProvisionDefaultActors(); + preProvisionDefaultOperations(); + } + + private void preProvisionDefaultActors() { + // Set up dictionary elements + Dictionary actorDictionary = new Dictionary(); + actorDictionary.setName("DefaultActors"); + actorDictionary.setSecondLevelDictionary(0); + actorDictionary.setSubDictionaryType(""); + + DictionaryElement elementSo = new DictionaryElement(); + elementSo.setName("SO"); + elementSo.setShortName("SO"); + elementSo.setType("string"); + elementSo.setDescription("SO component"); + actorDictionary.addDictionaryElements(elementSo); + + DictionaryElement elementSdnc = new DictionaryElement(); + elementSdnc.setName("SDNC"); + elementSdnc.setShortName("SDNC"); + elementSdnc.setType("string"); + elementSdnc.setDescription("SDNC component"); + actorDictionary.addDictionaryElements(elementSdnc); + + DictionaryElement elementAppc = new DictionaryElement(); + elementAppc.setName("APPC"); + elementAppc.setShortName("APPC"); + elementAppc.setType("string"); + elementAppc.setDescription("APPC component"); + actorDictionary.addDictionaryElements(elementAppc); + + DictionaryElement elementVfc = new DictionaryElement(); + elementVfc.setName("VFC"); + elementVfc.setShortName("VFC"); + elementVfc.setType("string"); + elementVfc.setDescription("VFC component"); + actorDictionary.addDictionaryElements(elementVfc); + + DictionaryElement elementSdnr = new DictionaryElement(); + elementSdnr.setName("SDNR"); + elementSdnr.setShortName("SDNR"); + elementSdnr.setType("string"); + elementSdnr.setDescription("SDNR component"); + actorDictionary.addDictionaryElements(elementSdnr); + + dictionaryService.saveOrUpdateDictionary(actorDictionary); + } + + private void preProvisionDefaultOperations() { + // Set up dictionary elements + Dictionary operationDictionary = new Dictionary(); + operationDictionary.setName("DefaultOperations"); + operationDictionary.setSecondLevelDictionary(0); + operationDictionary.setSubDictionaryType(""); + + DictionaryElement elementRestart = new DictionaryElement(); + elementRestart.setName("Restart"); + elementRestart.setShortName("Restart (APPC operation)"); + elementRestart.setType("string"); + elementRestart.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementRestart); + + DictionaryElement elementRebuild = new DictionaryElement(); + elementRebuild.setName("Rebuild"); + elementRebuild.setShortName("Rebuild (APPC operation)"); + elementRebuild.setType("string"); + elementRebuild.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementRebuild); + + DictionaryElement elementMigrate = new DictionaryElement(); + elementMigrate.setName("Migrate"); + elementMigrate.setShortName("Migrate (APPC operation)"); + elementMigrate.setType("string"); + elementMigrate.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementMigrate); + + DictionaryElement elementHealthCheck = new DictionaryElement(); + elementHealthCheck.setName("Health-Check"); + elementHealthCheck.setShortName("Health-Check (APPC operation)"); + elementHealthCheck.setType("string"); + elementHealthCheck.setDescription("APPC operation"); + operationDictionary.addDictionaryElements(elementHealthCheck); + + DictionaryElement elementModifyConfig = new DictionaryElement(); + elementModifyConfig.setName("ModifyConfig"); + elementModifyConfig.setShortName("ModifyConfig (APPC/VFC operation)"); + elementModifyConfig.setType("string"); + elementModifyConfig.setDescription("APPC/VFC operation"); + operationDictionary.addDictionaryElements(elementModifyConfig); + + DictionaryElement elementVfModuleCreate = new DictionaryElement(); + elementVfModuleCreate.setName("VF Module Create"); + elementVfModuleCreate.setShortName("VF Module Create (SO operation)"); + elementVfModuleCreate.setType("string"); + elementVfModuleCreate.setDescription("SO operation"); + operationDictionary.addDictionaryElements(elementVfModuleCreate); + + DictionaryElement elementVfModuleDelete = new DictionaryElement(); + elementVfModuleDelete.setName("VF Module Delete"); + elementVfModuleDelete.setShortName("VF Module Delete (SO operation)"); + elementVfModuleDelete.setType("string"); + elementVfModuleDelete.setDescription("SO operation"); + operationDictionary.addDictionaryElements(elementVfModuleDelete); + + DictionaryElement elementReroute = new DictionaryElement(); + elementReroute.setName("Reroute"); + elementReroute.setShortName("Reroute (SDNC operation)"); + elementReroute.setType("string"); + elementReroute.setDescription("SDNC operation"); + operationDictionary.addDictionaryElements(elementReroute); + + DictionaryElement elementBandwidthOnDemand = new DictionaryElement(); + elementBandwidthOnDemand.setName("BandwidthOnDemand"); + elementBandwidthOnDemand.setShortName("BandwidthOnDemand (SDNC operation)"); + elementBandwidthOnDemand.setType("string"); + elementBandwidthOnDemand.setDescription("SDNC operation"); + operationDictionary.addDictionaryElements(elementBandwidthOnDemand); + + dictionaryService.saveOrUpdateDictionary(operationDictionary); + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/DefaultUserConfiguration.java b/src/main/java/org/onap/clamp/clds/config/DefaultUserConfiguration.java new file mode 100644 index 000000000..cfd5f990f --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/DefaultUserConfiguration.java @@ -0,0 +1,138 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.config; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import org.onap.clamp.authorization.CldsUser; +import org.onap.clamp.clds.exception.CldsConfigException; +import org.onap.clamp.clds.exception.CldsUsersException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * This class is used to enable the HTTP authentication to login. It requires a + * specific JSON file containing the user definition + * (classpath:clds/clds-users.json). + */ +@Configuration +@EnableWebSecurity +@Profile("clamp-default-user") +public class DefaultUserConfiguration extends WebSecurityConfigurerAdapter { + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(DefaultUserConfiguration.class); + + private static final String SETUP_WEB_USERS_EXCEPTION_MSG = "Exception occurred during the " + + " setup of the Web users in memory"; + @Autowired + private ClampProperties refProp; + @Value("${clamp.config.security.permission.type.cl:permission-type-cl}") + private String cldsPersmissionTypeCl; + @Value("${CLDS_PERMISSION_INSTANCE:dev}") + private String cldsPermissionInstance; + @Value("${clamp.config.security.encoder:bcrypt}") + private String cldsEncoderMethod; + @Value("${clamp.config.security.encoder.bcrypt.strength:10}") + private Integer cldsBcryptEncoderStrength; + + /** + * This method configures on which URL the authorization will be enabled. + */ + @Override + protected void configure(HttpSecurity http) { + try { + http.csrf().disable().httpBasic().and().authorizeRequests().antMatchers("/restservices/clds/v1/user/**") + .authenticated().anyRequest().permitAll().and().sessionManagement() + .maximumSessions(1); + + } catch (Exception e) { + logger.error(SETUP_WEB_USERS_EXCEPTION_MSG, e); + throw new CldsUsersException(SETUP_WEB_USERS_EXCEPTION_MSG, e); + } + } + + /** + * This method is called by the framework and is used to load all the users + * defined in cldsUsersFile variable (this file path can be configured in the + * application.properties). + * + * @param auth authentication manager builder + */ + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) { + // configure algorithm used for password hashing + final PasswordEncoder passwordEncoder = getPasswordEncoder(); + + try { + CldsUser[] usersList = loadUsers(); + // no users defined + if (null == usersList) { + logger.warn("No users defined. Users should be defined under clds-users.json"); + return; + } + for (CldsUser user : usersList) { + auth.inMemoryAuthentication().withUser(user.getUser()).password(user.getPassword()) + .authorities(user.getPermissionsString()).and().passwordEncoder(passwordEncoder); + } + } catch (Exception e) { + logger.error(SETUP_WEB_USERS_EXCEPTION_MSG, e); + throw new CldsUsersException(SETUP_WEB_USERS_EXCEPTION_MSG, e); + } + } + + /** + * This method loads physically the JSON file and convert it to an Array of + * CldsUser. + * + * @return The array of CldsUser + * @throws IOException In case of the file is not found + */ + private CldsUser[] loadUsers() throws IOException { + logger.info("Load from clds-users.properties"); + return CldsUserJsonDecoder.decodeJson(refProp.getFileContent("files.cldsUsers")); + } + + /** + * This methods returns the chosen encoder for password hashing. + */ + private PasswordEncoder getPasswordEncoder() { + if ("bcrypt".equals(cldsEncoderMethod)) { + return new BCryptPasswordEncoder(cldsBcryptEncoderStrength); + } else { + throw new CldsConfigException( + "Invalid clamp.config.security.encoder value. 'bcrypt' is the only option at this time."); + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/config/SslConfig.java b/src/main/java/org/onap/clamp/clds/config/SslConfig.java new file mode 100644 index 000000000..6345f4b56 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/SslConfig.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.clds.config; + +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import org.onap.clamp.clds.util.ResourceFileUtils; +import org.onap.clamp.util.PassDecoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.server.Ssl; +import org.springframework.boot.web.server.SslStoreProvider; +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.core.io.ResourceLoader; + +@Configuration +@Profile("clamp-ssl-config") +public class SslConfig { + @Autowired + private Environment env; + + @Bean + WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer(ServerProperties serverProperties, + ResourceLoader resourceLoader) { + return (tomcat) -> tomcat.setSslStoreProvider(new SslStoreProvider() { + @Override + public KeyStore getKeyStore() throws KeyStoreException, + NoSuchAlgorithmException, CertificateException, IOException { + KeyStore keystore = KeyStore.getInstance(env.getProperty("server.ssl.key-store-type")); + String password = PassDecoder.decode(env.getProperty("server.ssl.key-store-password"), + env.getProperty("clamp.config.keyFile")); + keystore.load(ResourceFileUtils.getResourceAsStream(env.getProperty("server.ssl.key-store")), + password.toCharArray()); + return keystore; + } + + @Override + public KeyStore getTrustStore() throws KeyStoreException, + NoSuchAlgorithmException, CertificateException, IOException { + KeyStore truststore = KeyStore.getInstance("JKS"); + String password = PassDecoder.decode(env.getProperty("server.ssl.trust-store-password"), + env.getProperty("clamp.config.keyFile")); + truststore.load( + ResourceFileUtils.getResourceAsStream(env.getProperty("server.ssl.trust-store")), + password.toCharArray()); + return truststore; + } + }); + } + + @Bean + WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatSslCustomizer(ServerProperties serverProperties, + ResourceLoader resourceLoader) { + return (tomcat) -> tomcat.setSsl(new Ssl() { + @Override + public String getKeyPassword() { + String password = PassDecoder.decode(env.getProperty("server.ssl.key-password"), + env.getProperty("clamp.config.keyFile")); + return password; + } + }); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/config/SystemPropertiesLoader.java b/src/main/java/org/onap/clamp/clds/config/SystemPropertiesLoader.java new file mode 100644 index 000000000..7480beb8d --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/SystemPropertiesLoader.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.config; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import java.util.Properties; + +import javax.annotation.Resource; + +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Component +public class SystemPropertiesLoader implements ApplicationListener<ContextRefreshedEvent> { + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(SystemPropertiesLoader.class); + + @Resource(name = "mapper") + private Properties myTranslator; + + @Override + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + logger.info("Loading additional JVM properties:" + myTranslator.toString()); + System.getProperties().putAll(myTranslator); + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/sdc/SdcControllersConfiguration.java b/src/main/java/org/onap/clamp/clds/config/sdc/SdcControllersConfiguration.java new file mode 100644 index 000000000..ad2751bb8 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/sdc/SdcControllersConfiguration.java @@ -0,0 +1,99 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.config.sdc; + +import com.google.gson.JsonObject; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.PostConstruct; + +import org.onap.clamp.clds.exception.sdc.controller.SdcParametersException; +import org.onap.clamp.clds.util.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.Resource; + +/** + * This class maps the SDC config JSON file. This JSON can have multiple + * sdc-controller config. So the json is loaded in a static way and the instance + * must specify the controller name that it represents. + */ +public class SdcControllersConfiguration { + + private static final String CONTROLLER_SUBTREE_KEY = "sdc-connections"; + @Autowired + protected ApplicationContext appContext; + /** + * The file name that will be loaded by Spring. + */ + @Value("${clamp.config.files.sdcController:'classpath:/clds/sdc-controllers-config.json'}") + protected String sdcControllerFile; + /** + * The root of the JSON. + */ + private JsonObject jsonRootNode; + + /** + * Loads configuration from SDC controller config file. + * + * @throws IOException IO Exception + */ + @PostConstruct + public void loadConfiguration() throws IOException { + Resource resource = appContext.getResource(sdcControllerFile); + // Try to load json tree + jsonRootNode = JsonUtils.GSON.fromJson(new InputStreamReader( + resource.getInputStream(), StandardCharsets.UTF_8), + JsonObject.class); + } + + public SdcSingleControllerConfiguration getSdcSingleControllerConfiguration(String controllerName) { + return getAllDefinedControllers().get(controllerName); + } + + /** + * This method reads all Controllers configurations and returns them. + * + * @return A list of controller Names defined in the config + */ + public Map<String, SdcSingleControllerConfiguration> getAllDefinedControllers() { + Map<String, SdcSingleControllerConfiguration> result = new HashMap<>(); + if (jsonRootNode.get(CONTROLLER_SUBTREE_KEY) != null) { + jsonRootNode.get(CONTROLLER_SUBTREE_KEY).getAsJsonObject().entrySet().forEach( + entry -> result.put(entry.getKey(), + new SdcSingleControllerConfiguration(entry.getValue().getAsJsonObject(), entry.getKey()))); + } else { + throw new SdcParametersException( + CONTROLLER_SUBTREE_KEY + " key not found in the file: " + sdcControllerFile); + } + return result; + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java b/src/main/java/org/onap/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java new file mode 100644 index 000000000..da90e6060 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/sdc/SdcSingleControllerConfiguration.java @@ -0,0 +1,290 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.config.sdc; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.apache.commons.codec.DecoderException; +import org.onap.clamp.clds.exception.sdc.controller.SdcParametersException; +import org.onap.clamp.clds.util.CryptoUtils; +import org.onap.sdc.api.consumer.IConfiguration; + +/** + * This class maps the SDC config JSON for one controller. + */ +public class SdcSingleControllerConfiguration implements IConfiguration { + + private static final EELFLogger logger = EELFManager.getInstance() + .getLogger(SdcSingleControllerConfiguration.class); + /** + * The sdc Controller name corresponding. + */ + private String sdcControllerName; + /** + * The root of the JSON. + */ + private JsonObject jsonRootNode; + // All keys that can be present in the JSON + public static final String CONSUMER_GROUP_ATTRIBUTE_NAME = "consumerGroup"; + public static final String CONSUMER_ID_ATTRIBUTE_NAME = "consumerId"; + public static final String ENVIRONMENT_NAME_ATTRIBUTE_NAME = "environmentName"; + public static final String SDC_KEY_ATTRIBUTE_NAME = "password"; + public static final String POLLING_INTERVAL_ATTRIBUTE_NAME = "pollingInterval"; + public static final String RELEVANT_ARTIFACT_TYPES_ATTRIBUTE_NAME = "relevantArtifactTypes"; + public static final String USER_ATTRIBUTE_NAME = "user"; + public static final String SDC_ADDRESS_ATTRIBUTE_NAME = "sdcAddress"; + public static final String POLLING_TIMEOUT_ATTRIBUTE_NAME = "pollingTimeout"; + public static final String ACTIVATE_SERVER_TLS_AUTH = "activateServerTLSAuth"; + public static final String KEY_STORE_KEY = "keyStorePassword"; + public static final String KEY_STORE_PATH = "keyStorePath"; + public static final String MESSAGE_BUS_ADDRESSES = "messageBusAddresses"; + private String errorMessageKeyNotFound; + /** + * Supported artifact types. + */ + public static final String HEAT = "HEAT"; + public static final String HEAT_ARTIFACT = "HEAT_ARTIFACT"; + public static final String HEAT_ENV = "HEAT_ENV"; + public static final String HEAT_NESTED = "HEAT_NESTED"; + public static final String HEAT_NET = "HEAT_NET"; + public static final String HEAT_VOL = "HEAT_VOL"; + public static final String OTHER = "OTHER"; + public static final String TOSCA_CSAR = "TOSCA_CSAR"; + public static final String VF_MODULES_METADATA = "VF_MODULES_METADATA"; + private static final String[] SUPPORTED_ARTIFACT_TYPES = { + TOSCA_CSAR, VF_MODULES_METADATA + }; + public static final List<String> SUPPORTED_ARTIFACT_TYPES_LIST = Collections + .unmodifiableList(Arrays.asList(SUPPORTED_ARTIFACT_TYPES)); + + /** + * This constructor builds a SdcSingleControllerConfiguration from the + * corresponding json. + * + * @param jsonNode + * The JSON node + * @param controllerName + * The controller name that must appear in the JSON + */ + public SdcSingleControllerConfiguration(JsonObject jsonNode, String controllerName) { + jsonRootNode = jsonNode; + setSdcControllerName(controllerName); + testAllRequiredParameters(); + } + + public String getSdcControllerName() { + return sdcControllerName; + } + + /** + * Sets SDC controller name. + * + * @param controllerName SDC controller name + */ + public void setSdcControllerName(String controllerName) { + this.sdcControllerName = controllerName; + errorMessageKeyNotFound = " parameter cannot be found in config file for controller name" + sdcControllerName; + testAllRequiredParameters(); + } + + private String getStringConfig(String key) { + if (jsonRootNode != null && jsonRootNode.get(key) != null) { + String config = jsonRootNode.get(key).getAsString(); + return config.isEmpty() ? null : config; + } + return null; + } + + private Integer getIntConfig(String key) { + if (jsonRootNode != null && jsonRootNode.get(key) != null) { + return jsonRootNode.get(key).getAsInt(); + } else { + return 0; + } + } + + private String getEncryptedStringConfig(String key) throws GeneralSecurityException, DecoderException { + if (jsonRootNode != null && jsonRootNode.get(key) != null) { + return jsonRootNode.get(key).getAsString().isEmpty() ? null + : CryptoUtils.decrypt(jsonRootNode.get(key).getAsString()); + } + return null; + } + + @Override + public java.lang.Boolean isUseHttpsWithDmaap() { + return false; + } + + @Override + public String getConsumerGroup() { + if (jsonRootNode != null && jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME) != null) { + String config = jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME).getAsString(); + return "NULL".equals(config) || config.isEmpty() ? null : config; + } + return null; + } + + @Override + public String getConsumerID() { + return getStringConfig(CONSUMER_ID_ATTRIBUTE_NAME); + } + + @Override + public String getEnvironmentName() { + return getStringConfig(ENVIRONMENT_NAME_ATTRIBUTE_NAME); + } + + @Override + public String getPassword() { + try { + return getEncryptedStringConfig(SDC_KEY_ATTRIBUTE_NAME); + } catch (GeneralSecurityException | DecoderException e) { + logger.error("Unable to decrypt the SDC password", e); + return null; + } + } + + @Override + public int getPollingInterval() { + return getIntConfig(POLLING_INTERVAL_ATTRIBUTE_NAME); + } + + @Override + public List<String> getRelevantArtifactTypes() { + // DO not return the Static List SUPPORTED_ARTIFACT_TYPES_LIST because + // the ASDC Client could try to modify it !!! + return Arrays.asList(SUPPORTED_ARTIFACT_TYPES); + } + + @Override + public String getUser() { + return getStringConfig(USER_ATTRIBUTE_NAME); + } + + @Override + public String getAsdcAddress() { + return getStringConfig(SDC_ADDRESS_ATTRIBUTE_NAME); + } + + @Override + public int getPollingTimeout() { + return getIntConfig(POLLING_TIMEOUT_ATTRIBUTE_NAME); + } + + @Override + public boolean activateServerTLSAuth() { + if (jsonRootNode != null && jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH) != null + && jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH).isJsonPrimitive()) { + return jsonRootNode.get(ACTIVATE_SERVER_TLS_AUTH).getAsBoolean(); + } else { + return false; + } + } + + @Override + public String getKeyStorePassword() { + try { + return getEncryptedStringConfig(KEY_STORE_KEY); + } catch (GeneralSecurityException | DecoderException e) { + logger.error("Unable to decrypt the SDC password", e); + return null; + } + } + + @Override + public String getKeyStorePath() { + return getStringConfig(KEY_STORE_PATH); + } + + /** + * This method can be used to validate all required parameters are well + * there. + */ + public void testAllRequiredParameters() { + // Special case for this attribute that can be null from + // getConsumerGroup + if (jsonRootNode == null) { + throw new SdcParametersException("Json is null for controller " + this.getSdcControllerName()); + } + if (this.getConsumerGroup() == null && (jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME) == null + || !"NULL".equals(jsonRootNode.get(CONSUMER_GROUP_ATTRIBUTE_NAME).getAsString()))) { + throw new SdcParametersException(CONSUMER_GROUP_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getConsumerID() == null || this.getConsumerID().isEmpty()) { + throw new SdcParametersException(CONSUMER_ID_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getEnvironmentName() == null || this.getEnvironmentName().isEmpty()) { + throw new SdcParametersException(ENVIRONMENT_NAME_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getAsdcAddress() == null || this.getAsdcAddress().isEmpty()) { + throw new SdcParametersException(SDC_ADDRESS_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getMsgBusAddress() == null || this.getMsgBusAddress().isEmpty()) { + throw new SdcParametersException(MESSAGE_BUS_ADDRESSES + errorMessageKeyNotFound); + } + if (this.getPassword() == null || this.getPassword().isEmpty()) { + throw new SdcParametersException(SDC_KEY_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getPollingInterval() == 0) { + throw new SdcParametersException(POLLING_INTERVAL_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getPollingTimeout() == 0) { + throw new SdcParametersException(POLLING_TIMEOUT_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getRelevantArtifactTypes() == null || this.getRelevantArtifactTypes().isEmpty()) { + throw new SdcParametersException(RELEVANT_ARTIFACT_TYPES_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + if (this.getUser() == null || this.getUser().isEmpty()) { + throw new SdcParametersException(USER_ATTRIBUTE_NAME + errorMessageKeyNotFound); + } + } + + /** + * The flag allows the client to receive metadata for all resources of the + * service regardless of the artifacts associated to them. Setting the flag + * to false will preserve legacy behavior. + */ + @Override + public boolean isFilterInEmptyResources() { + return false; + } + + @Override + public List<String> getMsgBusAddress() { + List<String> addressesList = new ArrayList<>(); + if (jsonRootNode != null && jsonRootNode.get(MESSAGE_BUS_ADDRESSES) != null) { + jsonRootNode.get(MESSAGE_BUS_ADDRESSES).getAsJsonArray().forEach(k -> addressesList.add(k.getAsString())); + return addressesList; + } else { + return addressesList; + } + } +} diff --git a/src/main/java/org/onap/clamp/clds/config/spring/CldsConfiguration.java b/src/main/java/org/onap/clamp/clds/config/spring/CldsConfiguration.java new file mode 100644 index 000000000..14c08c800 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/spring/CldsConfiguration.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.config.spring; + +import org.onap.clamp.clds.config.ClampProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("clamp-default") +public class CldsConfiguration { + + @Autowired + private ApplicationContext appContext; + @Autowired + private ClampProperties refProp; + + + /** + * This loads the file system.properties. + * + * @return The PropertiesFactoryBean + */ + @Bean(name = "mapper") + public PropertiesFactoryBean mapper() { + PropertiesFactoryBean bean = new PropertiesFactoryBean(); + bean.setLocation(appContext.getResource(refProp.getStringValue("files.systemProperties"))); + return bean; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/config/spring/SdcControllerConfiguration.java b/src/main/java/org/onap/clamp/clds/config/spring/SdcControllerConfiguration.java new file mode 100644 index 000000000..eca45d66f --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/config/spring/SdcControllerConfiguration.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.clds.config.spring; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.onap.clamp.clds.config.ClampProperties; +import org.onap.clamp.clds.config.sdc.SdcControllersConfiguration; +import org.onap.clamp.clds.exception.sdc.controller.SdcControllerException; +import org.onap.clamp.clds.sdc.controller.SdcSingleController; +import org.onap.clamp.clds.sdc.controller.SdcSingleControllerStatus; +import org.onap.clamp.loop.CsarInstaller; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; + +@Configuration +@Profile("clamp-sdc-controller") +public class SdcControllerConfiguration { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcControllerConfiguration.class); + private List<SdcSingleController> sdcControllersList = new ArrayList<>(); + private final ClampProperties clampProp; + private final CsarInstaller csarInstaller; + + @Autowired + public SdcControllerConfiguration(ClampProperties clampProp, + @Qualifier("csarInstaller") CsarInstaller csarInstaller) { + this.clampProp = clampProp; + this.csarInstaller = csarInstaller; + } + + /** + * Loads SDC controller configuration. + */ + @PostConstruct + public void loadSdcControllers() { + SdcControllersConfiguration sdcControllersConfig = getSdcControllersConfiguration(); + sdcControllersConfig.getAllDefinedControllers().forEach((key, value) -> { + logger.info("Creating controller instance:" + key); + SdcSingleController sdcController = new SdcSingleController(clampProp, csarInstaller, value, null); + sdcControllersList.add(sdcController); + }); + } + + /** + * Checks whether all SDC controllers defined are up and running. + */ + @Scheduled(fixedRate = 120000) + public void checkAllSdcControllers() { + logger.info("Checking that all SDC Controllers defined are up and running"); + for (SdcSingleController controller : sdcControllersList) { + try { + if (SdcSingleControllerStatus.STOPPED.equals(controller.getControllerStatus())) { + controller.initSdc(); + } + } catch (SdcControllerException e) { + logger.error("Exception caught when booting sdc controller", e); + } + } + logger.info("SDC Controllers check completed"); + } + + /** + * Closes all SDC Controller and the SDC Client. + */ + @PreDestroy + public void killSdcControllers() { + sdcControllersList.forEach(e -> { + try { + e.closeSdc(); + } catch (SdcControllerException e1) { + logger.error("Exception caught when stopping sdc controller", e1); + } + }); + } + + @Bean(name = "sdcControllersConfiguration") + public SdcControllersConfiguration getSdcControllersConfiguration() { + return new SdcControllersConfiguration(); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/exception/CldsConfigException.java b/src/main/java/org/onap/clamp/clds/exception/CldsConfigException.java new file mode 100644 index 000000000..93d98151a --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/CldsConfigException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.onap.clamp.clds.exception; + +/** + * New exception to CldsUser errors. + * + */ +public class CldsConfigException extends RuntimeException { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 5958873136187918505L; + + /** + * This constructor can be used to create a new CldsConfigException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public CldsConfigException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new CldsConfigException. Use + * this constructor only if you are creating a new exception stack, not if + * an exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public CldsConfigException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/onap/clamp/clds/exception/CldsUsersException.java b/src/main/java/org/onap/clamp/clds/exception/CldsUsersException.java new file mode 100644 index 000000000..270bfa1e2 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/CldsUsersException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.onap.clamp.clds.exception; + +/** + * New exception to CldsUser errors. + * + */ +public class CldsUsersException extends RuntimeException { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 933535057227505342L; + + /** + * This constructor can be used to create a new CldsUsersException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public CldsUsersException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new CldsUsersException. Use this + * constructor only if you are creating a new exception stack, not if an + * exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public CldsUsersException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/onap/clamp/clds/exception/NotAuthorizedException.java b/src/main/java/org/onap/clamp/clds/exception/NotAuthorizedException.java new file mode 100644 index 000000000..1bdf18e7e --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/NotAuthorizedException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.exception; + +/** + * New exception to request errors. + * + */ +public class NotAuthorizedException extends RuntimeException { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -5738167530541646123L; + + /** + * This constructor can be used to create a new CldsConfigException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public NotAuthorizedException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new CldsConfigException. Use this + * constructor only if you are creating a new exception stack, not if an + * exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public NotAuthorizedException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/onap/clamp/clds/exception/cds/CdsParametersException.java b/src/main/java/org/onap/clamp/clds/exception/cds/CdsParametersException.java new file mode 100644 index 000000000..73ce31f89 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/cds/CdsParametersException.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.onap.clamp.clds.exception.cds; + +/** + * Exception while parsing CDS response. + */ +public class CdsParametersException extends RuntimeException { + + /** + * serialization id. + */ + private static final long serialVersionUID = 8425657297510362736L; + + /** + * This constructor can be used to create a new CdsParametersException. + * + * @param message The message to dump + */ + public CdsParametersException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new CdsParametersException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public CdsParametersException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/clamp/clds/exception/dcae/DcaeDeploymentException.java b/src/main/java/org/onap/clamp/clds/exception/dcae/DcaeDeploymentException.java new file mode 100644 index 000000000..e733da53d --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/dcae/DcaeDeploymentException.java @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.onap.clamp.clds.exception.dcae; + +/** + * New exception to capture DCAE communication errors. + * + */ +public class DcaeDeploymentException extends RuntimeException { + + /** + * Generated ID. + */ + private static final long serialVersionUID = 8452294782552680243L; + + /** + * This constructor can be used to create a new DcaeDeploymentException. + * + * @param message + * A string message detailing the problem + * @param ex + * The exception sent by the code + */ + public DcaeDeploymentException(String message, Throwable ex) { + super(message, ex); + } + + /** + * This constructor can be used to create a new DcaeDeploymentException. Use + * this constructor only if you are creating a new exception stack, not if + * an exception was already raised by another code. + * + * @param message + * A string message detailing the problem + */ + public DcaeDeploymentException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/onap/clamp/clds/exception/sdc/controller/BlueprintParserException.java b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/BlueprintParserException.java new file mode 100644 index 000000000..7257fd8a0 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/BlueprintParserException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.exception.sdc.controller; + +/** + * Exception during blueprint parsing. + */ +public class BlueprintParserException extends Exception { + + /** + * Serial ID. + */ + private static final long serialVersionUID = -3044162346353623199L; + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + */ + public BlueprintParserException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public BlueprintParserException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/clamp/clds/exception/sdc/controller/CsarHandlerException.java b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/CsarHandlerException.java new file mode 100644 index 000000000..c3ebde1f8 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/CsarHandlerException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.exception.sdc.controller; + +/** + * Exception during Csar operations. + */ +public class CsarHandlerException extends Exception { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -7628640776124409155L; + + /** + * This constructor can be used to create a new CsarHandlerException. + * + * @param message The message to dump + */ + public CsarHandlerException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new CsarHandlerException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public CsarHandlerException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java new file mode 100644 index 000000000..523766af1 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcArtifactInstallerException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.exception.sdc.controller; + +/** + * Exception during SDC artifact installation. + */ +public class SdcArtifactInstallerException extends Exception { + + /** + * serialization id. + */ + private static final long serialVersionUID = 4095937499475915021L; + + /** + * This constructor can be used to create a new SdcArtifactInstallerException. + * + * @param message The message to dump + */ + public SdcArtifactInstallerException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcArtifactInstallerException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcArtifactInstallerException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcControllerException.java b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcControllerException.java new file mode 100644 index 000000000..d73001d78 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcControllerException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.exception.sdc.controller; + +/** + * Exception of the SDC controller. + */ +public class SdcControllerException extends Exception { + + /** + * serialization id. + */ + private static final long serialVersionUID = -4236006447255525130L; + + /** + * This constructor can be used to create a new SdcControllerException. + * + * @param message The message to dump + */ + public SdcControllerException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcControllerException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcControllerException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcDownloadException.java b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcDownloadException.java new file mode 100644 index 000000000..6cd3fb88d --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcDownloadException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.exception.sdc.controller; + +/** + * Exception during download from SDC. + */ +public class SdcDownloadException extends Exception { + + /** + * serialization id. + */ + private static final long serialVersionUID = -5276848693231134901L; + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + */ + public SdcDownloadException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcDownloadException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcDownloadException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcParametersException.java b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcParametersException.java new file mode 100644 index 000000000..bfe63cbfb --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/exception/sdc/controller/SdcParametersException.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.exception.sdc.controller; + +/** + * Exception of the SDC controller. + */ +public class SdcParametersException extends RuntimeException { + + /** + * serialization id. + */ + private static final long serialVersionUID = 8425657297510362736L; + + /** + * This constructor can be used to create a new SdcParametersException. + * + * @param message The message to dump + */ + public SdcParametersException(final String message) { + super(message); + } + + /** + * This constructor can be used to create a new SdcParametersException. + * + * @param message The message to dump + * @param cause The Throwable cause object + */ + public SdcParametersException(final String message, final Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/onap/clamp/clds/filter/ClampCadiFilter.java b/src/main/java/org/onap/clamp/clds/filter/ClampCadiFilter.java new file mode 100644 index 000000000..c673f544a --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/filter/ClampCadiFilter.java @@ -0,0 +1,190 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.filter; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.StandardCopyOption; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +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 org.onap.aaf.cadi.config.Config; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.clamp.clds.util.ResourceFileUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; + +public class ClampCadiFilter extends CadiFilter { + private static final EELFLogger logger = EELFManager.getInstance().getLogger(ClampCadiFilter.class); + + @Autowired + private ApplicationContext appContext; + + @Value("${server.ssl.key-store:#{null}}") + private String keyStore; + + @Value("${server.ssl.key-store-password:#{null}}") + private String keyStorePass; + + @Value("${server.ssl.trust-store:#{null}}") + private String trustStore; + + @Value("${server.ssl.trust-store-password:#{null}}") + private String trustStorePass; + + @Value("${server.ssl.key-alias:clamp@clamp.onap.org}") + private String alias; + + @Value("${clamp.config.keyFile:#{null}}") + private String keyFile; + + @Value("${clamp.config.cadi.cadiLoglevel:#{null}}") + private String cadiLoglevel; + + @Value("${clamp.config.cadi.cadiLatitude:#{null}}") + private String cadiLatitude; + + @Value("${clamp.config.cadi.cadiLongitude:#{null}}") + private String cadiLongitude; + + @Value("${clamp.config.cadi.aafLocateUrl:#{null}}") + private String aafLocateUrl; + + @Value("${clamp.config.cadi.oauthTokenUrl:#{null}}") + private String oauthTokenUrl; + + @Value("${clamp.config.cadi.oauthIntrospectUrl:#{null}}") + private String oauthIntrospectUrl; + + @Value("${clamp.config.cadi.aafEnv:#{null}}") + private String aafEnv; + + @Value("${clamp.config.cadi.aafUrl:#{null}}") + private String aafUrl; + + @Value("${clamp.config.cadi.cadiX509Issuers:#{null}}") + private String cadiX509Issuers; + + @Value("${clamp.config.caCerts:#{null}}") + private String caCertsPath; + + private void checkIfNullProperty(String key, String value) { + /* + * When value is null, so not defined in application.properties set nothing in + * System properties + */ + if (value != null) { + /* + * Ensure that any properties already defined in System.prop by JVM params won't + * be overwritten by Spring application.properties values + */ + System.setProperty(key, System.getProperty(key, value)); + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // set some properties in System so that Cadi filter will find its config + // The JVM values set will always overwrite the Spring ones. + checkIfNullProperty(Config.CADI_KEYFILE, convertSpringToPath(keyFile)); + checkIfNullProperty(Config.CADI_LOGLEVEL, cadiLoglevel); + checkIfNullProperty(Config.CADI_LATITUDE, cadiLatitude); + checkIfNullProperty(Config.CADI_LONGITUDE, cadiLongitude); + + checkIfNullProperty(Config.AAF_LOCATE_URL, aafLocateUrl); + checkIfNullProperty(Config.AAF_OAUTH2_TOKEN_URL, oauthTokenUrl); + checkIfNullProperty(Config.AAF_OAUTH2_INTROSPECT_URL, oauthIntrospectUrl); + + checkIfNullProperty(Config.AAF_ENV, aafEnv); + checkIfNullProperty(Config.AAF_URL, aafUrl); + checkIfNullProperty(Config.CADI_X509_ISSUERS, cadiX509Issuers); + checkIfNullProperty(Config.CADI_KEYSTORE, convertSpringToPath(keyStore)); + checkIfNullProperty(Config.CADI_TRUSTSTORE, convertSpringToPath(trustStore)); + checkIfNullProperty(Config.CADI_ALIAS, alias); + checkIfNullProperty(Config.CADI_KEYSTORE_PASSWORD, keyStorePass); + checkIfNullProperty(Config.CADI_TRUSTSTORE_PASSWORD, trustStorePass); + + super.init(filterConfig); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + try { + String certHeader = ((HttpServletRequest) request).getHeader("X-SSL-Cert"); + if (certHeader != null) { + CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) certificateFactory + .generateCertificate(new ByteArrayInputStream( + URLDecoder.decode(certHeader, StandardCharsets.UTF_8.toString()).getBytes())); + X509Certificate caCert = (X509Certificate) certificateFactory + .generateCertificate(new ByteArrayInputStream( + ResourceFileUtils.getResourceAsString(this.caCertsPath).getBytes())); + + X509Certificate[] certifArray = ((X509Certificate[]) request + .getAttribute("javax.servlet.request.X509Certificate")); + if (certifArray == null) { + certifArray = new X509Certificate[] { cert, caCert }; + request.setAttribute("javax.servlet.request.X509Certificate", certifArray); + } else { + certifArray[0] = cert; + certifArray[1] = caCert; + } + } + + } catch (CertificateException e) { + logger.error("Unable to inject the X.509 certificate", e); + } + super.doFilter(request, response, chain); + } + + private String convertSpringToPath(String fileName) { + try (InputStream ioFile = appContext.getResource(fileName).getInputStream()) { + if (!fileName.contains("file:")) { + File targetFile = new File(appContext.getResource(fileName).getFilename()); + java.nio.file.Files.copy(ioFile, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + return targetFile.getPath(); + } else { + return appContext.getResource(fileName).getFile().getPath(); + } + } catch (IOException e) { + logger.error("Unable to open and copy the file: " + fileName, e); + return null; + } + + } +} diff --git a/src/main/java/org/onap/clamp/clds/model/ClampInformation.java b/src/main/java/org/onap/clamp/clds/model/ClampInformation.java new file mode 100644 index 000000000..d73e94204 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/model/ClampInformation.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2020 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.onap.clamp.clds.model; + +import com.google.gson.annotations.Expose; +import java.util.ArrayList; +import java.util.List; +import org.onap.clamp.clds.util.ClampVersioning; + +public class ClampInformation { + @Expose + private String userName; + @Expose + private String cldsVersion = ClampVersioning.getCldsVersionFromProps(); + @Expose + List<String> allPermissions = new ArrayList<>(); + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getCldsVersion() { + return cldsVersion; + } + + public void setCldsVersion(String cldsVersion) { + this.cldsVersion = cldsVersion; + } + + public List<String> getAllPermissions() { + return allPermissions; + } + + public void setAllPermissions(List<String> allPermissions) { + this.allPermissions = allPermissions; + } +} diff --git a/src/main/java/org/onap/clamp/clds/model/CldsHealthCheck.java b/src/main/java/org/onap/clamp/clds/model/CldsHealthCheck.java new file mode 100644 index 000000000..651997cd3 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/model/CldsHealthCheck.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.onap.clamp.clds.model; + +import com.google.gson.annotations.Expose; + +public class CldsHealthCheck { + @Expose + private String healthCheckComponent; + @Expose + private String healthCheckStatus; + @Expose + private String description; + + public String getHealthCheckComponent() { + return healthCheckComponent; + } + + public void setHealthCheckComponent(String healthCheckComponent) { + this.healthCheckComponent = healthCheckComponent; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getHealthCheckStatus() { + return healthCheckStatus; + } + + public void setHealthCheckStatus(String healthCheckStatus) { + this.healthCheckStatus = healthCheckStatus; + } + +} diff --git a/src/main/java/org/onap/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java b/src/main/java/org/onap/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java new file mode 100644 index 000000000..66025c479 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/model/cds/CdsBpWorkFlowListResponse.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.onap.clamp.clds.model.cds; + +import com.google.gson.annotations.Expose; + +import java.util.LinkedList; +import java.util.List; + +/** + * This class maps the CDS response to a pojo. + */ +public class CdsBpWorkFlowListResponse { + + @Expose + private String blueprintName; + + @Expose + private String version; + + @Expose + private List<String> workflows = new LinkedList<String>(); + + public String getBlueprintName() { + return blueprintName; + } + + public void setBlueprintName(String blueprintName) { + this.blueprintName = blueprintName; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public List<String> getWorkflows() { + return workflows; + } + + public void setWorkflows(List<String> workflows) { + this.workflows = workflows; + } +} diff --git a/src/main/java/org/onap/clamp/clds/model/dcae/DcaeInventoryCache.java b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeInventoryCache.java new file mode 100644 index 000000000..fc2ca5caa --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeInventoryCache.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.clds.model.dcae; + +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This class stores the multiple DcaeInventoryResponse coming back from DCAE. + * The structure is a map of list indexed by asdcServiceId. The list is sorted + * by asdcResourceId. Therefore it's possible to retrieve all the loops defined + * in the DCAE inventory and created by DCAE Mod. + */ +public class DcaeInventoryCache { + + private static Map<String, Set<DcaeInventoryResponse>> blueprintsMap = new ConcurrentHashMap<>(); + + /** + * Add Dcae inventory response. + * + * @param inventoryResponse the Dcae inventory response + */ + public void addDcaeInventoryResponse(DcaeInventoryResponse inventoryResponse) { + Set<DcaeInventoryResponse> responsesSet = blueprintsMap.get(inventoryResponse.getAsdcServiceId()); + if (responsesSet == null) { + responsesSet = new TreeSet<>(); + blueprintsMap.put(inventoryResponse.getAsdcServiceId(), responsesSet); + } + responsesSet.add(inventoryResponse); + } + + public Set<String> getAllLoopIds() { + return this.blueprintsMap.keySet(); + } + + public Set<DcaeInventoryResponse> getAllBlueprintsPerLoopId(String loopId) { + return blueprintsMap.getOrDefault(loopId, new TreeSet<>()); + } +} diff --git a/src/main/java/org/onap/clamp/clds/model/dcae/DcaeInventoryResponse.java b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeInventoryResponse.java new file mode 100644 index 000000000..67bd026d0 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeInventoryResponse.java @@ -0,0 +1,102 @@ + +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.clds.model.dcae; + +import com.google.gson.annotations.Expose; + +/** + * This class maps the DCAE inventory answer to a nice pojo. + */ +public class DcaeInventoryResponse implements Comparable<DcaeInventoryResponse> { + + @Expose + private String typeName; + + @Expose + private String typeId; + + @Expose + private String blueprintTemplate; + + /** + * This field will be used to know all blueprints associated a loop. + */ + @Expose + private String asdcServiceId; + + /** + * This field will be used to know to order of each blueprint microservice in a + * loop. + */ + @Expose + private String asdcResourceId; + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + public String getTypeId() { + return typeId; + } + + public void setTypeId(String typeId) { + this.typeId = typeId; + } + + public String getBlueprintTemplate() { + return blueprintTemplate; + } + + public void setBlueprintTemplate(String blueprintTemplate) { + this.blueprintTemplate = blueprintTemplate; + } + + public String getAsdcServiceId() { + return asdcServiceId; + } + + public void setAsdcServiceId(String asdcServiceId) { + this.asdcServiceId = asdcServiceId; + } + + public String getAsdcResourceId() { + return asdcResourceId; + } + + public void setAsdcResourceId(String asdcResourceId) { + this.asdcResourceId = asdcResourceId; + } + + @Override + public int compareTo(DcaeInventoryResponse otherResponse) { + int thisResourceId = Integer.parseInt(this.asdcResourceId); + int otherResourceId = Integer.parseInt(otherResponse.getAsdcResourceId()); + return (thisResourceId < otherResourceId ? -1 : (thisResourceId > otherResourceId ? 1 : 0)); + } +} diff --git a/src/main/java/org/onap/clamp/clds/model/dcae/DcaeLinks.java b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeLinks.java new file mode 100644 index 000000000..368e1b8e6 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeLinks.java @@ -0,0 +1,60 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.clds.model.dcae; + +import com.google.gson.annotations.Expose; + +public class DcaeLinks { + @Expose + private String self; + @Expose + private String status; + @Expose + private String uninstall; + + public String getSelf() { + return self; + } + + public void setSelf(String self) { + this.self = self; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getUninstall() { + return uninstall; + } + + public void setUninstall(String uninstall) { + this.uninstall = uninstall; + } + +} diff --git a/src/main/java/org/onap/clamp/clds/model/dcae/DcaeOperationStatusResponse.java b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeOperationStatusResponse.java new file mode 100644 index 000000000..aee7d0613 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/model/dcae/DcaeOperationStatusResponse.java @@ -0,0 +1,88 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.clds.model.dcae; + +import com.google.gson.annotations.Expose; + +/** + * This class maps the DCAE deployment handler response to a nice pojo. + */ +public class DcaeOperationStatusResponse { + + @Expose + private String operationType; + + @Expose + private String status; + + @Expose + private String requestId; + + @Expose + private String error; + + @Expose + private DcaeLinks links; + + public String getOperationType() { + return operationType; + } + + public void setOperationType(String operationType) { + this.operationType = operationType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public DcaeLinks getLinks() { + return links; + } + + public void setLinks(DcaeLinks links) { + this.links = links; + } + +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/DistributionStatusMessage.java b/src/main/java/org/onap/clamp/clds/sdc/controller/DistributionStatusMessage.java new file mode 100644 index 000000000..c80441fa6 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/DistributionStatusMessage.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.sdc.controller; + +import org.onap.sdc.api.consumer.IDistributionStatusMessage; +import org.onap.sdc.utils.DistributionStatusEnum; + +public class DistributionStatusMessage implements IDistributionStatusMessage { + + private String artifactUrl; + private String consumerId; + private String distributionId; + private DistributionStatusEnum distributionStatus; + private long timestamp; + + /** + * Distribution status message constructor. + * + * @param artifactUrl + * Url of specific SDC artifact(resource) + * @param consumerId + * Unique ID of SDC component instance + * @param distributionId + * Distribution ID published in the distribution notification. + * @param distributionStatusEnum + * Status to send in the message + * @param timestamp + * Timestamp of the message + */ + public DistributionStatusMessage(final String artifactUrl, final String consumerId, final String distributionId, + final DistributionStatusEnum distributionStatusEnum, final long timestamp) { + this.artifactUrl = artifactUrl; + this.consumerId = consumerId; + this.distributionId = distributionId; + this.distributionStatus = distributionStatusEnum; + this.timestamp = timestamp; + } + + @Override + public String getArtifactURL() { + return artifactUrl; + } + + @Override + public String getConsumerID() { + return consumerId; + } + + @Override + public String getDistributionID() { + return distributionId; + } + + @Override + public DistributionStatusEnum getStatus() { + return distributionStatus; + } + + @Override + public long getTimestamp() { + return timestamp; + } +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/SdcSingleController.java b/src/main/java/org/onap/clamp/clds/sdc/controller/SdcSingleController.java new file mode 100644 index 000000000..f9b43abb7 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/SdcSingleController.java @@ -0,0 +1,435 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018-2019 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============================================ + * Modifications copyright (c) 2018 Nokia + * =================================================================== + * + */ + +package org.onap.clamp.clds.sdc.controller; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import java.util.Date; +import java.util.Map.Entry; +import java.util.concurrent.ThreadLocalRandom; + +import org.onap.clamp.clds.config.ClampProperties; +import org.onap.clamp.clds.config.sdc.SdcSingleControllerConfiguration; +import org.onap.clamp.clds.exception.sdc.controller.BlueprintParserException; +import org.onap.clamp.clds.exception.sdc.controller.CsarHandlerException; +import org.onap.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.clamp.clds.exception.sdc.controller.SdcControllerException; +import org.onap.clamp.clds.exception.sdc.controller.SdcDownloadException; +import org.onap.clamp.clds.sdc.controller.installer.BlueprintArtifact; +import org.onap.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.clamp.clds.util.LoggingUtils; +import org.onap.clamp.loop.CsarInstaller; +import org.onap.sdc.api.IDistributionClient; +import org.onap.sdc.api.consumer.IComponentDoneStatusMessage; +import org.onap.sdc.api.consumer.IDistributionStatusMessage; +import org.onap.sdc.api.consumer.INotificationCallback; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; +import org.onap.sdc.api.results.IDistributionClientResult; +import org.onap.sdc.impl.DistributionClientFactory; +import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException; +import org.onap.sdc.utils.DistributionActionResultEnum; +import org.onap.sdc.utils.DistributionStatusEnum; + +/** + * This class handles one sdc controller defined in the config. + */ +public class SdcSingleController { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(SdcSingleController.class); + private boolean isSdcClientAutoManaged = false; + private CsarInstaller csarInstaller; + private ClampProperties refProp; + /** + * The constant CONFIG_SDC_FOLDER. + */ + public static final String CONFIG_SDC_FOLDER = "sdc.csarFolder"; + private int nbOfNotificationsOngoing = 0; + private SdcSingleControllerStatus controllerStatus = SdcSingleControllerStatus.STOPPED; + private SdcSingleControllerConfiguration sdcConfig; + private IDistributionClient distributionClient; + + /** + * Inner class for Notification callback. + */ + private final class SdcNotificationCallBack implements INotificationCallback { + + private SdcSingleController sdcController; + + /** + * Instantiates a new Sdc notification call back. + * + * @param controller the controller + */ + SdcNotificationCallBack(SdcSingleController controller) { + sdcController = controller; + } + + /** + * This method can be called multiple times at the same moment. The controller + * must be thread safe ! + */ + @Override + public void activateCallback(INotificationData notificationData) { + Date startTime = new Date(); + logger.info("Receive a callback notification in SDC, nb of resources: " + + notificationData.getResources().size()); + sdcController.treatNotification(notificationData); + LoggingUtils.setTimeContext(startTime, new Date()); + LoggingUtils.setResponseContext("0", "SDC Notification received and processed successfully", + this.getClass().getName()); + } + } + + /** + * Gets nb of notifications ongoing. + * + * @return the nb of notifications ongoing + */ + public int getNbOfNotificationsOngoing() { + return nbOfNotificationsOngoing; + } + + private void changeControllerStatusIdle() { + if (this.nbOfNotificationsOngoing > 1) { + --this.nbOfNotificationsOngoing; + } else { + this.nbOfNotificationsOngoing = 0; + this.controllerStatus = SdcSingleControllerStatus.IDLE; + } + } + + /** + * Change controller status. + * + * @param newControllerStatus the new controller status + */ + protected final synchronized void changeControllerStatus(SdcSingleControllerStatus newControllerStatus) { + switch (newControllerStatus) { + case BUSY: + ++this.nbOfNotificationsOngoing; + this.controllerStatus = newControllerStatus; + break; + case IDLE: + this.changeControllerStatusIdle(); + break; + default: + this.controllerStatus = newControllerStatus; + break; + } + } + + /** + * Gets controller status. + * + * @return the controller status + */ + public final synchronized SdcSingleControllerStatus getControllerStatus() { + return this.controllerStatus; + } + + /** + * Instantiates a new Sdc single controller. + * + * @param clampProp the clamp prop + * @param csarInstaller the csar installer + * @param sdcSingleConfig the sdc single config + * @param distributionClient the distribution client + */ + public SdcSingleController(ClampProperties clampProp, CsarInstaller csarInstaller, + SdcSingleControllerConfiguration sdcSingleConfig, + IDistributionClient distributionClient) { + this.distributionClient = distributionClient; + isSdcClientAutoManaged = (distributionClient == null); + this.sdcConfig = sdcSingleConfig; + this.refProp = clampProp; + this.csarInstaller = csarInstaller; + } + + /** + * This method initializes the SDC Controller and the SDC Client. + * + * @throws SdcControllerException It throws an exception if the SDC Client + * cannot be instantiated or if an init attempt + * is done when already initialized + */ + public void initSdc() throws SdcControllerException { + logger.info("Attempt to initialize the SDC Controller: " + sdcConfig.getSdcControllerName()); + if (this.getControllerStatus() != SdcSingleControllerStatus.STOPPED) { + throw new SdcControllerException("The controller is already initialized, call the closeSDC method first"); + } + if (distributionClient == null) { + distributionClient = DistributionClientFactory.createDistributionClient(); + } + IDistributionClientResult result = distributionClient.init(sdcConfig, new SdcNotificationCallBack(this)); + if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) { + logger.error("SDC distribution client init failed with reason:" + result.getDistributionMessageResult()); + this.changeControllerStatus(SdcSingleControllerStatus.STOPPED); + throw new SdcControllerException("Initialization of the SDC Controller failed with reason: " + + result.getDistributionMessageResult()); + } + logger.info("SDC Controller successfully initialized: " + sdcConfig.getSdcControllerName()); + logger.info("Attempt to start the SDC Controller: " + sdcConfig.getSdcControllerName()); + result = this.distributionClient.start(); + if (!result.getDistributionActionResult().equals(DistributionActionResultEnum.SUCCESS)) { + logger.error("SDC distribution client start failed with reason:" + result.getDistributionMessageResult()); + this.changeControllerStatus(SdcSingleControllerStatus.STOPPED); + throw new SdcControllerException( + "Startup of the SDC Controller failed with reason: " + result.getDistributionMessageResult()); + } + logger.info("SDC Controller successfully started: " + sdcConfig.getSdcControllerName()); + this.changeControllerStatus(SdcSingleControllerStatus.IDLE); + } + + /** + * This method closes the SDC Controller and the SDC Client. + * + * @throws SdcControllerException It throws an exception if the SDC Client + * cannot be closed because it's currently BUSY + * in processing notifications. + */ + public void closeSdc() throws SdcControllerException { + if (this.getControllerStatus() == SdcSingleControllerStatus.BUSY) { + throw new SdcControllerException("Cannot close the SDC controller as it's currently in BUSY state"); + } + if (this.distributionClient != null) { + this.distributionClient.stop(); + // If auto managed we can set it to Null, SdcController controls it. + // In the other case the client of this class has specified it, so + // we can't reset it + if (isSdcClientAutoManaged) { + // Next init will initialize it with a new SDC Client + this.distributionClient = null; + } + } + this.changeControllerStatus(SdcSingleControllerStatus.STOPPED); + } + + private void sendAllNotificationForCsarHandler(INotificationData notificationData, CsarHandler csar, + NotificationType notificationType, + DistributionStatusEnum distributionStatus, String errorMessage) { + if (csar != null) { + // Notify for the CSAR + this.sendSdcNotification(notificationType, csar.getArtifactElement().getArtifactURL(), + sdcConfig.getConsumerID(), notificationData.getDistributionID(), distributionStatus, errorMessage, + System.currentTimeMillis()); + // Notify for all VF resources found + for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) { + // Normally always 1 artifact in resource for Clamp as we + // specified + // only VF_METADATA type + this.sendSdcNotification(notificationType, + blueprint.getValue().getResourceAttached().getArtifacts().get(0).getArtifactURL(), + sdcConfig.getConsumerID(), notificationData.getDistributionID(), distributionStatus, + errorMessage, System.currentTimeMillis()); + } + } else { + this.sendSdcNotification(notificationType, null, sdcConfig.getConsumerID(), + notificationData.getDistributionID(), distributionStatus, errorMessage, System.currentTimeMillis()); + } + } + + /** + * This method processes the notification received from Sdc. + * + * @param notificationData The INotificationData + */ + public void treatNotification(INotificationData notificationData) { + CsarHandler csar = null; + try { + // wait for a random time, so that 2 running Clamp will not treat + // the same Notification at the same time + Thread.sleep(ThreadLocalRandom.current().nextInt(1, 10) * 1000L); + logger.info("Notification received for service UUID:" + notificationData.getServiceUUID()); + this.changeControllerStatus(SdcSingleControllerStatus.BUSY); + csar = new CsarHandler(notificationData, this.sdcConfig.getSdcControllerName(), + refProp.getStringValue(CONFIG_SDC_FOLDER)); + csar.save(downloadTheArtifact(csar.getArtifactElement())); + if (csarInstaller.isCsarAlreadyDeployed(csar)) { + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD, + DistributionStatusEnum.ALREADY_DOWNLOADED, null); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.ALREADY_DEPLOYED, null); + } else { + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD, + DistributionStatusEnum.DOWNLOAD_OK, null); + csarInstaller.installTheCsar(csar); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_OK, null); + } + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_OK, null); + } catch (SdcArtifactInstallerException | SdcToscaParserException e) { + logger.error("SdcArtifactInstallerException exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } catch (SdcDownloadException | CsarHandlerException e) { + logger.error("SdcDownloadException exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DOWNLOAD, + DistributionStatusEnum.DOWNLOAD_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } catch (InterruptedException e) { + logger.error("Interrupt exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + Thread.currentThread().interrupt(); + } catch (BlueprintParserException e) { + logger.error("BlueprintParser exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } catch (RuntimeException e) { + logger.error("Unexpected exception caught during the notification processing", e); + sendAllNotificationForCsarHandler(notificationData, csar, NotificationType.DEPLOY, + DistributionStatusEnum.DEPLOY_ERROR, e.getMessage()); + this.sendComponentStatus(notificationData, DistributionStatusEnum.COMPONENT_DONE_ERROR, e.getMessage()); + } finally { + this.changeControllerStatus(SdcSingleControllerStatus.IDLE); + } + } + + private enum NotificationType { + /** + * Download notification type. + */ + DOWNLOAD, + /** + * Deploy notification type. + */ + DEPLOY + } + + private IDistributionClientDownloadResult downloadTheArtifact(IArtifactInfo artifact) throws SdcDownloadException { + logger.info("Trying to download the artifact : " + artifact.getArtifactURL() + " UUID: " + + artifact.getArtifactUUID()); + IDistributionClientDownloadResult downloadResult; + try { + downloadResult = distributionClient.download(artifact); + if (null == downloadResult) { + logger.info("downloadResult is Null for: " + artifact.getArtifactUUID()); + return null; + } + } catch (RuntimeException e) { + throw new SdcDownloadException("Exception caught when downloading the artifact", e); + } + if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult())) { + logger.info("Successfully downloaded the artifact " + artifact.getArtifactURL() + " UUID " + + artifact.getArtifactUUID() + "Size of payload " + downloadResult.getArtifactPayload().length); + } else { + throw new SdcDownloadException("Artifact " + artifact.getArtifactName() + + " could not be downloaded from SDC URL " + artifact.getArtifactURL() + " UUID " + + artifact.getArtifactUUID() + ")" + System.lineSeparator() + "Error message is " + + downloadResult.getDistributionMessageResult() + System.lineSeparator()); + } + return downloadResult; + } + + private void sendSdcNotification(NotificationType notificationType, String artifactUrl, String consumerId, + String distributionId, DistributionStatusEnum status, String errorReason, + long timestamp) { + String event = "Sending " + notificationType.name() + "(" + status.name() + ")" + + " notification to SDC for artifact:" + artifactUrl; + if (errorReason != null) { + event = event + "(" + errorReason + ")"; + } + logger.info(event); + String action = ""; + try { + IDistributionStatusMessage message = new DistributionStatusMessage(artifactUrl, consumerId, distributionId, + status, timestamp); + switch (notificationType) { + case DOWNLOAD: + this.sendDownloadStatus(message, errorReason); + action = "sendDownloadStatus"; + break; + case DEPLOY: + this.sendDeploymentStatus(message, errorReason); + action = "sendDeploymentdStatus"; + break; + default: + break; + } + } catch (RuntimeException e) { + logger.warn("Unable to send the SDC Notification (" + action + ") due to an exception", e); + } + logger.info("SDC Notification sent successfully(" + action + ")"); + } + + private void sendComponentStatus(INotificationData notificationData, DistributionStatusEnum status, + String errorReason) { + try { + IComponentDoneStatusMessage message = new IComponentDoneStatusMessage() { + + @Override public String getDistributionID() { + return notificationData.getDistributionID(); + } + + @Override public String getConsumerID() { + return sdcConfig.getConsumerID(); + } + + @Override public long getTimestamp() { + return System.currentTimeMillis(); + } + + @Override public DistributionStatusEnum getStatus() { + return status; + } + + @Override public String getComponentName() { + return sdcConfig.getUser(); + } + }; + + if (errorReason != null) { + this.distributionClient.sendComponentDoneStatus(message, errorReason); + } else { + this.distributionClient.sendComponentDoneStatus(message); + } + } catch (RuntimeException e) { + logger.warn("Unable to send the SDC Notification (" + status.name() + ") due to an exception", e); + } + logger.info("SDC Notification sent successfully(" + status.name() + ")"); + } + + private void sendDownloadStatus(IDistributionStatusMessage message, String errorReason) { + if (errorReason != null) { + this.distributionClient.sendDownloadStatus(message, errorReason); + } else { + this.distributionClient.sendDownloadStatus(message); + } + } + + private void sendDeploymentStatus(IDistributionStatusMessage message, String errorReason) { + if (errorReason != null) { + this.distributionClient.sendDeploymentStatus(message, errorReason); + } else { + this.distributionClient.sendDeploymentStatus(message); + } + } +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/SdcSingleControllerStatus.java b/src/main/java/org/onap/clamp/clds/sdc/controller/SdcSingleControllerStatus.java new file mode 100644 index 000000000..a50e340e3 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/SdcSingleControllerStatus.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.sdc.controller; + +public enum SdcSingleControllerStatus { + STOPPED, IDLE, BUSY +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintArtifact.java b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintArtifact.java new file mode 100644 index 000000000..35bc909dc --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintArtifact.java @@ -0,0 +1,70 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.sdc.controller.installer; + +import org.onap.sdc.api.notification.IResourceInstance; + +/** + * This class is useful to store the information concerning + * blueprint artifact extracted from SDC CSAR. + */ +public class BlueprintArtifact { + + private String dcaeBlueprint; + private String blueprintArtifactName; + private String blueprintInvariantServiceUuid; + private IResourceInstance resourceAttached; + + public String getDcaeBlueprint() { + return dcaeBlueprint; + } + + public void setDcaeBlueprint(String dcaeBlueprint) { + this.dcaeBlueprint = dcaeBlueprint; + } + + public String getBlueprintArtifactName() { + return blueprintArtifactName; + } + + public void setBlueprintArtifactName(String blueprintArtifactName) { + this.blueprintArtifactName = blueprintArtifactName; + } + + public String getBlueprintInvariantServiceUuid() { + return blueprintInvariantServiceUuid; + } + + public void setBlueprintInvariantServiceUuid(String blueprintInvariantServiceUuid) { + this.blueprintInvariantServiceUuid = blueprintInvariantServiceUuid; + } + + public IResourceInstance getResourceAttached() { + return resourceAttached; + } + + public void setResourceAttached(IResourceInstance resourceAttached) { + this.resourceAttached = resourceAttached; + } +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintMicroService.java b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintMicroService.java new file mode 100644 index 000000000..e00ce9430 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintMicroService.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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============================================ + * Modifications copyright (c) 2019-2020 AT&T + * =================================================================== + * + */ + +package org.onap.clamp.clds.sdc.controller.installer; + +import java.util.Objects; + +public class BlueprintMicroService { + private final String name; + private final String modelType; + private final String inputFrom; + private final String modelVersion; + + /** + * The Micro service constructor. + * + * @param name The name in String + * @param modelType The model type + * @param inputFrom Comes from (single chained) + */ + public BlueprintMicroService(String name, String modelType, String inputFrom, String modelVersion) { + this.name = name; + this.inputFrom = inputFrom; + this.modelType = modelType; + this.modelVersion = modelVersion; + } + + public String getName() { + return name; + } + + public String getModelType() { + return modelType; + } + + public String getInputFrom() { + return inputFrom; + } + + /** + * modelVerrsion getter. + * + * @return the modelVersion + */ + public String getModelVersion() { + return modelVersion; + } + + @Override + public String toString() { + return "MicroService {" + "name='" + name + '\'' + ", modelType='" + modelType + '\'' + ", inputFrom='" + + inputFrom + '\'' + ", modelVersion='" + modelVersion + '\'' + '}'; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + BlueprintMicroService that = (BlueprintMicroService) obj; + return name.equals(that.name) && modelType.equals(that.modelType) && inputFrom.equals(that.inputFrom) + && modelVersion.equals(that.modelVersion); + } + + @Override + public int hashCode() { + return Objects.hash(name, modelType, inputFrom, modelVersion); + } +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintParser.java b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintParser.java new file mode 100644 index 000000000..5d5027d29 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/BlueprintParser.java @@ -0,0 +1,222 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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============================================ + * Modifications copyright (c) 2019 AT&T + * =================================================================== + * + */ + +package org.onap.clamp.clds.sdc.controller.installer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.json.JSONObject; +import org.onap.clamp.clds.exception.sdc.controller.BlueprintParserException; +import org.yaml.snakeyaml.Yaml; + +public class BlueprintParser { + + static final String TCA = "TCA"; + private static final String NODE_TEMPLATES = "node_templates"; + private static final String DCAE_NODES = "dcae.nodes."; + private static final String DCAE_NODES_POLICY = ".nodes.policy"; + private static final String TYPE = "type"; + private static final String PROPERTIES = "properties"; + private static final String NAME = "name"; + private static final String INPUT = "inputs"; + private static final String GET_INPUT = "get_input"; + private static final String POLICY_MODEL_ID = "policy_model_id"; + private static final String POLICY_MODEL_VERSION = "policy_model_version"; + private static final String RELATIONSHIPS = "relationships"; + private static final String CLAMP_NODE_RELATIONSHIPS_GETS_INPUT_FROM = "clamp_node.relationships.gets_input_from"; + private static final String TARGET = "target"; + public static final String DEFAULT_VERSION = "1.0.0"; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(BlueprintParser.class); + + private BlueprintParser() { + + } + + /** + * Get all micro services from blueprint. + * + * @param blueprintString the blueprint in a String + * @return A set of MircoService + * @throws BlueprintParserException In case of issues with the parsing + */ + public static Set<BlueprintMicroService> getMicroServices(String blueprintString) throws BlueprintParserException { + Set<BlueprintMicroService> microServices = new HashSet<>(); + JsonObject blueprintJson = BlueprintParser.convertToJson(blueprintString); + JsonObject nodeTemplateList = blueprintJson.get(NODE_TEMPLATES).getAsJsonObject(); + JsonObject inputList = blueprintJson.get(INPUT).getAsJsonObject(); + + for (Entry<String, JsonElement> entry : nodeTemplateList.entrySet()) { + JsonObject nodeTemplate = entry.getValue().getAsJsonObject(); + if (!nodeTemplate.get(TYPE).getAsString().contains(DCAE_NODES_POLICY) + && nodeTemplate.get(TYPE).getAsString().contains(DCAE_NODES)) { + BlueprintMicroService microService = getNodeRepresentation(entry, nodeTemplateList, inputList); + if (!microService.getModelType().isBlank()) { + microServices.add(microService); + } else { + logger.warn("Microservice " + microService.getName() + + " will NOT be used by CLAMP as the model type is not defined or has not been found"); + } + } + } + logger.debug("Those microservices have been found in the blueprint:" + microServices); + return microServices; + } + + /** + * Does a fallback to TCA. + * + * @return The list of microservices + */ + public static List<BlueprintMicroService> fallbackToOneMicroService() { + return Collections.singletonList( + new BlueprintMicroService(TCA, "onap.policies.monitoring.cdap.tca.hi.lo.app", "", DEFAULT_VERSION)); + } + + static String getName(Entry<String, JsonElement> entry) { + String microServiceYamlName = entry.getKey(); + JsonObject ob = entry.getValue().getAsJsonObject(); + if (ob.has(PROPERTIES)) { + JsonObject properties = ob.get(PROPERTIES).getAsJsonObject(); + if (properties.has(NAME)) { + return properties.get(NAME).getAsString(); + } + } + return microServiceYamlName; + } + + static String getInput(Entry<String, JsonElement> entry) { + JsonObject ob = entry.getValue().getAsJsonObject(); + if (ob.has(RELATIONSHIPS)) { + JsonArray relationships = ob.getAsJsonArray(RELATIONSHIPS); + for (JsonElement element : relationships) { + String target = getTarget(element.getAsJsonObject()); + if (!target.isEmpty()) { + return target; + } + } + } + return ""; + } + + static String findPropertyInRelationshipsArray(String propertyName, JsonArray relationshipsArray, + JsonObject blueprintNodeTemplateList, JsonObject blueprintInputList) throws BlueprintParserException { + for (JsonElement elem : relationshipsArray) { + if (blueprintNodeTemplateList.get(elem.getAsJsonObject().get(TARGET).getAsString()) == null) { + throw new BlueprintParserException( + "The Target mentioned in the blueprint is not a known entry in the blueprint: " + + elem.getAsJsonObject().get(TARGET).getAsString()); + } else { + String property = getPropertyValue(propertyName, + new AbstractMap.SimpleEntry<String, JsonElement>( + elem.getAsJsonObject().get(TARGET).getAsString(), blueprintNodeTemplateList + .get(elem.getAsJsonObject().get(TARGET).getAsString()).getAsJsonObject()), + blueprintNodeTemplateList, blueprintInputList); + if (!property.isEmpty()) { + return property; + } + } + } + return ""; + } + + static String getDirectOrInputPropertyValue(String propertyName, JsonObject blueprintInputList, + JsonObject nodeTemplateContent) { + JsonObject properties = nodeTemplateContent.get(PROPERTIES).getAsJsonObject(); + if (properties.has(propertyName)) { + if (properties.get(propertyName).isJsonObject()) { + // it's a blueprint parameter + return blueprintInputList + .get(properties.get(propertyName).getAsJsonObject().get(GET_INPUT).getAsString()) + .getAsJsonObject().get("default").getAsString(); + } else { + // It's a direct value + return properties.get(propertyName).getAsString(); + } + } + return ""; + } + + static String getPropertyValue(String propertyName, Entry<String, JsonElement> nodeTemplateEntry, + JsonObject blueprintNodeTemplateList, JsonObject blueprintIputList) throws BlueprintParserException { + JsonObject nodeTemplateContent = nodeTemplateEntry.getValue().getAsJsonObject(); + // Search first in this node template + if (nodeTemplateContent.has(PROPERTIES)) { + String propValue = getDirectOrInputPropertyValue(propertyName, blueprintIputList, nodeTemplateContent); + if (!propValue.isBlank()) { + return propValue; + } + } + // Or it's may be defined in a relationship + if (nodeTemplateContent.has(RELATIONSHIPS)) { + return findPropertyInRelationshipsArray(propertyName, + nodeTemplateContent.get(RELATIONSHIPS).getAsJsonArray(), blueprintNodeTemplateList, + blueprintIputList); + } + return ""; + } + + static BlueprintMicroService getNodeRepresentation(Entry<String, JsonElement> nodeTemplateEntry, + JsonObject blueprintNodeTemplateList, JsonObject blueprintInputList) throws BlueprintParserException { + String modelIdFound = getPropertyValue(POLICY_MODEL_ID, nodeTemplateEntry, blueprintNodeTemplateList, + blueprintInputList); + String versionFound = getPropertyValue(POLICY_MODEL_VERSION, nodeTemplateEntry, blueprintNodeTemplateList, + blueprintInputList); + if (modelIdFound.isBlank()) { + logger.warn("policy_model_id is not defined for the node template:" + nodeTemplateEntry.getKey()); + } + if (versionFound.isBlank()) { + logger.warn("policy_model_version is not defined (setting it to a default value) for the node template:" + + nodeTemplateEntry.getKey()); + } + return new BlueprintMicroService(getName(nodeTemplateEntry), modelIdFound, getInput(nodeTemplateEntry), + !versionFound.isBlank() ? versionFound : DEFAULT_VERSION); + } + + private static String getTarget(JsonObject elementObject) { + if (elementObject.has(TYPE) && elementObject.has(TARGET) + && elementObject.get(TYPE).getAsString().equals(CLAMP_NODE_RELATIONSHIPS_GETS_INPUT_FROM)) { + return elementObject.get(TARGET).getAsString(); + } + return ""; + } + + private static JsonObject convertToJson(String yamlString) { + Map<String, Object> map = new Yaml().load(yamlString); + return new Gson().fromJson(new JSONObject(map).toString(), JsonObject.class); + } +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/installer/ChainGenerator.java b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/ChainGenerator.java new file mode 100644 index 000000000..2bd259c2b --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/ChainGenerator.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.clds.sdc.controller.installer; + +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.stereotype.Component; + +@Component +public class ChainGenerator { + + ChainGenerator() { + } + + /** + * Get list of microservices chain. + * + * @param input A set of microservices + * @return The list of microservice chained + */ + public List<BlueprintMicroService> getChainOfMicroServices(Set<BlueprintMicroService> input) { + LinkedList<BlueprintMicroService> returnList = new LinkedList<>(); + if (preValidate(input)) { + LinkedList<BlueprintMicroService> theList = new LinkedList<>(); + for (BlueprintMicroService ms : input) { + insertNodeTemplateIntoChain(ms, theList); + } + if (postValidate(theList)) { + returnList = theList; + } + } + return returnList; + } + + private boolean preValidate(Set<BlueprintMicroService> input) { + List<BlueprintMicroService> noInputs = input.stream().filter(ms -> "".equals(ms.getInputFrom())) + .collect(Collectors.toList()); + return noInputs.size() == 1; + } + + private boolean postValidate(LinkedList<BlueprintMicroService> microServices) { + for (int i = 1; i < microServices.size() - 1; i++) { + BlueprintMicroService prev = microServices.get(i - 1); + BlueprintMicroService current = microServices.get(i); + if (!current.getInputFrom().equals(prev.getName())) { + return false; + } + } + return true; + } + + private void insertNodeTemplateIntoChain(BlueprintMicroService microServicetoInsert, + LinkedList<BlueprintMicroService> chainOfMicroServices) { + int insertIndex = 0; + for (int i = 0; i < chainOfMicroServices.size(); i++) { + BlueprintMicroService current = chainOfMicroServices.get(i); + if (microServicetoInsert.getName().equals(current.getInputFrom())) { + insertIndex = i; + break; + } else if (current.getName().equals(microServicetoInsert.getInputFrom())) { + insertIndex = i + 1; + break; + } + } + chainOfMicroServices.add(insertIndex, microServicetoInsert); + } +} diff --git a/src/main/java/org/onap/clamp/clds/sdc/controller/installer/CsarHandler.java b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/CsarHandler.java new file mode 100644 index 000000000..471415a37 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/sdc/controller/installer/CsarHandler.java @@ -0,0 +1,221 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.sdc.controller.installer; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.apache.commons.io.IOUtils; +import org.codehaus.plexus.util.StringUtils; +import org.onap.clamp.clds.exception.sdc.controller.CsarHandlerException; +import org.onap.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.sdc.api.notification.IArtifactInfo; +import org.onap.sdc.api.notification.INotificationData; +import org.onap.sdc.api.notification.IResourceInstance; +import org.onap.sdc.api.results.IDistributionClientDownloadResult; +import org.onap.sdc.tosca.parser.api.ISdcCsarHelper; +import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException; +import org.onap.sdc.tosca.parser.impl.SdcToscaParserFactory; + +/** + * CsarDescriptor that will be used to deploy file in CLAMP file system. Some + * methods can also be used to get some data from it. + */ +public class CsarHandler { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarHandler.class); + private IArtifactInfo artifactElement; + private String csarFilePath; + private String controllerName; + private SdcToscaParserFactory factory = SdcToscaParserFactory.getInstance(); + private ISdcCsarHelper sdcCsarHelper; + private Map<String, BlueprintArtifact> mapOfBlueprints = new HashMap<>(); + public static final String CSAR_TYPE = "TOSCA_CSAR"; + public static final String BLUEPRINT_TYPE = "DCAE_INVENTORY_BLUEPRINT"; + private INotificationData sdcNotification; + public static final String RESOURCE_INSTANCE_NAME_PREFIX = "/Artifacts/Resources/"; + public static final String RESOURCE_INSTANCE_NAME_SUFFIX = "/Deployment/"; + public static final String POLICY_DEFINITION_NAME_SUFFIX = "Definitions/policies.yml"; + public static final String DATA_DEFINITION_NAME_SUFFIX = "Definitions/data.yml"; + public static final String DATA_DEFINITION_KEY = "data_types:"; + + /** + * Constructor for CsarHandler taking sdc notification in input. + */ + public CsarHandler(INotificationData data, String controller, String clampCsarPath) throws CsarHandlerException { + this.sdcNotification = data; + this.controllerName = controller; + this.artifactElement = searchForUniqueCsar(data); + this.csarFilePath = buildFilePathForCsar(artifactElement, clampCsarPath); + } + + private String buildFilePathForCsar(IArtifactInfo artifactElement, String clampCsarPath) { + return clampCsarPath + "/" + controllerName + "/" + artifactElement.getArtifactName(); + } + + private IArtifactInfo searchForUniqueCsar(INotificationData notificationData) throws CsarHandlerException { + List<IArtifactInfo> serviceArtifacts = notificationData.getServiceArtifacts(); + for (IArtifactInfo artifact : serviceArtifacts) { + if (artifact.getArtifactType().equals(CSAR_TYPE)) { + return artifact; + } + } + throw new CsarHandlerException("Unable to find a CSAR in the Sdc Notification"); + } + + /** + * This saves the notification to disk and database. + * + * @param resultArtifact The artifact to install + * @throws SdcArtifactInstallerException In case of issues with the installation + * @throws SdcToscaParserException In case of issues with the parsing of + * the CSAR + */ + public synchronized void save(IDistributionClientDownloadResult resultArtifact) + throws SdcArtifactInstallerException, SdcToscaParserException { + try { + logger.info("Writing CSAR file to: " + csarFilePath + " UUID " + artifactElement.getArtifactUUID() + ")"); + Path path = Paths.get(csarFilePath); + Files.createDirectories(path.getParent()); + // Create or replace the file + try (OutputStream out = Files.newOutputStream(path)) { + out.write(resultArtifact.getArtifactPayload(), 0, resultArtifact.getArtifactPayload().length); + } + sdcCsarHelper = factory.getSdcCsarHelper(csarFilePath); + this.loadDcaeBlueprint(); + } catch (IOException e) { + throw new SdcArtifactInstallerException( + "Exception caught when trying to write the CSAR on the file system to " + csarFilePath, e); + } + } + + private IResourceInstance searchForResourceByInstanceName(String blueprintResourceInstanceName) + throws SdcArtifactInstallerException { + for (IResourceInstance resource : this.sdcNotification.getResources()) { + String filteredString = resource.getResourceInstanceName().replaceAll("-", ""); + filteredString = filteredString.replaceAll(" ", ""); + if (filteredString.equalsIgnoreCase(blueprintResourceInstanceName)) { + return resource; + } + } + throw new SdcArtifactInstallerException("Error when searching for " + blueprintResourceInstanceName + + " as ResourceInstanceName in Sdc notification and did not find it"); + } + + private void loadDcaeBlueprint() throws IOException, SdcArtifactInstallerException { + try (ZipFile zipFile = new ZipFile(csarFilePath)) { + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (!entry.isDirectory() && entry.getName().contains(BLUEPRINT_TYPE)) { + BlueprintArtifact blueprintArtifact = new BlueprintArtifact(); + blueprintArtifact.setBlueprintArtifactName( + entry.getName().substring(entry.getName().lastIndexOf('/') + 1, entry.getName().length())); + blueprintArtifact + .setBlueprintInvariantServiceUuid(this.getSdcNotification().getServiceInvariantUUID()); + try (InputStream stream = zipFile.getInputStream(entry)) { + blueprintArtifact.setDcaeBlueprint(IOUtils.toString(stream, StandardCharsets.UTF_8)); + } + blueprintArtifact.setResourceAttached(searchForResourceByInstanceName(entry.getName().substring( + entry.getName().indexOf(RESOURCE_INSTANCE_NAME_PREFIX) + + RESOURCE_INSTANCE_NAME_PREFIX.length(), + entry.getName().indexOf(RESOURCE_INSTANCE_NAME_SUFFIX)))); + this.mapOfBlueprints.put(blueprintArtifact.getBlueprintArtifactName(), blueprintArtifact); + logger.info("Found a blueprint entry in the CSAR " + blueprintArtifact.getBlueprintArtifactName() + + " for resource instance Name " + + blueprintArtifact.getResourceAttached().getResourceInstanceName()); + } + } + logger.info(this.mapOfBlueprints.size() + " blueprint(s) will be converted to closed loop"); + } + } + + public IArtifactInfo getArtifactElement() { + return artifactElement; + } + + public String getFilePath() { + return csarFilePath; + } + + public String setFilePath(String newPath) { + return csarFilePath = newPath; + } + + public synchronized ISdcCsarHelper getSdcCsarHelper() { + return sdcCsarHelper; + } + + public INotificationData getSdcNotification() { + return sdcNotification; + } + + public Map<String, BlueprintArtifact> getMapOfBlueprints() { + return mapOfBlueprints; + } + + /** + * Get the whole policy model Yaml. It combines the content of policies.yaml and + * data.yaml. + * + * @return The whole policy model yaml + * @throws IOException The IO Exception + */ + public Optional<String> getPolicyModelYaml() throws IOException { + String result = null; + try (ZipFile zipFile = new ZipFile(csarFilePath)) { + ZipEntry entry = zipFile.getEntry(POLICY_DEFINITION_NAME_SUFFIX); + if (entry != null) { + ZipEntry data = zipFile.getEntry(DATA_DEFINITION_NAME_SUFFIX); + if (data != null) { + String dataStr = IOUtils.toString(zipFile.getInputStream(data), StandardCharsets.UTF_8); + String dataStrWithoutHeader = dataStr.substring(dataStr.indexOf(DATA_DEFINITION_KEY)); + String policyStr = IOUtils.toString(zipFile.getInputStream(entry), StandardCharsets.UTF_8); + StringUtils.chomp(policyStr); + result = policyStr.concat(dataStrWithoutHeader); + } else { + result = IOUtils.toString(zipFile.getInputStream(entry), StandardCharsets.UTF_8); + } + } else { + logger.info("Policy model not found inside the CSAR file: " + csarFilePath); + } + return Optional.ofNullable(result); + } + } +} diff --git a/src/main/java/org/onap/clamp/clds/service/CldsHealthcheckService.java b/src/main/java/org/onap/clamp/clds/service/CldsHealthcheckService.java new file mode 100644 index 000000000..3fceace55 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/service/CldsHealthcheckService.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.service; + +import java.util.Date; +import org.onap.clamp.clds.model.CldsHealthCheck; +import org.onap.clamp.clds.util.LoggingUtils; +import org.onap.clamp.clds.util.OnapLogConstants; +import org.onap.clamp.loop.LoopController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Service to retrieve the Health Check of the clds application. + * + */ +@Component +public class CldsHealthcheckService { + + @Autowired + private LoopController loopController; + + protected static final Logger logger = LoggerFactory.getLogger(CldsHealthcheckService.class); + + /** + * REST service that retrieves clds healthcheck information. + * + * @return CldsHealthCheck class containing healthcheck info + */ + public CldsHealthCheck gethealthcheck() { + CldsHealthCheck cldsHealthCheck = new CldsHealthCheck(); + Date startTime = new Date(); + LoggingUtils util = new LoggingUtils(logger); + LoggingUtils.setRequestContext("CldsService: GET healthcheck", "Clamp-Health-Check"); + LoggingUtils.setTimeContext(startTime, new Date()); + try { + loopController.getLoopNames(); + cldsHealthCheck.setHealthCheckComponent("CLDS-APP"); + cldsHealthCheck.setHealthCheckStatus("UP"); + cldsHealthCheck.setDescription("OK"); + LoggingUtils.setResponseContext("0", "Get healthcheck success", + this.getClass().getName()); + util.exiting(HttpStatus.OK.value(), "Healthcheck success", Level.INFO, + OnapLogConstants.ResponseStatus.COMPLETE); + } catch (Exception e) { + logger.error("CLAMP application Heath check failed", e); + LoggingUtils.setResponseContext("999", "Get healthcheck failed", + this.getClass().getName()); + cldsHealthCheck.setHealthCheckComponent("CLDS-APP"); + cldsHealthCheck.setHealthCheckStatus("DOWN"); + cldsHealthCheck.setDescription("NOT-OK"); + util.exiting(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Healthcheck failed", Level.INFO, + OnapLogConstants.ResponseStatus.ERROR); + } + return cldsHealthCheck; + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/JsonEditorSchemaConstants.java b/src/main/java/org/onap/clamp/clds/tosca/JsonEditorSchemaConstants.java new file mode 100644 index 000000000..e3c661698 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/JsonEditorSchemaConstants.java @@ -0,0 +1,86 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018-2019 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.onap.clamp.clds.tosca; + +public class JsonEditorSchemaConstants { + + //Data types in JSON Schema + public static final String TYPE_OBJECT = "object"; + public static final String TYPE_ARRAY = "array"; + public static final String TYPE_MAP = "map"; + public static final String TYPE_STRING = "string"; + public static final String TYPE_INTEGER = "integer"; + public static final String TYPE_DATE_TIME = "datetime"; + + //Key elements in JSON Schema + public static final String TYPE = "type"; + public static final String TITLE = "title"; + public static final String REQUIRED = "required"; + public static final String DEFAULT = "default"; + public static final String ENUM = "enum"; + public static final String ENUM_TITLES = "enum_titles"; + public static final String OPTIONS = "options"; + public static final String FORMAT = "format"; + public static final String ITEMS = "items"; + public static final String PROPERTIES = "properties"; + public static final String PROPERTY_ORDER = "propertyOrder"; + public static final String VALUES = "values"; + public static final String HEADER_TEMPLATE = "headerTemplate"; + public static final String HEADER_TEMPLATE_VALUE = "{{self.name}}"; + + public static final String MINIMUM = "minimum"; + public static final String MAXIMUM = "maximum"; + public static final String MIN_LENGTH = "minLength"; + public static final String MAX_LENGTH = "maxLength"; + public static final String EXCLUSIVE_MINIMUM = "exclusiveMinimum"; + public static final String EXCLUSIVE_MAXIMUM = "exclusiveMaximum"; + public static final String MINITEMS = "minItems"; + public static final String MAXITEMS = "maxItems"; + + public static final String CUSTOM_KEY_FORMAT = "format"; + public static final String CUSTOM_KEY_FORMAT_TABS_TOP = "tabs-top"; + public static final String CUSTOM_KEY_FORMAT_TABS = "tabs"; + public static final String CUSTOM_KEY_FORMAT_INPUT = "input"; + public static final String FORMAT_SELECT = "select"; + public static final String UNIQUE_ITEMS = "uniqueItems"; + public static final String TRUE = "true"; + public static final String QSSCHEMA = "qschema"; + public static final String TYPE_QBLDR = "qbldr"; + + public static final String ID = "id"; + public static final String LABEL = "label"; + public static final String OPERATORS = "operators"; + public static final String FILTERS = "filters"; + + public static final String SCHEMA = "schema"; + public static final String CURRENT_VALUES = "currentValues"; + + public static final String PLUGIN = "plugin"; + public static final String DATE_TIME_PICKER = "datetimepicker"; + public static final String VALIDATION = "validation"; + public static final String DATE_TIME_FORMAT = "YYYY/MM/DD HH:mm:ss"; + public static final String INPUT_EVENT = "input_event"; + public static final String DP_CHANGE = "dp.change"; + +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/ToscaSchemaConstants.java b/src/main/java/org/onap/clamp/clds/tosca/ToscaSchemaConstants.java new file mode 100644 index 000000000..d00c431c8 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/ToscaSchemaConstants.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.tosca; + +public class ToscaSchemaConstants { + + // Data types in TOSCA Schema + public static final String TYPE_LIST = "list"; + public static final String TYPE_MAP = "map"; + public static final String TYPE_STRING = "string"; + public static final String TYPE_INTEGER = "integer"; + public static final String TYPE_NUMBER = "number"; + public static final String TYPE_DATE_TIME = "datetime"; + public static final String TYPE_FLOAT = "float"; + public static final String TYPE_BOOLEAN = "boolean"; + public static final String TYPE_USER_DEFINED = "userDefined"; + + // Key elements in Tosca + public static final String NODE_TYPES = "policy_types"; + public static final String DATA_TYPES = "data_types"; + public static final String TYPE = "type"; + public static final String DESCRIPTION = "description"; + public static final String DEFAULT = "default"; + public static final String PROPERTIES = "properties"; + public static final String REQUIRED = "required"; + public static final String ENTRY_SCHEMA = "entry_schema"; + + public static final String METADATA = "metadata"; + public static final String METADATA_POLICY_MODEL_TYPE = "policy_model_type"; + public static final String METADATA_ACRONYM = "acronym"; + public static final String METADATA_ELEMENT_NAME = "element_name"; + public static final String METADATA_HEADER_TEMPLATE = "header_template"; + public static final String METADATA_CLAMP_POSSIBLE_VALUES = "clamp_possible_values"; + + // Constraints + public static final String CONSTRAINTS = "constraints"; + public static final String VALID_VALUES = "valid_values"; + public static final String EQUAL = "equal"; + public static final String GREATER_THAN = "greater_than"; + public static final String GREATER_OR_EQUAL = "greater_or_equal"; + public static final String LESS_THAN = "less_than"; + public static final String LESS_OR_EQUAL = "less_or_equal"; + public static final String IN_RANGE = "in_range"; + public static final String LENGTH = "length"; + public static final String MIN_LENGTH = "min_length"; + public static final String MAX_LENGTH = "max_length"; + public static final String PATTERN = "pattern"; + + // Prefix for policy nodes + public static final String POLICY_NODE = "onap.policies."; + + // Prefix for data nodes + public static final String POLICY_DATA = "onap.datatypes."; + + // Prefix for dictionary elements + public static final String DICTIONARY = "Dictionary:"; + + // Custom Elements that must exist in the Tosca models + public static final String NAME = "name"; + public static final String CONTEXT = "context"; + +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/ToscaYamlToJsonConvertor.java b/src/main/java/org/onap/clamp/clds/tosca/ToscaYamlToJsonConvertor.java new file mode 100644 index 000000000..45bb87ed8 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/ToscaYamlToJsonConvertor.java @@ -0,0 +1,780 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.tosca; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.stream.Collectors; +import org.json.JSONArray; +import org.json.JSONObject; +import org.onap.clamp.clds.config.ClampProperties; +import org.onap.clamp.tosca.Dictionary; +import org.onap.clamp.tosca.DictionaryElement; +import org.onap.clamp.tosca.DictionaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.yaml.snakeyaml.Yaml; + +/** + * Tosca Model Yaml parser and convertor to JSON Schema consumable for JSON + * Editor. + * + */ +@Component +public class ToscaYamlToJsonConvertor { + + @Autowired + private DictionaryService dictionaryService; + + @Autowired + private ClampProperties refProp; + + private int simpleTypeOrder = 1000; + private int complexTypeOrder = 10000; + private int complexSimpleTypeOrder = 1; + + private int incrementSimpleTypeOrder() { + return simpleTypeOrder++; + } + + private int incrementComplexTypeOrder() { + return complexTypeOrder = complexTypeOrder + 10000; + } + + private int incrementComplexSimpleTypeOrder() { + complexSimpleTypeOrder++; + return complexTypeOrder + complexSimpleTypeOrder; + } + + /** + * Parses Tosca YAML string and Converts to JsonObject. + * + * @param yamlString YAML string + * @return JsonObject + */ + public JsonObject validateAndConvertToJson(String yamlString) { + + Yaml yaml = new Yaml(); + LinkedHashMap<String, Object> loadedYaml = yaml.load(yamlString); + if (loadedYaml == null) { + return null; + } + + JSONObject jsonObject = new JSONObject(loadedYaml); + return new Gson().fromJson(jsonObject.toString(), JsonObject.class); + } + + /** + * return the values by looking up the key in the Toscsa JSON object. + * + * @param obj Tosca Json Object + * @param key the parameter key to look up + * @return the value for the provided key + */ + public String getValueFromMetadata(JsonObject obj, String key) { + JsonElement jsonElement = obj.get(ToscaSchemaConstants.NODE_TYPES); + if (jsonElement.isJsonObject()) { + Iterator<Entry<String, JsonElement>> itr = + jsonElement.getAsJsonObject().entrySet().iterator(); + while (itr.hasNext()) { + Entry<String, JsonElement> entry = itr.next(); + if (entry.getValue() != null && entry.getValue().isJsonObject() + && entry.getValue().getAsJsonObject().has(ToscaSchemaConstants.METADATA)) { + JsonObject metadatas = entry.getValue().getAsJsonObject() + .get(ToscaSchemaConstants.METADATA).getAsJsonObject(); + if (metadatas.has(key)) { + return metadatas.get(key).getAsString(); + } + } + } + } + return null; + } + + /** + * Parses Tosca YAML string. + * + * @param yamlString YAML string + * @param modelTypeToUse The model type that must be used to obtain the Json + * Schema + * @return JSON string + */ + public String parseToscaYaml(String yamlString, String modelTypeToUse) { + + Yaml yaml = new Yaml(); + LinkedHashMap<String, Object> loadedYaml = yaml.load(yamlString); + if (loadedYaml == null) { + return ""; + } + LinkedHashMap<String, Object> nodeTypes = new LinkedHashMap<>(); + LinkedHashMap<String, Object> dataNodes = new LinkedHashMap<>(); + JSONObject jsonParentObject = new JSONObject(); + JSONObject jsonTempObject = new JSONObject(); + parseNodeAndDataType(loadedYaml, nodeTypes, dataNodes); + populateJsonEditorObject(loadedYaml, nodeTypes, dataNodes, jsonParentObject, jsonTempObject, + modelTypeToUse); + + String headerTemplate = getValueFromMetadata(validateAndConvertToJson(yamlString), + ToscaSchemaConstants.METADATA_HEADER_TEMPLATE); + if (headerTemplate != null) { + jsonParentObject.put(JsonEditorSchemaConstants.HEADER_TEMPLATE, + JsonEditorSchemaConstants.HEADER_TEMPLATE_VALUE); + } + if (jsonTempObject.length() > 0) { + jsonParentObject = jsonTempObject; + } + JSONObject jsonEditorObject = new JSONObject(); + jsonEditorObject.put(JsonEditorSchemaConstants.SCHEMA, jsonParentObject); + return jsonEditorObject.toString(); + } + + // Parse node_type and data_type + @SuppressWarnings("unchecked") + private void parseNodeAndDataType(LinkedHashMap<String, Object> map, + LinkedHashMap<String, Object> nodeTypes, LinkedHashMap<String, Object> dataNodes) { + map.entrySet().stream().forEach(n -> { + if (n.getKey().contains(ToscaSchemaConstants.NODE_TYPES) + && n.getValue() instanceof Map) { + parseNodeAndDataType((LinkedHashMap<String, Object>) n.getValue(), nodeTypes, + dataNodes); + } else if (n.getKey().contains(ToscaSchemaConstants.DATA_TYPES) + && n.getValue() instanceof Map) { + parseNodeAndDataType((LinkedHashMap<String, Object>) n.getValue(), nodeTypes, + dataNodes); + } else if (n.getKey().contains(ToscaSchemaConstants.POLICY_NODE)) { + nodeTypes.put(n.getKey(), n.getValue()); + } else if (n.getKey().contains(ToscaSchemaConstants.POLICY_DATA)) { + dataNodes.put(n.getKey(), n.getValue()); + } + }); + } + + @SuppressWarnings("unchecked") + private void populateJsonEditorObject(LinkedHashMap<String, Object> map, + LinkedHashMap<String, Object> nodeTypes, LinkedHashMap<String, Object> dataNodes, + JSONObject jsonParentObject, JSONObject jsonTempObject, String modelTypeToUse) { + + Map<String, JSONObject> jsonEntrySchema = new HashMap<>(); + jsonParentObject.put(JsonEditorSchemaConstants.TYPE, JsonEditorSchemaConstants.TYPE_OBJECT); + if (nodeTypes.get(modelTypeToUse) instanceof Map) { + ((LinkedHashMap<String, Object>) nodeTypes.get(modelTypeToUse)).entrySet() + .forEach(ntElement -> { + if (ntElement.getKey().equalsIgnoreCase(ToscaSchemaConstants.PROPERTIES)) { + JSONArray rootNodeArray = new JSONArray(); + if (ntElement.getValue() instanceof Map) { + ((LinkedHashMap<String, Object>) ntElement.getValue()).entrySet() + .forEach((ntPropertiesElement) -> { + boolean isListNode = false; + parseDescription( + (LinkedHashMap<String, Object>) ntPropertiesElement + .getValue(), + jsonParentObject); + LinkedHashMap<String, Object> parentPropertiesMap = + (LinkedHashMap<String, Object>) ntPropertiesElement + .getValue(); + if (parentPropertiesMap.containsKey(ToscaSchemaConstants.TYPE) + && ((String) parentPropertiesMap + .get(ToscaSchemaConstants.TYPE)) + .contains(ToscaSchemaConstants.TYPE_MAP) + && parentPropertiesMap + .containsKey(ToscaSchemaConstants.ENTRY_SCHEMA)) { + parentPropertiesMap = + (LinkedHashMap<String, Object>) parentPropertiesMap + .get(ToscaSchemaConstants.ENTRY_SCHEMA); + isListNode = true; + } + if (parentPropertiesMap.containsKey(ToscaSchemaConstants.TYPE) + && ((String) parentPropertiesMap + .get(ToscaSchemaConstants.TYPE)) + .contains(ToscaSchemaConstants.POLICY_DATA)) { + ((LinkedHashMap<String, Object>) dataNodes.get( + parentPropertiesMap.get(ToscaSchemaConstants.TYPE))) + .entrySet().stream().forEach(pmap -> { + if (pmap.getKey().equalsIgnoreCase( + ToscaSchemaConstants.PROPERTIES)) { + parseToscaProperties( + ToscaSchemaConstants.POLICY_NODE, + (LinkedHashMap<String, Object>) pmap + .getValue(), + jsonParentObject, rootNodeArray, + jsonEntrySchema, dataNodes, + incrementSimpleTypeOrder()); + } + }); + } + if (isListNode) { + jsonTempObject.put(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_ARRAY); + parseDescription( + (LinkedHashMap<String, Object>) ntPropertiesElement + .getValue(), + jsonTempObject); + jsonTempObject.put(JsonEditorSchemaConstants.ITEMS, + jsonParentObject); + jsonTempObject.put(JsonEditorSchemaConstants.FORMAT, + JsonEditorSchemaConstants.CUSTOM_KEY_FORMAT_TABS); + jsonTempObject.put(JsonEditorSchemaConstants.UNIQUE_ITEMS, + JsonEditorSchemaConstants.TRUE); + } + }); + } + } + }); + } + } + + @SuppressWarnings("unchecked") + private void parseToscaProperties(String parentKey, LinkedHashMap<String, Object> propertiesMap, + JSONObject jsonDataNode, JSONArray array, Map<String, JSONObject> jsonEntrySchema, + LinkedHashMap<String, Object> dataNodes, final int order) { + JSONObject jsonPropertyNode = new JSONObject(); + propertiesMap.entrySet().stream().forEach(p -> { + // Populate JSON Array for "required" key + + if (p.getValue() instanceof Map) { + LinkedHashMap<String, Object> nodeMap = + (LinkedHashMap<String, Object>) p.getValue(); + if (nodeMap.containsKey(ToscaSchemaConstants.REQUIRED) + && ((boolean) nodeMap.get(ToscaSchemaConstants.REQUIRED))) { + array.put(p.getKey()); + } + // if(nodeMap.containsKey(ToscaSchemaConstants.CONSTRAINTS)) + parseToscaChildNodeMap(p.getKey(), nodeMap, jsonPropertyNode, jsonEntrySchema, + dataNodes, array, incrementSimpleTypeOrder()); + } + }); + jsonDataNode.put(JsonEditorSchemaConstants.REQUIRED, array); + jsonDataNode.put(JsonEditorSchemaConstants.PROPERTIES, jsonPropertyNode); + } + + @SuppressWarnings("unchecked") + private void parseToscaPropertiesForType(String parentKey, + LinkedHashMap<String, Object> propertiesMap, JSONObject jsonDataNode, JSONArray array, + Map<String, JSONObject> jsonEntrySchema, LinkedHashMap<String, Object> dataNodes, + boolean isType, int order) { + JSONObject jsonPropertyNode = new JSONObject(); + + propertiesMap.entrySet().stream().forEach(p -> { + // array.put(p.getKey()); + boolean overWriteArray = false; + if (p.getValue() instanceof Map) { + LinkedHashMap<String, Object> nodeMap = + (LinkedHashMap<String, Object>) p.getValue(); + if (!(parentKey.contains(ToscaSchemaConstants.ENTRY_SCHEMA) + || parentKey.contains(ToscaSchemaConstants.POLICY_NODE)) + && nodeMap.containsKey(ToscaSchemaConstants.TYPE) + && (((String) nodeMap.get(ToscaSchemaConstants.TYPE)) + .contains(ToscaSchemaConstants.POLICY_DATA))) { + overWriteArray = true; + } + if (nodeMap.containsKey(ToscaSchemaConstants.REQUIRED) + && ((boolean) nodeMap.get(ToscaSchemaConstants.REQUIRED))) { + array.put(p.getKey()); + } + parseToscaChildNodeMap(p.getKey(), nodeMap, jsonPropertyNode, jsonEntrySchema, + dataNodes, array, order); + } + }); + jsonDataNode.put(JsonEditorSchemaConstants.REQUIRED, array); + jsonDataNode.put(JsonEditorSchemaConstants.PROPERTIES, jsonPropertyNode); + } + + private void parseToscaChildNodeMap(String childObjectKey, + LinkedHashMap<String, Object> childNodeMap, JSONObject jsonPropertyNode, + Map<String, JSONObject> jsonEntrySchema, LinkedHashMap<String, Object> dataNodes, + JSONArray array, int order) { + JSONObject childObject = new JSONObject(); + // JSONArray childArray = new JSONArray(); + parseDescription(childNodeMap, childObject); + parseTypes(childObjectKey, childNodeMap, childObject, jsonEntrySchema, dataNodes, array, + order); + parseConstraints(childNodeMap, childObject); + parseMetadataPossibleValues(childNodeMap, childObject); + parseEntrySchema(childNodeMap, childObject, jsonPropertyNode, jsonEntrySchema, dataNodes); + + jsonPropertyNode.put(childObjectKey, childObject); + order++; + + } + + private void parseEntrySchema(LinkedHashMap<String, Object> childNodeMap, + JSONObject childObject, JSONObject jsonPropertyNode, + Map<String, JSONObject> jsonEntrySchema, LinkedHashMap<String, Object> dataNodes) { + if (childNodeMap.get(ToscaSchemaConstants.ENTRY_SCHEMA) != null) { + if (childNodeMap.get(ToscaSchemaConstants.ENTRY_SCHEMA) instanceof Map) { + LinkedHashMap<String, Object> entrySchemaMap = + (LinkedHashMap<String, Object>) childNodeMap + .get(ToscaSchemaConstants.ENTRY_SCHEMA); + entrySchemaMap.entrySet().stream().forEach(entry -> { + if (entry.getKey().equalsIgnoreCase(ToscaSchemaConstants.TYPE) + && entry.getValue() != null) { + String entrySchemaType = (String) entry.getValue(); + if (entrySchemaType.contains(ToscaSchemaConstants.POLICY_DATA)) { + JSONArray array = new JSONArray(); + if (jsonEntrySchema.get(entrySchemaType) != null) { + // Already traversed + JSONObject entrySchemaObject = jsonEntrySchema.get(entrySchemaType); + attachEntrySchemaJsonObject(childObject, entrySchemaObject, + JsonEditorSchemaConstants.TYPE_OBJECT); + } else if (dataNodes.containsKey(entrySchemaType)) { + + JSONObject entrySchemaObject = new JSONObject(); + // Need to traverse + ((LinkedHashMap<String, Object>) dataNodes.get(entrySchemaType)) + .entrySet().stream().forEach(pmap -> { + if (pmap.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.PROPERTIES)) { + parseToscaProperties(ToscaSchemaConstants.ENTRY_SCHEMA, + (LinkedHashMap<String, Object>) pmap.getValue(), + entrySchemaObject, array, jsonEntrySchema, + dataNodes, incrementComplexTypeOrder()); + jsonEntrySchema.put(entrySchemaType, entrySchemaObject); + dataNodes.remove(entrySchemaType); + attachEntrySchemaJsonObject(childObject, + entrySchemaObject, + JsonEditorSchemaConstants.TYPE_OBJECT); + } + + }); + } + } else if (entrySchemaType + .equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING) + || entrySchemaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_INTEGER) + || entrySchemaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_FLOAT)) { + JSONObject entrySchemaObject = new JSONObject(); + parseConstraints(entrySchemaMap, entrySchemaObject); + parseMetadataPossibleValues(entrySchemaMap, entrySchemaObject); + String jsontype = JsonEditorSchemaConstants.TYPE_STRING; + if (entrySchemaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_INTEGER) + || entrySchemaType + .equalsIgnoreCase(ToscaSchemaConstants.TYPE_FLOAT)) { + jsontype = JsonEditorSchemaConstants.TYPE_INTEGER; + } + if (childNodeMap.get(ToscaSchemaConstants.TYPE) != null) { + // Only known value of type is String for now + if (childNodeMap.get(ToscaSchemaConstants.TYPE) instanceof String) { + String typeValue = + (String) childNodeMap.get(ToscaSchemaConstants.TYPE); + if (typeValue + .equalsIgnoreCase(ToscaSchemaConstants.TYPE_LIST)) { + // Custom key for JSON Editor and UI rendering + childObject.put(JsonEditorSchemaConstants.CUSTOM_KEY_FORMAT, + JsonEditorSchemaConstants.FORMAT_SELECT); + // childObject.put(JsonEditorSchemaConstants.UNIQUE_ITEMS, + // JsonEditorSchemaConstants.TRUE); + } + } + } + attachEntrySchemaJsonObject(childObject, entrySchemaObject, jsontype); + } + } + }); + } + } + } + + private void attachEntrySchemaJsonObject(JSONObject childObject, JSONObject entrySchemaObject, + String dataType) { + + entrySchemaObject.put(JsonEditorSchemaConstants.TYPE, dataType); + childObject.put(JsonEditorSchemaConstants.ITEMS, entrySchemaObject); + } + + @SuppressWarnings("unchecked") + private void attachTypeJsonObject(JSONObject childObject, JSONObject typeObject) { + Iterator<String> keys = typeObject.keys(); + while (keys.hasNext()) { + String key = keys.next(); + childObject.put(key, typeObject.get(key)); + } + } + + /* + * private String parseKey(String toscaKey, String lookupString) { return + * toscaKey.substring(toscaKey.indexOf(lookupString) + lookupString.length(), + * toscaKey.length()); } + */ + + private void parseDescription(LinkedHashMap<String, Object> childNodeMap, + JSONObject childObject) { + if (childNodeMap.get(ToscaSchemaConstants.DESCRIPTION) != null) { + childObject.put(JsonEditorSchemaConstants.TITLE, + childNodeMap.get(ToscaSchemaConstants.DESCRIPTION)); + } + } + + private void parseTypes(String childObjectKey, LinkedHashMap<String, Object> childNodeMap, + JSONObject childObject, Map<String, JSONObject> jsonEntrySchema, + LinkedHashMap<String, Object> dataNodes, JSONArray array, int order) { + if (childNodeMap.get(ToscaSchemaConstants.TYPE) != null) { + // Only known value of type is String for now + if (childNodeMap.get(ToscaSchemaConstants.TYPE) instanceof String) { + childObject.put(JsonEditorSchemaConstants.PROPERTY_ORDER, order); + String typeValue = (String) childNodeMap.get(ToscaSchemaConstants.TYPE); + if (typeValue.equalsIgnoreCase(ToscaSchemaConstants.TYPE_INTEGER)) { + childObject.put(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_INTEGER); + + } else if (typeValue.equalsIgnoreCase(ToscaSchemaConstants.TYPE_FLOAT)) { + childObject.put(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_INTEGER); + } else if (typeValue.equalsIgnoreCase(ToscaSchemaConstants.TYPE_LIST)) { + childObject.put(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_ARRAY); + // Custom key for JSON Editor and UI rendering + childObject.put(JsonEditorSchemaConstants.CUSTOM_KEY_FORMAT, + JsonEditorSchemaConstants.CUSTOM_KEY_FORMAT_TABS_TOP); + childObject.put(JsonEditorSchemaConstants.UNIQUE_ITEMS, + JsonEditorSchemaConstants.TRUE); + } else if (typeValue.equalsIgnoreCase(ToscaSchemaConstants.TYPE_MAP)) { + childObject.put(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_OBJECT); + } else if (typeValue.contains(ToscaSchemaConstants.POLICY_DATA)) { + JSONArray childArray = new JSONArray(); + + if (jsonEntrySchema.get(typeValue) != null) { + // Already traversed + JSONObject entrySchemaObject = jsonEntrySchema.get(typeValue); + attachTypeJsonObject(childObject, entrySchemaObject); + } else if (dataNodes.containsKey(typeValue)) { + JSONObject entrySchemaObject = new JSONObject(); + // Need to traverse + JSONArray jsonArray = new JSONArray(); + ((LinkedHashMap<String, Object>) dataNodes.get(typeValue)).entrySet() + .stream().forEach(pmap -> { + if (pmap.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.PROPERTIES)) { + parseToscaPropertiesForType(childObjectKey, + (LinkedHashMap<String, Object>) pmap.getValue(), + entrySchemaObject, childArray, jsonEntrySchema, dataNodes, + true, incrementComplexSimpleTypeOrder()); + jsonEntrySchema.put(typeValue, entrySchemaObject); + dataNodes.remove(typeValue); + attachTypeJsonObject(childObject, entrySchemaObject); + } + }); + } + } else { + childObject.put(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_STRING); + } + } + if (childNodeMap.get(ToscaSchemaConstants.DEFAULT) != null) { + childObject.put(JsonEditorSchemaConstants.DEFAULT, + childNodeMap.get(ToscaSchemaConstants.DEFAULT)); + } + } + } + + private void parseConstraints(LinkedHashMap<String, Object> childNodeMap, + JSONObject childObject) { + if (childNodeMap.containsKey(ToscaSchemaConstants.CONSTRAINTS) + && childNodeMap.get(ToscaSchemaConstants.CONSTRAINTS) != null) { + List<LinkedHashMap<String, Object>> constraintsList = + (List<LinkedHashMap<String, Object>>) childNodeMap + .get(ToscaSchemaConstants.CONSTRAINTS); + constraintsList.stream().forEach(c -> { + if (c instanceof Map) { + c.entrySet().stream().forEach(constraint -> { + if (constraint.getKey().equalsIgnoreCase(ToscaSchemaConstants.MIN_LENGTH) + || constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.GREATER_OR_EQUAL)) { + // For String min_lenghth is minimum length whereas for number, it will + // be + // minimum or greater than to the defined value + if (childNodeMap.containsKey(ToscaSchemaConstants.TYPE) + && (childNodeMap.get(ToscaSchemaConstants.TYPE) instanceof String) + && ((String) childNodeMap.get(ToscaSchemaConstants.TYPE)) + .equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING)) { + childObject.put(JsonEditorSchemaConstants.MIN_LENGTH, + constraint.getValue()); + } else { + childObject.put(JsonEditorSchemaConstants.MINIMUM, + constraint.getValue()); + } + } else if (constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.MAX_LENGTH) + || constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.LESS_OR_EQUAL)) { + // For String max_lenghth is maximum length whereas for number, it will + // be + // maximum or less than the defined value + if (childNodeMap.containsKey(ToscaSchemaConstants.TYPE) + && (childNodeMap.get(ToscaSchemaConstants.TYPE) instanceof String) + && ((String) childNodeMap.get(ToscaSchemaConstants.TYPE)) + .equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING)) { + childObject.put(JsonEditorSchemaConstants.MAX_LENGTH, + constraint.getValue()); + } else { + childObject.put(JsonEditorSchemaConstants.MAXIMUM, + constraint.getValue()); + } + } else if (constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.LESS_THAN)) { + childObject.put(JsonEditorSchemaConstants.EXCLUSIVE_MAXIMUM, + constraint.getValue()); + } else if (constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.GREATER_THAN)) { + childObject.put(JsonEditorSchemaConstants.EXCLUSIVE_MINIMUM, + constraint.getValue()); + } else if (constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.IN_RANGE)) { + if (constraint.getValue() instanceof ArrayList<?>) { + if (childNodeMap.containsKey(ToscaSchemaConstants.TYPE) + && (childNodeMap + .get(ToscaSchemaConstants.TYPE) instanceof String) + && ((String) childNodeMap.get(ToscaSchemaConstants.TYPE)) + .equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING)) { + childObject.put(JsonEditorSchemaConstants.MIN_LENGTH, + ((ArrayList) constraint.getValue()).get(0)); + childObject.put(JsonEditorSchemaConstants.MAX_LENGTH, + ((ArrayList) constraint.getValue()).get(1)); + } else { + childObject.put(JsonEditorSchemaConstants.MINIMUM, + ((ArrayList) constraint.getValue()).get(0)); + childObject.put(JsonEditorSchemaConstants.MAXIMUM, + ((ArrayList) constraint.getValue()).get(1)); + } + + } + } else if (constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.VALID_VALUES)) { + JSONArray validValuesArray = new JSONArray(); + + if (constraint.getValue() instanceof ArrayList<?>) { + boolean processDictionary = + ((ArrayList<?>) constraint.getValue()).stream().anyMatch( + value -> (value instanceof String && ((String) value) + .contains(ToscaSchemaConstants.DICTIONARY))); + if (!processDictionary) { + ((ArrayList<?>) constraint.getValue()).stream() + .forEach(value -> { + validValuesArray.put(value); + }); + childObject.put(JsonEditorSchemaConstants.ENUM, + validValuesArray); + } else { + ((ArrayList<?>) constraint.getValue()).stream() + .forEach(value -> { + if ((value instanceof String && ((String) value) + .contains(ToscaSchemaConstants.DICTIONARY))) { + processDictionaryElements(childObject, + (String) value); + } + + }); + + } + } + + } + }); + } + }); + } + } + + private void parseMetadataPossibleValues(LinkedHashMap<String, Object> childNodeMap, + JSONObject childObject) { + if (childNodeMap.containsKey(ToscaSchemaConstants.METADATA) + && childNodeMap.get(ToscaSchemaConstants.METADATA) != null) { + LinkedHashMap<String, Object> metadataMap = + (LinkedHashMap<String, Object>) childNodeMap.get(ToscaSchemaConstants.METADATA); + if (metadataMap instanceof Map) { + metadataMap.entrySet().stream().forEach(constraint -> { + if (constraint.getKey() + .equalsIgnoreCase(ToscaSchemaConstants.METADATA_CLAMP_POSSIBLE_VALUES)) { + JSONArray validValuesArray = new JSONArray(); + + if (constraint.getValue() instanceof ArrayList<?>) { + boolean processDictionary = ((ArrayList<?>) constraint.getValue()) + .stream().anyMatch(value -> (value instanceof String + && ((String) value).contains(ToscaSchemaConstants.DICTIONARY))); + if (processDictionary) { + ((ArrayList<?>) constraint.getValue()).stream().forEach(value -> { + if ((value instanceof String && ((String) value) + .contains(ToscaSchemaConstants.DICTIONARY))) { + processDictionaryElements(childObject, (String) value); + } + + }); + + } + } + + } + }); + } + } + } + + private void processDictionaryElements(JSONObject childObject, String dictionaryReference) { + if (dictionaryReference.contains("#")) { + String[] dictionaryKeyArray = dictionaryReference + .substring(dictionaryReference.indexOf(ToscaSchemaConstants.DICTIONARY) + 11, + dictionaryReference.length()) + .split("#"); + // We support only one # as of now. + List<DictionaryElement> cldsDictionaryElements = null; + List<DictionaryElement> subDictionaryElements = null; + if (dictionaryKeyArray != null && dictionaryKeyArray.length == 2) { + cldsDictionaryElements = dictionaryService.getDictionary(dictionaryKeyArray[0]) + .getDictionaryElements().stream().collect(Collectors.toList()); + subDictionaryElements = dictionaryService.getDictionary(dictionaryKeyArray[1]) + .getDictionaryElements().stream().collect(Collectors.toList()); + + if (cldsDictionaryElements != null) { + List<String> subCldsDictionaryNames = subDictionaryElements.stream() + .map(DictionaryElement::getShortName).collect(Collectors.toList()); + JSONArray jsonArray = new JSONArray(); + + Optional.ofNullable(cldsDictionaryElements).get().stream().forEach(c -> { + JSONObject jsonObject = new JSONObject(); + if (c.getSubDictionary() != null) { + Dictionary subDictionary = + dictionaryService.getDictionary(c.getSubDictionary()); + if (subDictionary != null + && !subDictionary.getDictionaryElements().isEmpty()) { + + jsonObject.put(JsonEditorSchemaConstants.CUSTOM_KEY_FORMAT_INPUT, + JsonEditorSchemaConstants.FORMAT_SELECT); + + List<String> shortNames = new ArrayList<>(); + subDictionary.getDictionaryElements().stream().forEach(c1 -> { + shortNames.add(c1.getShortName()); + }); + jsonObject.put(JsonEditorSchemaConstants.VALUES, shortNames); + } + } + jsonObject.put(JsonEditorSchemaConstants.TYPE, getJsonType(c.getType())); + + if (c.getType() != null + && (c.getType().equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING) + || c.getType().equalsIgnoreCase(ToscaSchemaConstants.TYPE_DATE_TIME) + || c.getType().equalsIgnoreCase(ToscaSchemaConstants.TYPE_MAP))) { + jsonObject.put(JsonEditorSchemaConstants.MIN_LENGTH, 1); + + if (c.getType().equalsIgnoreCase(ToscaSchemaConstants.TYPE_DATE_TIME)) { + jsonObject.put(JsonEditorSchemaConstants.PLUGIN, + JsonEditorSchemaConstants.DATE_TIME_PICKER); + jsonObject.put(JsonEditorSchemaConstants.INPUT_EVENT, + JsonEditorSchemaConstants.DP_CHANGE); + JSONObject formatJsonObject = new JSONObject(); + formatJsonObject.put(JsonEditorSchemaConstants.FORMAT, + JsonEditorSchemaConstants.DATE_TIME_FORMAT); + jsonObject.put(JsonEditorSchemaConstants.VALIDATION, + formatJsonObject); + } + } + + jsonObject.put(JsonEditorSchemaConstants.ID, c.getName()); + jsonObject.put(JsonEditorSchemaConstants.LABEL, c.getShortName()); + jsonObject.put(JsonEditorSchemaConstants.OPERATORS, subCldsDictionaryNames); + jsonArray.put(jsonObject); + });; + JSONObject filterObject = new JSONObject(); + filterObject.put(JsonEditorSchemaConstants.FILTERS, jsonArray); + + childObject.put(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_QBLDR); + // TO invoke validation on such parameters + childObject.put(JsonEditorSchemaConstants.MIN_LENGTH, 1); + childObject.put(JsonEditorSchemaConstants.QSSCHEMA, filterObject); + + } + } + } else { + String dictionaryKey = dictionaryReference.substring( + dictionaryReference.indexOf(ToscaSchemaConstants.DICTIONARY) + 11, + dictionaryReference.length()); + + if (dictionaryKey != null) { + if (dictionaryKey.contains(ToscaSchemaConstants.TYPE_USER_DEFINED)) { + childObject.put(JsonEditorSchemaConstants.ENUM, new ArrayList<>()); + // Add Enum titles for generated translated values during + // JSON instance generation + JSONObject enumTitles = new JSONObject(); + enumTitles.put(JsonEditorSchemaConstants.ENUM_TITLES, new ArrayList<>()); + childObject.put(JsonEditorSchemaConstants.OPTIONS, enumTitles); + } else { + List<DictionaryElement> cldsDictionaryElements = + dictionaryService.getDictionary(dictionaryKey).getDictionaryElements() + .stream().collect(Collectors.toList()); + if (cldsDictionaryElements != null) { + List<String> cldsDictionaryNames = new ArrayList<>(); + List<String> cldsDictionaryFullNames = new ArrayList<>(); + cldsDictionaryElements.stream().forEach(c -> { + // Json type will be translated before Policy creation + if (c.getType() != null && !c.getType().equalsIgnoreCase("json")) { + cldsDictionaryFullNames.add(c.getName()); + } + cldsDictionaryNames.add(c.getShortName()); + }); + + if (!cldsDictionaryFullNames.isEmpty()) { + childObject.put(JsonEditorSchemaConstants.ENUM, + cldsDictionaryFullNames); + // Add Enum titles for generated translated values during JSON instance + // generation + JSONObject enumTitles = new JSONObject(); + enumTitles.put(JsonEditorSchemaConstants.ENUM_TITLES, + cldsDictionaryNames); + childObject.put(JsonEditorSchemaConstants.OPTIONS, enumTitles); + } else { + childObject.put(JsonEditorSchemaConstants.ENUM, cldsDictionaryNames); + } + + } + } + } + } + } + + private String getJsonType(String toscaType) { + String jsonType = null; + if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_INTEGER) + || toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_NUMBER)) { + jsonType = JsonEditorSchemaConstants.TYPE_INTEGER; + } else if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_DATE_TIME)) { + jsonType = JsonEditorSchemaConstants.TYPE_DATE_TIME; + } else if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_LIST)) { + jsonType = JsonEditorSchemaConstants.TYPE_ARRAY; + } else if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_MAP)) { + jsonType = JsonEditorSchemaConstants.TYPE_MAP; + } else { + jsonType = JsonEditorSchemaConstants.TYPE_STRING; + } + return jsonType; + } + +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java b/src/main/java/org/onap/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java new file mode 100644 index 000000000..5832986a1 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/ToscaConverterWithDictionarySupport.java @@ -0,0 +1,98 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.io.IOException; +import org.onap.clamp.clds.config.ClampProperties; +import org.onap.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser; +import org.onap.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParserWithDictionarySupport; +import org.onap.clamp.clds.tosca.update.templates.JsonTemplateManager; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.loop.service.Service; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ToscaConverterWithDictionarySupport { + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(ToscaConverterWithDictionarySupport.class); + + private ClampProperties clampProperties; + private ToscaMetadataParser metadataParser; + + /** + * Constructor with Spring support. + * + * @param clampProperties Clamp Spring properties + * @param metadataParser Metadata parser + */ + @Autowired + public ToscaConverterWithDictionarySupport(ClampProperties clampProperties, + ToscaMetadataParserWithDictionarySupport metadataParser) { + this.clampProperties = clampProperties; + this.metadataParser = metadataParser; + } + + /** + * This method converts a tosca file to a json schema. + * It uses some parameters specified in the application.properties. + * + * @param toscaFile The tosca file as String + * @param policyTypeToDecode The policy type to decode + * @param serviceModel The service model associated so that the clamp enrichment could be done if required by + * the tosca model + * @return A json object being a json schema + */ + public JsonObject convertToscaToJsonSchemaObject(String toscaFile, String policyTypeToDecode, + Service serviceModel) { + try { + return new JsonTemplateManager(toscaFile, + clampProperties.getFileContent("tosca.converter.default.datatypes"), + clampProperties.getFileContent("tosca.converter.json.schema.templates")) + .getJsonSchemaForPolicyType(policyTypeToDecode, Boolean.parseBoolean(clampProperties.getStringValue( + "tosca.converter.dictionary.support.enabled")) ? metadataParser : null, serviceModel); + } catch (IOException | UnknownComponentException e) { + logger.error("Unable to convert the tosca properly, exception caught during the decoding", + e); + return new JsonObject(); + } + } + + /** + * This method converts a tosca file to a json schema. + * It uses some parameters specified in the application.properties. + * + * @param toscaFile The tosca file as String + * @param policyTypeToDecode The policy type to decode + * @param serviceModel The service Model so that clamp enrichment could be done if required by tosca model + * @return A String containing the json schema + */ + public String convertToscaToJsonSchemaString(String toscaFile, String policyTypeToDecode, Service serviceModel) { + return JsonUtils.GSON.toJson(this.convertToscaToJsonSchemaObject(toscaFile, policyTypeToDecode, serviceModel)); + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/UnknownComponentException.java b/src/main/java/org/onap/clamp/clds/tosca/update/UnknownComponentException.java new file mode 100644 index 000000000..e30f9158b --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/UnknownComponentException.java @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update; + +public class UnknownComponentException extends Exception { + public UnknownComponentException(String nameEntry) { + this.getWrongName(nameEntry); + } + + public String getWrongName(String nameEntry) { + return "Unknown Component: " + nameEntry; + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/elements/ArrayField.java b/src/main/java/org/onap/clamp/clds/tosca/update/elements/ArrayField.java new file mode 100644 index 000000000..83f792f3f --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/elements/ArrayField.java @@ -0,0 +1,72 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.elements;
+
+import com.google.gson.JsonArray;
+import java.util.ArrayList;
+
+public class ArrayField {
+
+ private ArrayList<Object> complexFields;
+
+ /**
+ * Constructor from arraryList.
+ *
+ * @param arrayProperties the array properties
+ */
+ public ArrayField(ArrayList<Object> arrayProperties) {
+ this.complexFields = arrayProperties;
+ }
+
+ /**
+ * Each LinkedHashMap is parsed to extract the Array and each of its value. They are casted for the JsonObject.
+ *
+ * @return JsonArray
+ */
+ public JsonArray deploy() {
+
+ JsonArray subPropertyValuesArray = new JsonArray();
+ for (Object arrayElement : complexFields) {
+ //Cast for each Primitive Type
+ String typeValue = arrayElement.getClass().getSimpleName();
+ switch (typeValue) {
+ case "String":
+ subPropertyValuesArray.add((String) arrayElement);
+ break;
+ case "Boolean":
+ subPropertyValuesArray.add((Boolean) arrayElement);
+ break;
+ case "Double":
+ subPropertyValuesArray.add((Number) arrayElement);
+ break;
+ case "Integer":
+ subPropertyValuesArray.add((Number) arrayElement);
+ break;
+ default:
+ break;
+ }
+ }
+ return subPropertyValuesArray;
+ }
+}
diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/elements/Constraint.java b/src/main/java/org/onap/clamp/clds/tosca/update/elements/Constraint.java new file mode 100644 index 000000000..d6bd355e3 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/elements/Constraint.java @@ -0,0 +1,222 @@ +/*-
+ * ============LICENSE_START=======================================================
+ * ONAP CLAMP
+ * ================================================================================
+ * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.elements;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+import org.onap.clamp.clds.tosca.update.templates.JsonTemplate;
+
+public class Constraint {
+
+ private LinkedHashMap<String, Object> constraints;
+ private JsonTemplate jsonTemplate;
+
+ public Constraint(LinkedHashMap<String, Object> constraints, JsonTemplate jsonTemplate) {
+ this.jsonTemplate = jsonTemplate;
+ this.constraints = constraints;
+ }
+
+ /**
+ * Deploy the linkedhashmap which contains the constraints, to extract them one to one.
+ *
+ * @param jsonSchema The json Schema
+ * @param typeProperty The ype property
+ * @return the json object
+ */
+ public JsonObject deployConstraints(JsonObject jsonSchema, String typeProperty) {
+ for (Entry<String, Object> constraint : constraints.entrySet()) {
+ this.parseConstraint(jsonSchema, constraint.getKey(), constraint.getValue(), typeProperty);
+ }
+ return jsonSchema;
+ }
+
+ /**
+ * Each case of Tosca constraints below parse specifically the field in the JsonObject.
+ *
+ * @param jsonSchema Json Schema
+ * @param nameConstraint Name constraint
+ * @param valueConstraint value constraint
+ * @param typeProperty Type Property
+ */
+ @SuppressWarnings("unchecked")
+ public void parseConstraint(JsonObject jsonSchema, String nameConstraint, Object valueConstraint,
+ String typeProperty) {
+ switch (nameConstraint) {
+ case "equal":
+ checkTemplateField("const", jsonSchema, valueConstraint);
+ break;
+ case "greater_than":
+ checkTemplateField("exclusiveMinimum", jsonSchema, valueConstraint);
+ break;
+ case "greater_or_equal":
+ checkTemplateField("minimum", jsonSchema, valueConstraint);
+ break;
+ case "less_than":
+ checkTemplateField("exclusiveMaximum", jsonSchema, valueConstraint);
+ break;
+ case "less_or_equal":
+ checkTemplateField("maximum", jsonSchema, valueConstraint);
+ break;
+ case "in_range":
+ ArrayList<Integer> limitValues = (ArrayList<Integer>) valueConstraint;
+ checkTemplateField("minimum", jsonSchema, limitValues.get(0));
+ checkTemplateField("maximum", jsonSchema, limitValues.get(1));
+ break;
+ case "pattern":
+ jsonSchema.addProperty(nameConstraint, (String) valueConstraint);
+ break;
+ case "length":
+ this.getSpecificLength(jsonSchema, valueConstraint, typeProperty);
+ break;
+ case "min_length":
+ String[] prefixValues = nameConstraint.split("_");
+ this.getLimitValue(jsonSchema, valueConstraint, typeProperty, prefixValues[0]);
+ break;
+ case "max_length":
+ String[] maxtab = nameConstraint.split("_");
+ this.getLimitValue(jsonSchema, valueConstraint, typeProperty, maxtab[0]);
+ break;
+ default://valid_value
+ this.getValueArray(jsonSchema, valueConstraint, typeProperty);
+ break;
+ }
+
+ }
+
+ /**
+ * To be done.
+ *
+ * @param jsonSchema json schema
+ * @param fieldValue field value
+ * @param typeProperty For the complex components, get a specific number of items/properties
+ */
+ public void getSpecificLength(JsonObject jsonSchema, Object fieldValue, String typeProperty) {
+ switch (typeProperty.toLowerCase()) {
+ case "string":
+ checkTemplateField("minLength", jsonSchema, fieldValue);
+ checkTemplateField("maxLength", jsonSchema, fieldValue);
+ break;
+ case "array":
+ if (fieldValue.equals(1) && jsonTemplate.hasFields("uniqueItems")) {
+ jsonSchema.addProperty("uniqueItems", true);
+ } else {
+ checkTemplateField("minItems", jsonSchema, fieldValue);
+ checkTemplateField("maxItems", jsonSchema, fieldValue);
+ }
+ break;
+ default:// Map && List
+ checkTemplateField("minProperties", jsonSchema, fieldValue);
+ checkTemplateField("maxProperties", jsonSchema, fieldValue);
+ break;
+ }
+
+ }
+
+ /**
+ * To be done.
+ *
+ * @param jsonSchema json schema
+ * @param fieldValue field value
+ * @param typeProperty type property
+ * @param side Get the limits fieldValue for the properties : depend of the type of the component
+ */
+ public void getLimitValue(JsonObject jsonSchema, Object fieldValue, String typeProperty, String side) {
+ switch (typeProperty) {
+ case "string":
+ if (side.equals("min")) {
+ checkTemplateField("minLength", jsonSchema, fieldValue);
+ } else {
+ checkTemplateField("maxLength", jsonSchema, fieldValue);
+ }
+ break;
+ default:// Array
+ if (side.equals("min")) {
+ checkTemplateField("minItems", jsonSchema, fieldValue);
+ } else {
+ checkTemplateField("maxItems", jsonSchema, fieldValue);
+ }
+ break;
+ }
+
+ }
+
+ /**
+ * To be done.
+ *
+ * @param jsonSchema Json schema
+ * @param fieldValue field value
+ * @param typeProperty Get as Enum the valid values for the property
+ */
+ public void getValueArray(JsonObject jsonSchema, Object fieldValue, String typeProperty) {
+ if (jsonTemplate.hasFields("enum")) {
+ JsonArray enumeration = new JsonArray();
+ if (typeProperty.equals("string") || typeProperty.equals("String")) {
+ ArrayList<String> arrayValues = (ArrayList<String>) fieldValue;
+ for (String arrayItem : arrayValues) {
+ enumeration.add(arrayItem);
+ }
+ jsonSchema.add("enum", enumeration);
+ } else {
+ ArrayList<Number> arrayValues = (ArrayList<Number>) fieldValue;
+ for (Number arrayItem : arrayValues) {
+ enumeration.add(arrayItem);
+ }
+ jsonSchema.add("enum", enumeration);
+ }
+ }
+ }
+
+ /**
+ * To be done.
+ *
+ * @param field Field
+ * @param jsonSchema Json schema
+ * @param fieldValue Simple way to avoid code duplication
+ */
+ public void checkTemplateField(String field, JsonObject jsonSchema, Object fieldValue) {
+ if (jsonTemplate.hasFields(field)) {
+ String typeField = fieldValue.getClass().getSimpleName();
+ switch (typeField) {
+ case "String":
+ jsonSchema.addProperty(field, (String) fieldValue);
+ break;
+ case "Integer":
+ jsonSchema.addProperty(field, (Integer) fieldValue);
+ break;
+ case "Number":
+ jsonSchema.addProperty(field, (Number) fieldValue);
+ break;
+ case "Boolean":
+ jsonSchema.addProperty(field, (Boolean) fieldValue);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/elements/ToscaElement.java b/src/main/java/org/onap/clamp/clds/tosca/update/elements/ToscaElement.java new file mode 100644 index 000000000..9035a5806 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/elements/ToscaElement.java @@ -0,0 +1,121 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.elements; + +import java.util.ArrayList; +import java.util.LinkedHashMap; + +public class ToscaElement { + + /** + * name parameter is used as "key", in the LinkedHashMap of Components. + */ + private String name; + private String derivedFrom; + private String version; + private String typeVersion; + private String description; + private LinkedHashMap<String, ToscaElementProperty> properties; + + public ToscaElement() { + } + + /** + * Constructor. + * + * @param name name + * @param derivedFrom derivedFrom + * @param description description + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public ToscaElement(String name, String derivedFrom, String description) { + super(); + this.name = name; + this.derivedFrom = derivedFrom; + this.description = description; + this.properties = new LinkedHashMap(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDerivedFrom() { + return derivedFrom; + } + + public void setDerivedFrom(String derivedFrom) { + this.derivedFrom = derivedFrom; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getTypeVersion() { + return typeVersion; + } + + public void setTypeVersion(String typeVersion) { + this.typeVersion = typeVersion; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LinkedHashMap<String, ToscaElementProperty> getProperties() { + return properties; + } + + public void setProperties(LinkedHashMap<String, ToscaElementProperty> properties) { + this.properties = properties; + } + + public void addProperties(ToscaElementProperty toscaElementProperty) { + this.properties.put(toscaElementProperty.getName(), toscaElementProperty); + } + + public ArrayList<String> propertiesNames() { + return new ArrayList<>(properties.keySet()); + } + + @Override + public String toString() { + return name + ": " + description + ", version: " + version + ", nb de properties: " + properties.size() + + System.getProperty("line.separator") + propertiesNames(); + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/elements/ToscaElementProperty.java b/src/main/java/org/onap/clamp/clds/tosca/update/elements/ToscaElementProperty.java new file mode 100644 index 000000000..c5ab5a18e --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/elements/ToscaElementProperty.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.elements; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import org.onap.clamp.clds.tosca.update.templates.JsonTemplate; + +public class ToscaElementProperty { + + /** + * name parameter is used as "key", in the LinkedHashMap of Components. + */ + private String name; + private LinkedHashMap<String, Object> items; + + /** + * Constructor. + * + * @param name the name + * @param items the items + */ + public ToscaElementProperty(String name, LinkedHashMap<String, Object> items) { + super(); + this.name = name; + this.items = items; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LinkedHashMap<String, Object> getItems() { + return items; + } + + public void setItems(LinkedHashMap<String, Object> items) { + this.items = items; + } + + /** + * For each primitive value, requires to get each field Value and cast it and add it in a Json. + * + * @param fieldsContent field + * @param fieldName field + * @param value value + */ + public void addFieldToJson(JsonObject fieldsContent, String fieldName, Object value) { + if (value != null) { + String typeValue = value.getClass().getSimpleName(); + switch (typeValue) { + case "String": + fieldsContent.addProperty(fieldName, (String) value); + break; + case "Boolean": + fieldsContent.addProperty(fieldName, (Boolean) value); + break; + case "Double": + fieldsContent.addProperty(fieldName, (Number) value); + break; + case "Integer": + fieldsContent.addProperty(fieldName, (Integer) value); + break; + default: + fieldsContent.add(fieldName, parseArray((ArrayList) value)); + break; + } + } + } + + /** + * If a field value is an Array, create an Instance of ArrayField to insert if in the JsonObject. + * + * @param arrayProperties array pro + * @return a json array + */ + public JsonArray parseArray(ArrayList<Object> arrayProperties) { + JsonArray arrayContent = new JsonArray(); + ArrayList<Object> arrayComponent = new ArrayList<>(); + for (Object itemArray : arrayProperties) { + arrayComponent.add(itemArray); + } + ArrayField af = new ArrayField(arrayComponent); + arrayContent = af.deploy(); + return arrayContent; + } + + /** + * Create an instance of Constraint, to extract the values and add it to the Json (according to the type + * * of the current property). + * + * @param json a json + * @param constraints constraints + * @param jsonTemplate template + */ + @SuppressWarnings("unchecked") + public void addConstraintsAsJson(JsonObject json, ArrayList<Object> constraints, JsonTemplate jsonTemplate) { + for (Object constraint : constraints) { + if (constraint instanceof LinkedHashMap) { + LinkedHashMap<String, Object> valueConstraint = (LinkedHashMap<String, Object>) constraint; + Constraint constraintParser = new Constraint(valueConstraint, jsonTemplate); + constraintParser.deployConstraints(json, (String) getItems().get("type")); + } + } + + } + +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java b/src/main/java/org/onap/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java new file mode 100644 index 000000000..885e755bd --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/execution/ToscaMetadataExecutor.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.execution; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.onap.clamp.clds.tosca.update.execution.cds.ToscaMetadataCdsProcess; +import org.onap.clamp.clds.tosca.update.execution.target.ToscaMetadataTargetProcess; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.tosca.DictionaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * This class is used to execute a code based on a key found in the metadata section. + */ +@Component +public class ToscaMetadataExecutor { + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(ToscaMetadataExecutor.class); + + @Autowired + private DictionaryService dictionaryService; + + private Map<String, ToscaMetadataProcess> mapOfProcesses = new HashMap<>(); + + /** + * This method executes the required process specified in processInfo. + * + * @param processInfo A String containing the process to execute, like "cds/param1:value1/param2:value2" + * @param childObject The jsonObject + * @param serviceModel The service model associated to do clamp enrichment + */ + public void executeTheProcess(String processInfo, JsonObject childObject, Service serviceModel) { + String[] processParameters = (processInfo + "/ ").split("/"); + logger.info("Executing the Tosca clamp process " + processParameters[0] + " with parameters " + + processParameters[1].trim()); + mapOfProcesses.get(processParameters[0].trim()) + .executeProcess(processParameters[1].trim(), childObject, serviceModel); + } + + /** + * Init method. + */ + @PostConstruct + public void init() { + mapOfProcesses.put("CDS", new ToscaMetadataCdsProcess()); + mapOfProcesses.put("CSAR_RESOURCES", new ToscaMetadataTargetProcess()); + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java b/src/main/java/org/onap/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java new file mode 100644 index 000000000..214eadb03 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/execution/ToscaMetadataProcess.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.execution; + +import com.google.gson.JsonObject; +import org.onap.clamp.loop.service.Service; + +/** + * This code is the interface that must be implemented to have a tosca process. + */ +public abstract class ToscaMetadataProcess { + + /** + * This method add some elements to the JsonObject childObject passed in argument. + * The process can take multiple parameters in arguments. + * + * @param parameters The parameters required by the process + * @param childObject The Json Object modified by the current process + * @param serviceModel The service model associated to do clamp enrichment + */ + public abstract void executeProcess(String parameters, JsonObject childObject, Service serviceModel); +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java b/src/main/java/org/onap/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java new file mode 100644 index 000000000..39fa25a2b --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/execution/cds/ToscaMetadataCdsProcess.java @@ -0,0 +1,220 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.execution.cds; + +import static org.onap.clamp.clds.tosca.ToscaSchemaConstants.TYPE; +import static org.onap.clamp.clds.tosca.ToscaSchemaConstants.TYPE_LIST; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.Map; +import java.util.Set; +import org.onap.clamp.clds.tosca.update.execution.ToscaMetadataProcess; +import org.onap.clamp.loop.service.Service; + +/** + * This class is there to add the JsonObject for CDS in the json Schema according to what is found in the Tosca model. + */ +public class ToscaMetadataCdsProcess extends ToscaMetadataProcess { + + @Override + public void executeProcess(String parameters, JsonObject childObject, Service serviceModel) { + switch (parameters) { + case "actor": + JsonArray jsonArray = new JsonArray(); + jsonArray.add("CDS"); + addToJsonArray(childObject, "enum", jsonArray); + break; + case "payload": + generatePayload(childObject, serviceModel); + break; + case "operation": + generateOperation(childObject, serviceModel); + break; + default: + } + } + + private static void generatePayload(JsonObject childObject, Service serviceModel) { + JsonArray schemaAnyOf = new JsonArray(); + schemaAnyOf.addAll(createBlankEntry()); + schemaAnyOf.addAll(generatePayloadPerResource("VF", serviceModel)); + schemaAnyOf.addAll(generatePayloadPerResource("PNF", serviceModel)); + addToJsonArray(childObject, "anyOf", schemaAnyOf); + } + + private static void generateOperation(JsonObject childObject, Service serviceModel) { + generateOperationPerResource(childObject, "VF", serviceModel); + generateOperationPerResource(childObject, "PNF", serviceModel); + } + + private static void generateOperationPerResource(JsonObject childObject, String resourceName, + Service serviceModel) { + JsonArray schemaEnum = new JsonArray(); + JsonArray schemaTitle = new JsonArray(); + for (Map.Entry<String, JsonElement> entry : serviceModel.getResourceDetails().getAsJsonObject(resourceName) + .entrySet()) { + JsonObject controllerProperties = entry.getValue().getAsJsonObject() + .getAsJsonObject("controllerProperties"); + if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) { + for (String workflowsEntry : controllerProperties.getAsJsonObject("workflows").keySet()) { + schemaEnum.add(workflowsEntry); + schemaTitle.add(workflowsEntry + " (CDS operation)"); + } + } + } + addToJsonArray(childObject, "enum", schemaEnum); + if (childObject.get("options") == null) { + JsonObject optionsSection = new JsonObject(); + childObject.add("options", optionsSection); + } + addToJsonArray(childObject.getAsJsonObject("options"), "enum_titles", schemaTitle); + + } + + private static JsonArray generatePayloadPerResource(String resourceName, + Service serviceModel) { + JsonArray schemaAnyOf = new JsonArray(); + + for (Map.Entry<String, JsonElement> entry : serviceModel.getResourceDetails().getAsJsonObject(resourceName) + .entrySet()) { + JsonObject controllerProperties = entry.getValue().getAsJsonObject() + .getAsJsonObject("controllerProperties"); + if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) { + for (Map.Entry<String, JsonElement> workflowsEntry : controllerProperties.getAsJsonObject("workflows") + .entrySet()) { + JsonObject obj = new JsonObject(); + obj.addProperty("title", workflowsEntry.getKey()); + obj.add("properties", + createInputPropertiesForPayload(workflowsEntry.getValue().getAsJsonObject(), + controllerProperties, + workflowsEntry.getKey())); + schemaAnyOf.add(obj); + } + } + } + return schemaAnyOf; + } + + private static JsonArray createBlankEntry() { + JsonArray result = new JsonArray(); + JsonObject blankObject = new JsonObject(); + blankObject.addProperty("title", "User defined"); + blankObject.add("properties", new JsonObject()); + result.add(blankObject); + return result; + } + + private static JsonObject createAnyOfJsonProperty(String name, + String defaultValue, + boolean readOnlyFlag) { + JsonObject result = new JsonObject(); + result.addProperty("title", name); + result.addProperty("type", "string"); + result.addProperty("default", defaultValue); + result.addProperty("readOnly", readOnlyFlag); + return result; + } + + private static void addToJsonArray(JsonObject childObject, String section, JsonArray value) { + if (childObject.getAsJsonArray(section) != null) { + childObject.getAsJsonArray(section).addAll(value); + } else { + childObject.add(section, value); + } + } + + /** + * Returns the properties of payload based on the cds work flows. + * + * @param workFlow cds work flows to update payload + * @param controllerProperties cds properties to get blueprint name and + * version + * @param workFlowName work flow name + * @return returns the properties of payload + */ + public static JsonObject createInputPropertiesForPayload(JsonObject workFlow, + JsonObject controllerProperties, + String workFlowName) { + String artifactName = controllerProperties.get("sdnc_model_name").getAsString(); + String artifactVersion = controllerProperties.get("sdnc_model_version").getAsString(); + JsonObject inputs = workFlow.getAsJsonObject("inputs"); + JsonObject jsonObject = new JsonObject(); + jsonObject.add("artifact_name", createAnyOfJsonProperty( + "artifact name", artifactName, true)); + jsonObject.add("artifact_version", createAnyOfJsonProperty( + "artifact version", artifactVersion, true)); + jsonObject.add("mode", createAnyOfJsonProperty( + "mode", "async", false)); + jsonObject.add("data", createDataProperty(inputs, workFlowName)); + return jsonObject; + } + + private static JsonObject createDataProperty(JsonObject inputs, String workFlowName) { + JsonObject data = new JsonObject(); + data.addProperty("title", "data"); + data.addProperty("type", "string"); + data.addProperty("format", "textarea"); + JsonObject defaultValue = new JsonObject(); + addDefaultValueForData(inputs, defaultValue, workFlowName); + data.addProperty("default", defaultValue.toString()); + return data; + } + + private static void addDefaultValueForData(JsonObject inputs, + JsonObject defaultValue, + String workFlowName) { + Set<Map.Entry<String, JsonElement>> entrySet = inputs.entrySet(); + for (Map.Entry<String, JsonElement> entry : entrySet) { + String key = entry.getKey(); + JsonObject inputProperty = inputs.getAsJsonObject(key); + if (key.equalsIgnoreCase(workFlowName + "-properties")) { + addDefaultValueForData(entry.getValue().getAsJsonObject().get("properties") + .getAsJsonObject(), defaultValue, workFlowName); + } else if ("object".equalsIgnoreCase(inputProperty.get(TYPE).getAsString())) { + JsonObject object = new JsonObject(); + addDefaultValueForData(entry.getValue().getAsJsonObject().get("properties") + .getAsJsonObject(), object, workFlowName); + defaultValue.add(entry.getKey(), object); + } else if (TYPE_LIST.equalsIgnoreCase(inputProperty.get(TYPE).getAsString())) { + defaultValue.add(entry.getKey(), handleListType(entry.getValue().getAsJsonObject(), workFlowName)); + } else { + defaultValue.addProperty(entry.getKey(), ""); + } + } + } + + private static JsonArray handleListType(JsonObject inputs, + String workFlowName) { + + JsonObject object = new JsonObject(); + if (inputs.get("properties") != null) { + addDefaultValueForData(inputs.get("properties").getAsJsonObject(), object, workFlowName); + } + JsonArray arr = new JsonArray(); + arr.add(object); + return arr; + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/execution/target/ToscaMetadataTargetProcess.java b/src/main/java/org/onap/clamp/clds/tosca/update/execution/target/ToscaMetadataTargetProcess.java new file mode 100644 index 000000000..8b8fa1784 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/execution/target/ToscaMetadataTargetProcess.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.execution.target; + +import com.google.gson.JsonObject; +import org.onap.clamp.clds.tosca.update.execution.ToscaMetadataProcess; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.policy.operational.OperationalPolicyRepresentationBuilder; + +/** + * This class is there to add the JsonObject for CDS in the json Schema according to what is found in the Tosca model. + */ +public class ToscaMetadataTargetProcess extends ToscaMetadataProcess { + + @Override + public void executeProcess(String parameters, JsonObject childObject, Service serviceModel) { + childObject.add("anyOf", OperationalPolicyRepresentationBuilder.createAnyOfArray(serviceModel, false)); + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java b/src/main/java/org/onap/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java new file mode 100644 index 000000000..9721e33d9 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/parser/ToscaConverterToJsonSchema.java @@ -0,0 +1,346 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.parser; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import org.onap.clamp.clds.tosca.update.elements.ToscaElement; +import org.onap.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.onap.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser; +import org.onap.clamp.clds.tosca.update.templates.JsonTemplate; +import org.onap.clamp.loop.service.Service; + +public class ToscaConverterToJsonSchema { + private LinkedHashMap<String, ToscaElement> components; + private LinkedHashMap<String, JsonTemplate> templates; + + private ToscaMetadataParser metadataParser; + + private Service serviceModel; + + /** + * Constructor. + * + * @param toscaElementsMap All the tosca elements found (policy type + data types + native tosca datatypes) + * @param jsonSchemaTemplates All Json schema templates to use + * @param metadataParser The metadata parser to use for metadata section + * @param serviceModel The service model for clamp enrichment + */ + public ToscaConverterToJsonSchema(LinkedHashMap<String, ToscaElement> toscaElementsMap, + LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates, + ToscaMetadataParser metadataParser, Service serviceModel) { + this.components = toscaElementsMap; + this.templates = jsonSchemaTemplates; + this.metadataParser = metadataParser; + this.serviceModel = serviceModel; + } + + /** + * For a given component, launch process to parse it in Json. + * + * @param toscaElementKey name components + * @return return + */ + public JsonObject getJsonSchemaOfToscaElement(String toscaElementKey) { + return this.getFieldAsObject(getToscaElement(toscaElementKey)); + } + + /** + * Return the classical/general fields of the component, & launch the properties deployment. + * + * @param toscaElement the compo + * @return a json object + */ + public JsonObject getFieldAsObject(ToscaElement toscaElement) { + + JsonObject globalFields = new JsonObject(); + if (templates.get("object").hasFields("title")) { + globalFields.addProperty("title", toscaElement.getName()); + } + if (templates.get("object").hasFields("type")) { + globalFields.addProperty("type", "object"); + } + if (templates.get("object").hasFields("description")) { + if (toscaElement.getDescription() != null) { + globalFields.addProperty("description", toscaElement.getDescription()); + } + } + if (templates.get("object").hasFields("required")) { + globalFields.add("required", this.getRequirements(toscaElement.getName())); + } + if (templates.get("object").hasFields("properties")) { + globalFields.add("properties", this.deploy(toscaElement.getName())); + } + return globalFields; + } + + /** + * Get the required properties of the Component, including the parents properties requirements. + * + * @param nameComponent name component + * @return a json array + */ + public JsonArray getRequirements(String nameComponent) { + JsonArray requirements = new JsonArray(); + ToscaElement toParse = components.get(nameComponent); + //Check for a father component, and launch the same process + if (!toParse.getDerivedFrom().equals("tosca.datatypes.Root") + && !toParse.getDerivedFrom().equals("tosca.policies.Root")) { + requirements.addAll(getRequirements(toParse.getDerivedFrom())); + } + //Each property is checked, and add to the requirement array if it's required + Collection<ToscaElementProperty> properties = toParse.getProperties().values(); + for (ToscaElementProperty toscaElementProperty : properties) { + if (toscaElementProperty.getItems().containsKey("required") + && toscaElementProperty.getItems().get("required").equals(true)) { + requirements.add(toscaElementProperty.getName()); + } + } + return requirements; + } + + /** + * The beginning of the recursive process. Get the parents (or not) to launch the same process, and otherwise + * deploy and parse the properties. + * + * @param nameComponent name component + * @return a json object + */ + public JsonObject deploy(String nameComponent) { + JsonObject jsonSchema = new JsonObject(); + ToscaElement toParse = components.get(nameComponent); + //Check for a father component, and launch the same process + if (!toParse.getDerivedFrom().equals("tosca.datatypes.Root") + && !toParse.getDerivedFrom().equals("tosca.policies.Root")) { + jsonSchema = this.getParent(toParse.getDerivedFrom()); + } + //For each component property, check if its a complex properties (a component) or not. In that case, + //launch the analyse of the property. + for (Entry<String, ToscaElementProperty> property : toParse.getProperties().entrySet()) { + if (getToscaElement((String) property.getValue().getItems().get("type")) != null) { + jsonSchema.add(property.getValue().getName(), + this.getJsonSchemaOfToscaElement((String) property.getValue().getItems().get("type"))); + } + else { + jsonSchema.add(property.getValue().getName(), this.complexParse(property.getValue())); + } + } + return jsonSchema; + } + + /** + * If a component has a parent, it is deploy in the same way. + * + * @param nameComponent name component + * @return a json object + */ + public JsonObject getParent(String nameComponent) { + return deploy(nameComponent); + } + + /** + * to be done. + * + * @param toscaElementProperty property + * @return a json object + */ + @SuppressWarnings("unchecked") + public JsonObject complexParse(ToscaElementProperty toscaElementProperty) { + JsonObject propertiesInJson = new JsonObject(); + JsonTemplate currentPropertyJsonTemplate; + String typeProperty = (String) toscaElementProperty.getItems().get("type"); + if (typeProperty.toLowerCase().equals("list") || typeProperty.toLowerCase().equals("map")) { + currentPropertyJsonTemplate = templates.get("object"); + } + else { + String propertyType = (String) toscaElementProperty.getItems().get("type"); + currentPropertyJsonTemplate = templates.get(propertyType.toLowerCase()); + } + //Each "special" field is analysed, and has a specific treatment + for (String propertyField : toscaElementProperty.getItems().keySet()) { + switch (propertyField) { + case "type": + if (currentPropertyJsonTemplate.hasFields(propertyField)) { + String fieldtype = (String) toscaElementProperty.getItems().get(propertyField); + switch (fieldtype.toLowerCase()) { + case "list": + propertiesInJson.addProperty("type", "array"); + break; + case "map": + propertiesInJson.addProperty("type", "object"); + break; + case "scalar-unit.time": + case "scalar-unit.frequency": + case "scalar-unit.size": + propertiesInJson.addProperty("type", "string"); + break; + case "timestamp": + propertiesInJson.addProperty("type", "string"); + propertiesInJson.addProperty("format", "date-time"); + break; + case "float": + propertiesInJson.addProperty("type", "number"); + break; + case "range": + propertiesInJson.addProperty("type", "integer"); + if (!checkConstraintPresence(toscaElementProperty, "greater_than") + && currentPropertyJsonTemplate.hasFields("exclusiveMinimum")) { + propertiesInJson.addProperty("exclusiveMinimum", false); + } + if (!checkConstraintPresence(toscaElementProperty, "less_than") + && currentPropertyJsonTemplate.hasFields("exclusiveMaximum")) { + propertiesInJson.addProperty("exclusiveMaximum", false); + } + break; + default: + propertiesInJson.addProperty("type", currentPropertyJsonTemplate.getName()); + break; + } + } + break; + case "metadata": + if (metadataParser != null) { + metadataParser.processAllMetadataElement(toscaElementProperty, serviceModel).entrySet() + .forEach((jsonEntry) -> { + propertiesInJson.add(jsonEntry.getKey(), + jsonEntry.getValue()); + + }); + } + break; + case "constraints": + toscaElementProperty.addConstraintsAsJson(propertiesInJson, + (ArrayList<Object>) toscaElementProperty.getItems().get("constraints"), + currentPropertyJsonTemplate); + break; + case "entry_schema": + //Here, a way to check if entry is a component (datatype) or a simple string + if (getToscaElement(this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema")) + != null) { + String nameComponent = this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema"); + ToscaConverterToJsonSchema child = new ToscaConverterToJsonSchema(components, templates, + metadataParser, serviceModel); + JsonObject propertiesContainer = new JsonObject(); + + switch ((String) toscaElementProperty.getItems().get("type")) { + case "map": // Get it as an object + JsonObject componentAsProperty = child.getJsonSchemaOfToscaElement(nameComponent); + propertiesContainer.add(nameComponent, componentAsProperty); + if (currentPropertyJsonTemplate.hasFields("properties")) { + propertiesInJson.add("properties", propertiesContainer); + } + break; + default://list : get it as an Array + JsonObject componentAsItem = child.getJsonSchemaOfToscaElement(nameComponent); + if (currentPropertyJsonTemplate.hasFields("properties")) { + propertiesInJson.add("items", componentAsItem); + propertiesInJson.addProperty("format", "tabs-top"); + } + break; + } + + } + // Native cases + else if (toscaElementProperty.getItems().get("type").equals("list")) { + JsonObject itemContainer = new JsonObject(); + String valueInEntrySchema = + this.extractSpecificFieldFromMap(toscaElementProperty, "entry_schema"); + itemContainer.addProperty("type", valueInEntrySchema); + propertiesInJson.add("items", itemContainer); + propertiesInJson.addProperty("format", "tabs-top"); + } + // MAP Case, for now nothing + + break; + default: + //Each classical field : type, description, default.. + if (currentPropertyJsonTemplate.hasFields(propertyField) && !propertyField.equals("required")) { + toscaElementProperty.addFieldToJson(propertiesInJson, propertyField, + toscaElementProperty.getItems().get(propertyField)); + } + break; + } + } + return propertiesInJson; + } + + /** + * Look for a matching Component for the name parameter, in the components list. + * + * @param name the tosca element name to search for + * @return a tosca element + */ + public ToscaElement getToscaElement(String name) { + ToscaElement correspondingToscaElement = null; + if (components == null) { + return null; + } + for (ToscaElement toscaElement : components.values()) { + if (toscaElement.getName().equals(name)) { + correspondingToscaElement = toscaElement; + } + } + return correspondingToscaElement; + } + + /** + * Simple method to extract quickly a type field from particular property item. + * + * @param toscaElementProperty the property + * @param fieldName the fieldname + * @return a string + */ + @SuppressWarnings("unchecked") + public String extractSpecificFieldFromMap(ToscaElementProperty toscaElementProperty, String fieldName) { + LinkedHashMap<String, String> entrySchemaFields = + (LinkedHashMap<String, String>) toscaElementProperty.getItems().get(fieldName); + return entrySchemaFields.get("type"); + } + + /** + * Check if a constraint, for a specific property, is there. + * + * @param toscaElementProperty property + * @param nameConstraint name constraint + * @return a flag boolean + */ + public boolean checkConstraintPresence(ToscaElementProperty toscaElementProperty, String nameConstraint) { + boolean presentConstraint = false; + if (toscaElementProperty.getItems().containsKey("constraints")) { + ArrayList<Object> constraints = (ArrayList) toscaElementProperty.getItems().get("constraints"); + for (Object constraint : constraints) { + if (constraint instanceof LinkedHashMap) { + if (((LinkedHashMap) constraint).containsKey(nameConstraint)) { + presentConstraint = true; + } + } + } + } + return presentConstraint; + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/parser/ToscaElementParser.java b/src/main/java/org/onap/clamp/clds/tosca/update/parser/ToscaElementParser.java new file mode 100644 index 000000000..090fcfcfa --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/parser/ToscaElementParser.java @@ -0,0 +1,103 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.parser; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; +import org.onap.clamp.clds.tosca.update.elements.ToscaElement; +import org.onap.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.yaml.snakeyaml.Yaml; + +public class ToscaElementParser { + /** + * Constructor. + */ + private ToscaElementParser() { + } + + private static LinkedHashMap<String, Object> searchAllDataTypesAndPolicyTypes(String toscaYaml) { + LinkedHashMap<String, LinkedHashMap<String, Object>> file = + (LinkedHashMap<String, LinkedHashMap<String, Object>>) new Yaml().load(toscaYaml); + LinkedHashMap<String, Object> allDataTypesFound = file.get("data_types"); + LinkedHashMap<String, Object> allPolicyTypesFound = file.get("policy_types"); + LinkedHashMap<String, Object> allItemsFound = new LinkedHashMap<>(); + // Put the policies and datatypes in the same collection + allItemsFound = (allDataTypesFound == null) ? (new LinkedHashMap<>()) : allDataTypesFound; + allItemsFound.putAll(allPolicyTypesFound == null ? new LinkedHashMap<>() : allPolicyTypesFound); + return allItemsFound; + } + + private static LinkedHashMap<String, Object> searchAllNativeToscaDataTypes(String toscaNativeYaml) { + return ((LinkedHashMap<String, LinkedHashMap<String, Object>>) new Yaml().load(toscaNativeYaml)) + .get("data_types"); + } + + /** + * Yaml Parse gets raw policies and datatypes, in different sections : necessary to extract + * all entities and put them at the same level. + * + * @param toscaYaml the tosca model content + * @param nativeToscaYaml the tosca native datatype content + * @return a map of Tosca Element containing all tosca elements found (policy types and datatypes) + */ + public static LinkedHashMap<String, ToscaElement> searchAllToscaElements(String toscaYaml, + String nativeToscaYaml) { + LinkedHashMap<String, Object> allItemsFound = searchAllDataTypesAndPolicyTypes(toscaYaml); + allItemsFound.putAll(searchAllNativeToscaDataTypes(nativeToscaYaml)); + return parseAllItemsFound(allItemsFound); + } + + /** + * With all the component, get as Map, Components and Components properties are created. + * + * @param allMaps maps + */ + private static LinkedHashMap<String, ToscaElement> parseAllItemsFound(LinkedHashMap<String, Object> allMaps) { + LinkedHashMap<String, ToscaElement> allItemsFound = new LinkedHashMap<String, ToscaElement>(); + //Component creations, from the file maps + for (Entry<String, Object> itemToParse : allMaps.entrySet()) { + LinkedHashMap<String, Object> componentBody = (LinkedHashMap<String, Object>) itemToParse.getValue(); + ToscaElement toscaElement = + new ToscaElement(itemToParse.getKey(), (String) componentBody.get("derived_from"), + (String) componentBody.get("description")); + //If policy, version and type_version : + if (componentBody.get("type_version") != null) { + toscaElement.setVersion((String) componentBody.get("type_version")); + toscaElement.setTypeVersion((String) componentBody.get("type_version")); + } + //Properties creation, from the map + if (componentBody.get("properties") != null) { + LinkedHashMap<String, Object> properties = + (LinkedHashMap<String, Object>) componentBody.get("properties"); + for (Entry<String, Object> itemToProperty : properties.entrySet()) { + ToscaElementProperty toscaElementProperty = new ToscaElementProperty(itemToProperty.getKey(), + (LinkedHashMap<String, Object>) itemToProperty.getValue()); + toscaElement.addProperties(toscaElementProperty); + } + } + allItemsFound.put(toscaElement.getName(), toscaElement); + } + return allItemsFound; + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java b/src/main/java/org/onap/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java new file mode 100644 index 000000000..f4a48139e --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParser.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.parser.metadata; + +import com.google.gson.JsonObject; +import org.onap.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.onap.clamp.loop.service.Service; + +public interface ToscaMetadataParser { + JsonObject processAllMetadataElement(ToscaElementProperty toscaElementProperty, Service serviceModel); +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java b/src/main/java/org/onap/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java new file mode 100644 index 000000000..33e084279 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/parser/metadata/ToscaMetadataParserWithDictionarySupport.java @@ -0,0 +1,219 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.parser.metadata; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Optional; +import org.onap.clamp.clds.tosca.JsonEditorSchemaConstants; +import org.onap.clamp.clds.tosca.ToscaSchemaConstants; +import org.onap.clamp.clds.tosca.update.elements.ToscaElementProperty; +import org.onap.clamp.clds.tosca.update.execution.ToscaMetadataExecutor; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.tosca.DictionaryElement; +import org.onap.clamp.tosca.DictionaryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class ToscaMetadataParserWithDictionarySupport implements ToscaMetadataParser { + + @Autowired + private ToscaMetadataExecutor toscaMetadataExecutor; + + @Autowired + private DictionaryService dictionaryService; + + /** + * This method is used to start the processing of the metadata field. + * + * @param toscaElementProperty The property metadata as Json Object + * @return The jsonObject structure that must be added to the json schema + */ + public JsonObject processAllMetadataElement(ToscaElementProperty toscaElementProperty, Service serviceModel) { + if (dictionaryService != null) { + return parseMetadataPossibleValues(toscaElementProperty.getItems(), dictionaryService, serviceModel, + toscaMetadataExecutor); + } + else { + return null; + } + } + + private static JsonObject parseMetadataPossibleValues(LinkedHashMap<String, Object> childNodeMap, + DictionaryService dictionaryService, Service serviceModel, + ToscaMetadataExecutor toscaMetadataExecutor) { + JsonObject childObject = new JsonObject(); + if (childNodeMap.containsKey(ToscaSchemaConstants.METADATA) + && childNodeMap.get(ToscaSchemaConstants.METADATA) != null) { + ((LinkedHashMap<String, Object>) childNodeMap.get(ToscaSchemaConstants.METADATA)).forEach((key, + value) -> { + if (key.equalsIgnoreCase(ToscaSchemaConstants.METADATA_CLAMP_POSSIBLE_VALUES)) { + String[] multipleValues = ((String) value).split(","); + for (String multipleValue : multipleValues) { + if (multipleValue.contains(ToscaSchemaConstants.DICTIONARY)) { + processDictionaryElements(multipleValue, childObject, dictionaryService); + } + if (multipleValue.contains("ClampExecution:")) { + executeClampProcess(multipleValue.replaceAll("ClampExecution:", ""), childObject, + serviceModel, toscaMetadataExecutor); + } + } + + } + }); + } + return childObject; + } + + private static void executeClampProcess(String processInfo, JsonObject childObject, Service serviceModel, + ToscaMetadataExecutor toscaMetadataExecutor) { + toscaMetadataExecutor.executeTheProcess(processInfo, childObject, serviceModel); + } + + /** + * For dictionary with multiple levels (defined by #). + * + * @param dictionaryKeyArray the array containing the different elements + * @param childObject the structure getting the new entries + * @param dictionaryService the dictionary service bean + */ + private static void processComplexDictionaryElements(String[] dictionaryKeyArray, JsonObject childObject, + DictionaryService dictionaryService) { + // We support only one # as of now. + List<DictionaryElement> dictionaryElements = null; + if (dictionaryKeyArray.length == 2) { + dictionaryElements = new ArrayList<>(dictionaryService.getDictionary(dictionaryKeyArray[0]) + .getDictionaryElements()); + JsonArray subDictionaryNames = new JsonArray(); + new ArrayList<DictionaryElement>(dictionaryService.getDictionary(dictionaryKeyArray[1]) + .getDictionaryElements()).forEach(elem -> subDictionaryNames.add(elem.getShortName())); + + JsonArray jsonArray = new JsonArray(); + + Optional.of(dictionaryElements).get().forEach(c -> { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty(JsonEditorSchemaConstants.TYPE, getJsonType(c.getType())); + if (c.getType() != null + && c.getType().equalsIgnoreCase(ToscaSchemaConstants.TYPE_STRING)) { + jsonObject.addProperty(JsonEditorSchemaConstants.MIN_LENGTH, 1); + + } + jsonObject.addProperty(JsonEditorSchemaConstants.ID, c.getName()); + jsonObject.addProperty(JsonEditorSchemaConstants.LABEL, c.getShortName()); + jsonObject.add(JsonEditorSchemaConstants.OPERATORS, subDictionaryNames); + jsonArray.add(jsonObject); + }); + + JsonObject filterObject = new JsonObject(); + filterObject.add(JsonEditorSchemaConstants.FILTERS, jsonArray); + + childObject.addProperty(JsonEditorSchemaConstants.TYPE, + JsonEditorSchemaConstants.TYPE_QBLDR); + // TO invoke validation on such parameters + childObject.addProperty(JsonEditorSchemaConstants.MIN_LENGTH, 1); + childObject.add(JsonEditorSchemaConstants.QSSCHEMA, filterObject); + + } + } + + /** + * For dictionary with single entry. + * + * @param dictionaryKeyArray the array containing the different elements + * @param childObject the structure getting the new entries + * @param dictionaryService the dictionary service bean + */ + private static void processSimpleDictionaryElements(String[] dictionaryKeyArray, JsonObject childObject, + DictionaryService dictionaryService) { + JsonArray dictionaryNames = new JsonArray(); + JsonArray dictionaryFullNames = new JsonArray(); + dictionaryService.getDictionary(dictionaryKeyArray[0]).getDictionaryElements().forEach(c -> { + // Json type will be translated before Policy creation + if (c.getType() != null && !c.getType().equalsIgnoreCase("json")) { + dictionaryFullNames.add(c.getName()); + } + dictionaryNames.add(c.getShortName()); + }); + + if (dictionaryFullNames.size() > 0) { + if (childObject.get(JsonEditorSchemaConstants.ENUM) != null) { + childObject.get(JsonEditorSchemaConstants.ENUM).getAsJsonArray().add(dictionaryFullNames); + } + else { + childObject.add(JsonEditorSchemaConstants.ENUM, dictionaryFullNames); + } + // Add Enum titles for generated translated values during JSON instance + // generation + JsonObject enumTitles = new JsonObject(); + enumTitles.add(JsonEditorSchemaConstants.ENUM_TITLES, dictionaryNames); + if (childObject.get(JsonEditorSchemaConstants.OPTIONS) != null) { + childObject.get(JsonEditorSchemaConstants.OPTIONS).getAsJsonArray().add(enumTitles); + } + else { + childObject.add(JsonEditorSchemaConstants.OPTIONS, enumTitles); + } + + } + else { + if (childObject.get(JsonEditorSchemaConstants.ENUM) != null) { + childObject.get(JsonEditorSchemaConstants.ENUM).getAsJsonArray().add(dictionaryNames); + } + else { + childObject.add(JsonEditorSchemaConstants.ENUM, dictionaryNames); + } + } + } + + private static void processDictionaryElements(String dictionaryReference, JsonObject childObject, + DictionaryService dictionaryService) { + String[] dictionaryKeyArray = + dictionaryReference.substring(dictionaryReference.indexOf(ToscaSchemaConstants.DICTIONARY) + 11, + dictionaryReference.length()).split("#"); + if (dictionaryKeyArray.length > 1) { + processComplexDictionaryElements(dictionaryKeyArray, childObject, dictionaryService); + } + else { + processSimpleDictionaryElements(dictionaryKeyArray, childObject, dictionaryService); + } + } + + private static String getJsonType(String toscaType) { + String jsonType = null; + if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_INTEGER)) { + jsonType = JsonEditorSchemaConstants.TYPE_INTEGER; + } + else if (toscaType.equalsIgnoreCase(ToscaSchemaConstants.TYPE_LIST)) { + jsonType = JsonEditorSchemaConstants.TYPE_ARRAY; + } + else { + jsonType = JsonEditorSchemaConstants.TYPE_STRING; + } + return jsonType; + } + +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplate.java b/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplate.java new file mode 100644 index 000000000..f64ba68cf --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplate.java @@ -0,0 +1,224 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.templates; + +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.List; + +public class JsonTemplate { + + /** + * name parameter is used as "key", in the LinkedHashMap of Templates. + */ + private String name; + private List<JsonTemplateField> jsonTemplateFields; + + public JsonTemplate(String name) { + this.name = name; + this.jsonTemplateFields = new ArrayList<>(); + } + + public JsonTemplate(String name, List<JsonTemplateField> jsonTemplateFields) { + this.name = name; + this.jsonTemplateFields = jsonTemplateFields; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List<JsonTemplateField> getJsonTemplateFields() { + return jsonTemplateFields; + } + + public void setJsonTemplateFields(List<JsonTemplateField> jsonTemplateFields) { + this.jsonTemplateFields = jsonTemplateFields; + } + + /** + * Search in fields if fieldName exists. + * + * @param fieldName The field name + * @return Ture if it exists, false otherwise + */ + public boolean hasFields(String fieldName) { + for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) { + if (jsonTemplateField.getTitle().equals(fieldName)) { + return true; + } + } + return false; + } + + /** + * Get a specific Field. + * + * @param fieldName The field name + * @return THe Field found + */ + public JsonTemplateField getSpecificField(String fieldName) { + for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) { + if (jsonTemplateField.getTitle().equals(fieldName)) { + return jsonTemplateField; + } + } + return null; + } + + public void addField(JsonTemplateField jsonTemplateField) { + jsonTemplateFields.add(jsonTemplateField); + } + + public void removeField(JsonTemplateField jsonTemplateField) { + jsonTemplateFields.remove(jsonTemplateField); + } + + /** + * Enable or disable the visibility. + * + * @param nameField THe field name + * @param state True or false + */ + public void setVisibility(String nameField, boolean state) { + for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) { + if (jsonTemplateField.getTitle().equals(nameField)) { + jsonTemplateField.setVisible(state); + } + } + } + + /** + * This method defines if a field is static or not. + * + * @param nameField The name of the field + * @param state true or false + */ + public void setStatic(String nameField, boolean state) { + for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) { + if (jsonTemplateField.getTitle().equals(nameField)) { + jsonTemplateField.setStaticValue(state); + } + } + } + + /** + * This method updates the value of a specfic field. + * + * @param nameField The name of the field + * @param newValue The new value as Object + */ + public void updateValueField(String nameField, Object newValue) { + for (JsonTemplateField jsonTemplateField : this.jsonTemplateFields) { + if (jsonTemplateField.getTitle().equals(nameField)) { + jsonTemplateField.setValue(newValue); + } + } + } + + /** + * Compare two templates : size and their contents. + * + * @param jsonTemplate the template + * @return a boolean + */ + public boolean checkFields(JsonTemplate jsonTemplate) { + boolean duplicateFields = false; + if (jsonTemplate.getJsonTemplateFields().size() == this.getJsonTemplateFields().size()) { + int countMatchingFields = 0; + //loop each component of first + for (JsonTemplateField jsonTemplateFieldToCheck : jsonTemplate.getJsonTemplateFields()) { + for (JsonTemplateField jsonTemplateField : this.getJsonTemplateFields()) { + if (jsonTemplateFieldToCheck.compareWithField(jsonTemplateField)) { + countMatchingFields++; + } + } + } + + if (jsonTemplate.getJsonTemplateFields().size() == countMatchingFields) { + duplicateFields = true; + } + } + return duplicateFields; + } + + /** + * This method gets the specific field status. + * + * @param field The field name + * @return true or false + */ + public boolean fieldStaticStatus(String field) { + if (this.hasFields(field) && this.getSpecificField(field).getStaticValue().equals(true) + && this.getSpecificField(field).getValue() != null) { + return true; + } + return false; + } + + public boolean isVisible(String field) { + return this.getSpecificField(field).getVisible(); + } + + /** + * Set the value of a property of the Field in the json. + * + * @param jsonSchema The Json schema + * @param fieldName The Field name + * @param value The value + */ + public void setValue(JsonObject jsonSchema, String fieldName, String value) { + if (isVisible(fieldName)) { + if (fieldStaticStatus(fieldName)) { + String defaultValue = (String) this.getSpecificField(fieldName).getValue(); + jsonSchema.addProperty(fieldName, defaultValue); + } + else { + jsonSchema.addProperty(fieldName, value); + } + } + } + + /** + * Inject a static value in the json. + * + * @param jsonSchema The json schema object + * @param fieldName The field name + */ + public void injectStaticValue(JsonObject jsonSchema, String fieldName) { + if (isVisible(fieldName)) { + JsonTemplateField toInject = this.getSpecificField(fieldName); + jsonSchema.addProperty(fieldName, (String) toInject.getValue()); + } + } + + @Override + public String toString() { + return " templateFields : " + jsonTemplateFields; + } +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplateField.java b/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplateField.java new file mode 100644 index 000000000..a1e15307c --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplateField.java @@ -0,0 +1,149 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.templates; + +public class JsonTemplateField { + private String title; + private Object value; + private Boolean visible; + private Boolean staticValue; + + public JsonTemplateField(String title) { + this.title = title; + } + + /** + * Constructor. + * + * @param title The title + * @param value The value + * @param visible visible or not + * @param staticValue The static value + */ + public JsonTemplateField(String title, Object value, Boolean visible, Boolean staticValue) { + this.title = title; + this.value = value; + this.visible = visible; + this.staticValue = staticValue; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public Boolean getVisible() { + return visible; + } + + public void setVisible(Boolean visible) { + this.visible = visible; + } + + public Boolean getStaticValue() { + return staticValue; + } + + public void setStaticValue(Boolean staticValue) { + this.staticValue = staticValue; + } + + public String toString() { + return title + " " + value + " " + visible + " " + staticValue; + } + + /** + * This method compares two fields. + * + * @param otherField Compare the current object with the one specified + * @return true if they are totally equals, false otherwise + */ + public boolean compareWithField(Object otherField) { + if (this == otherField) { + return true; + } + if (otherField == null || getClass() != otherField.getClass()) { + return false; + } + + JsonTemplateField jsonTemplateField = (JsonTemplateField) otherField; + + if (title != null ? !title.equals(jsonTemplateField.title) : jsonTemplateField.title != null) { + return false; + } + if (value != null ? !value.equals(jsonTemplateField.value) : jsonTemplateField.value != null) { + return false; + } + if (visible != null ? !visible.equals(jsonTemplateField.visible) : jsonTemplateField.visible != null) { + return false; + } + return staticValue != null ? staticValue.equals(jsonTemplateField.staticValue) : + jsonTemplateField.staticValue == null; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + + JsonTemplateField jsonTemplateField = (JsonTemplateField) object; + + return title != null ? title.equals(jsonTemplateField.title) : jsonTemplateField.title == null; + } + + @Override + public int hashCode() { + return title != null ? title.hashCode() : 0; + } + + /** + * This method test the entire equality. + * + * @param jsonTemplateField1 object one + * @param jsonTemplateField2 object two + * @return true if they are totally equals (all attributes, false otherwise + */ + public static boolean fieldsEquals(JsonTemplateField jsonTemplateField1, JsonTemplateField jsonTemplateField2) { + return (jsonTemplateField2.getTitle().equals(jsonTemplateField1.getTitle()) + && jsonTemplateField2.getValue().equals(jsonTemplateField1.getValue()) + && jsonTemplateField2.getVisible().equals(jsonTemplateField1.getVisible()) + && jsonTemplateField2.getStaticValue().equals(jsonTemplateField1.getStaticValue())); + } + +} diff --git a/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplateManager.java b/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplateManager.java new file mode 100644 index 000000000..0b399ba0b --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/tosca/update/templates/JsonTemplateManager.java @@ -0,0 +1,187 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.clds.tosca.update.templates; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.onap.clamp.clds.tosca.update.UnknownComponentException; +import org.onap.clamp.clds.tosca.update.elements.ToscaElement; +import org.onap.clamp.clds.tosca.update.parser.ToscaConverterToJsonSchema; +import org.onap.clamp.clds.tosca.update.parser.ToscaElementParser; +import org.onap.clamp.clds.tosca.update.parser.metadata.ToscaMetadataParser; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.loop.service.Service; + +public class JsonTemplateManager { + private LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates; + private LinkedHashMap<String, ToscaElement> toscaElements; + + /** + * Constructor. + * + * @param toscaYamlContent Policy Tosca Yaml content as string + * @param nativeToscaDatatypes The tosca yaml with tosca native datatypes + * @param jsonSchemaTemplates template properties as string + */ + public JsonTemplateManager(String toscaYamlContent, String nativeToscaDatatypes, String jsonSchemaTemplates) { + if (toscaYamlContent != null && !toscaYamlContent.isEmpty()) { + this.toscaElements = ToscaElementParser.searchAllToscaElements(toscaYamlContent, nativeToscaDatatypes); + this.jsonSchemaTemplates = initializeTemplates(jsonSchemaTemplates); + } + else { + toscaElements = null; + } + } + + //GETTERS & SETTERS + public LinkedHashMap<String, ToscaElement> getToscaElements() { + return toscaElements; + } + + public void setToscaElements(LinkedHashMap<String, ToscaElement> toscaElements) { + this.toscaElements = toscaElements; + } + + public LinkedHashMap<String, JsonTemplate> getJsonSchemaTemplates() { + return jsonSchemaTemplates; + } + + public void setJsonSchemaTemplates(LinkedHashMap<String, JsonTemplate> jsonSchemaTemplates) { + this.jsonSchemaTemplates = jsonSchemaTemplates; + } + + /** + * Add a template. + * + * @param name name + * @param jsonTemplateFields fields + */ + public void addTemplate(String name, List<JsonTemplateField> jsonTemplateFields) { + JsonTemplate jsonTemplate = new JsonTemplate(name, jsonTemplateFields); + //If it is true, the operation does not have any interest : + // replace OR put two different object with the same body + if (!jsonSchemaTemplates.containsKey(jsonTemplate.getName()) || !this.hasTemplate(jsonTemplate)) { + this.jsonSchemaTemplates.put(jsonTemplate.getName(), jsonTemplate); + } + } + + /** + * By name, find and remove a given template. + * + * @param nameTemplate name template + */ + public void removeTemplate(String nameTemplate) { + this.jsonSchemaTemplates.remove(nameTemplate); + } + + /** + * Update Template : adding with true flag, removing with false. + * + * @param nameTemplate name template + * @param jsonTemplateField field name + * @param operation operation + */ + public void updateTemplate(String nameTemplate, JsonTemplateField jsonTemplateField, Boolean operation) { + // Operation = true && field is not present => add Field + if (operation + && !this.jsonSchemaTemplates.get(nameTemplate).getJsonTemplateFields().contains(jsonTemplateField)) { + this.jsonSchemaTemplates.get(nameTemplate).addField(jsonTemplateField); + } + // Operation = false && field is present => remove Field + else if (!operation + && this.jsonSchemaTemplates.get(nameTemplate).getJsonTemplateFields().contains(jsonTemplateField)) { + this.jsonSchemaTemplates.get(nameTemplate).removeField(jsonTemplateField); + } + } + + /** + * Check if the JSONTemplates have the same bodies. + * + * @param jsonTemplate template + * @return a boolean + */ + public boolean hasTemplate(JsonTemplate jsonTemplate) { + boolean duplicateTemplate = false; + Collection<String> templatesName = jsonSchemaTemplates.keySet(); + if (templatesName.contains(jsonTemplate.getName())) { + JsonTemplate existingJsonTemplate = jsonSchemaTemplates.get(jsonTemplate.getName()); + duplicateTemplate = existingJsonTemplate.checkFields(jsonTemplate); + } + return duplicateTemplate; + } + + /** + * For a given policy type, get a corresponding JsonObject from the tosca model. + * + * @param policyType The policy type in the tosca + * @param toscaMetadataParser The MetadataParser class that must be used if metadata section are encountered, if null + * they will be skipped + * @return an json object defining the equivalent json schema from the tosca for a given policy type + */ + public JsonObject getJsonSchemaForPolicyType(String policyType, ToscaMetadataParser toscaMetadataParser, + Service serviceModel) + throws UnknownComponentException { + ToscaConverterToJsonSchema + toscaConverterToJsonSchema = new ToscaConverterToJsonSchema(toscaElements, jsonSchemaTemplates, + toscaMetadataParser, serviceModel); + if (toscaConverterToJsonSchema.getToscaElement(policyType) == null) { + throw new UnknownComponentException(policyType); + } + return toscaConverterToJsonSchema.getJsonSchemaOfToscaElement(policyType); + } + + /** + * Create and complete several Templates from file.properties. + * + * @param jsonTemplates The template properties as String + * @return a map + */ + @SuppressWarnings("unused") + private LinkedHashMap<String, JsonTemplate> initializeTemplates(String jsonTemplates) { + + LinkedHashMap<String, JsonTemplate> generatedTemplates = new LinkedHashMap<>(); + JsonObject templates = JsonUtils.GSON.fromJson(jsonTemplates, JsonObject.class); + + for (Map.Entry<String, JsonElement> templateAsJson : templates.entrySet()) { + JsonTemplate jsonTemplate = new JsonTemplate(templateAsJson.getKey()); + JsonObject templateBody = (JsonObject) templateAsJson.getValue(); + for (Map.Entry<String, JsonElement> field : templateBody.entrySet()) { + String fieldName = field.getKey(); + JsonObject bodyFieldAsJson = (JsonObject) field.getValue(); + Object fieldValue = bodyFieldAsJson.get("defaultValue").getAsString(); + Boolean fieldVisible = bodyFieldAsJson.get("visible").getAsBoolean(); + Boolean fieldStatic = bodyFieldAsJson.get("static").getAsBoolean(); + JsonTemplateField + bodyJsonTemplateField = new JsonTemplateField(fieldName, fieldValue, fieldVisible, fieldStatic); + jsonTemplate.getJsonTemplateFields().add(bodyJsonTemplateField); + } + generatedTemplates.put(jsonTemplate.getName(), jsonTemplate); + } + return generatedTemplates; + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/clds/util/ClampVersioning.java b/src/main/java/org/onap/clamp/clds/util/ClampVersioning.java new file mode 100644 index 000000000..ec0162cb1 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/util/ClampVersioning.java @@ -0,0 +1,62 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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============================================ + * Modifications copyright (c) 2018 Nokia + * =================================================================== + * + */ + +package org.onap.clamp.clds.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import java.io.InputStream; +import java.util.Properties; + +/** + * This class give a way to know the Clamp version easily, the version in that + * file is set by maven at build time. + * + */ +public class ClampVersioning { + private static final String RESOURCE_NAME = "clds-version.properties"; + private static final String CLDS_VERSION_PROPERTY = "clds.version"; + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ClampVersioning.class); + + private ClampVersioning() { + } + + /** + * Returns Clds version from properties. + * + * @return Clds version from properties + */ + public static String getCldsVersionFromProps() { + String cldsVersion = ""; + Properties props = new Properties(); + try (InputStream resourceStream = ResourceFileUtils.getResourceAsStream(RESOURCE_NAME)) { + props.load(resourceStream); + cldsVersion = props.getProperty(CLDS_VERSION_PROPERTY); + } catch (Exception ex) { + LOGGER.error("Exception caught during the " + CLDS_VERSION_PROPERTY + " property reading", ex); + } + return cldsVersion; + } +} diff --git a/src/main/java/org/onap/clamp/clds/util/CryptoUtils.java b/src/main/java/org/onap/clamp/clds/util/CryptoUtils.java new file mode 100644 index 000000000..1ddf3a90a --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/util/CryptoUtils.java @@ -0,0 +1,168 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.common.base.Charsets; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Properties; +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.lang3.ArrayUtils; + +/** + * CryptoUtils for encrypting/decrypting string based on a Key defined in + * application.properties (Spring config file). + */ +public final class CryptoUtils { + + /** + * Used to log CryptoUtils class. + */ + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CryptoUtils.class); + // Openssl commands: + // Encrypt: echo -n "123456" | openssl aes-128-cbc -e -K <Private Hex key> + // -iv <16 Bytes iv (HEX), be careful it's 32 Hex Chars> | xxd -u -g100 + // Final result is to put in properties file is: IV + Outcome of openssl + // command + // ************************************************************ + // Decrypt: echo -n 'Encrypted string' | xxd -r -ps | openssl aes-128-cbc -d + // -K + // <Private Hex Key> -iv <16 Bytes IV extracted from Encrypted String, be + // careful it's 32 Hex Chars> + /** + * Definition of encryption algorithm. + */ + private static final String ALGORITHM = "AES"; + + /** + * AES Encryption Key environment variable for external configuration. + */ + private static final String AES_ENCRYPTION_KEY = "AES_ENCRYPTION_KEY"; + + /** + * Detailed definition of encryption algorithm. + */ + private static final String ALGORITHM_DETAILS = ALGORITHM + "/CBC/PKCS5PADDING"; + private static final int IV_BLOCK_SIZE_IN_BITS = 128; + /** + * An Initial Vector of 16 Bytes, so 32 Hexadecimal Chars. + */ + private static final int IV_BLOCK_SIZE_IN_BYTES = IV_BLOCK_SIZE_IN_BITS / 8; + /** + * Key to read in the key.properties file. + */ + private static final String KEY_PARAM = "org.onap.clamp.encryption.aes.key"; + private static final String PROPERTIES_FILE_NAME = "clds/key.properties"; + /** + * The SecretKeySpec created from the Base 64 String key. + */ + private static final SecretKeySpec SECRET_KEY_SPEC = readSecretKeySpec(PROPERTIES_FILE_NAME); + + /** + * Private constructor to avoid creating instances of util class. + */ + private CryptoUtils() { + } + + /** + * Encrypt a value based on the Clamp Encryption Key. + * + * @param value The value to encrypt + * @return The encrypted string + * @throws GeneralSecurityException In case of issue with the encryption + * @throws UnsupportedEncodingException In case of issue with the charset + * conversion + */ + public static String encrypt(String value) throws GeneralSecurityException { + Cipher cipher = Cipher.getInstance(ALGORITHM_DETAILS, "SunJCE"); + byte[] iv = new byte[IV_BLOCK_SIZE_IN_BYTES]; + SecureRandom.getInstance("SHA1PRNG").nextBytes(iv); + IvParameterSpec ivspec = new IvParameterSpec(iv); + cipher.init(Cipher.ENCRYPT_MODE, SECRET_KEY_SPEC, ivspec); + return Hex.encodeHexString(ArrayUtils.addAll(iv, cipher.doFinal(value.getBytes(Charsets.UTF_8)))); + } + + /** + * Decrypt a value based on the Clamp Encryption Key. + * + * @param message The encrypted string that must be decrypted using the Clamp + * Encryption Key + * @return The String decrypted + * @throws GeneralSecurityException In case of issue with the encryption + * @throws DecoderException In case of issue to decode the HexString + */ + public static String decrypt(String message) throws GeneralSecurityException, DecoderException { + byte[] encryptedMessage = Hex.decodeHex(message.toCharArray()); + Cipher cipher = Cipher.getInstance(ALGORITHM_DETAILS, "SunJCE"); + IvParameterSpec ivspec = new IvParameterSpec(ArrayUtils.subarray(encryptedMessage, 0, IV_BLOCK_SIZE_IN_BYTES)); + byte[] realData = ArrayUtils.subarray(encryptedMessage, IV_BLOCK_SIZE_IN_BYTES, encryptedMessage.length); + cipher.init(Cipher.DECRYPT_MODE, SECRET_KEY_SPEC, ivspec); + byte[] decrypted = cipher.doFinal(realData); + return new String(decrypted); + } + + /** + * Method used to generate the SecretKeySpec from a Base64 String. + * + * @param keyString The key as a string in Base 64 + * @return The SecretKeySpec created + * @throws DecoderException In case of issues with the decoding of Base64 + */ + private static SecretKeySpec getSecretKeySpec(String keyString) throws DecoderException { + byte[] key = Hex.decodeHex(keyString.toCharArray()); + return new SecretKeySpec(key, ALGORITHM); + } + + /** + * Reads SecretKeySpec from file specified by propertiesFileName. + * + * @param propertiesFileName File name with properties + * @return SecretKeySpec secret key spec read from propertiesFileName + */ + private static SecretKeySpec readSecretKeySpec(String propertiesFileName) { + Properties props = new Properties(); + try { + // Workaround fix to make encryption key configurable + // System environment variable takes precedence for over clds/key.properties + String encryptionKey = System.getenv(AES_ENCRYPTION_KEY); + if (encryptionKey != null && encryptionKey.trim().length() > 0) { + return getSecretKeySpec(encryptionKey); + } else { + props.load(ResourceFileUtils.getResourceAsStream(propertiesFileName)); + return getSecretKeySpec(props.getProperty(KEY_PARAM)); + } + } catch (IOException | DecoderException e) { + logger.error("Exception occurred during the key reading", e); + return null; + } + } +} diff --git a/src/main/java/org/onap/clamp/clds/util/JsonUtils.java b/src/main/java/org/onap/clamp/clds/util/JsonUtils.java new file mode 100644 index 000000000..8024331f2 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/util/JsonUtils.java @@ -0,0 +1,55 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018-2019 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.onap.clamp.clds.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.time.Instant; + +import org.onap.clamp.authorization.SecureServicePermission; +import org.onap.clamp.authorization.SecureServicePermissionDeserializer; +import org.onap.clamp.dao.model.gson.converter.InstantDeserializer; +import org.onap.clamp.dao.model.gson.converter.InstantSerializer; + +/** + * This class is used to access the GSON with restricted type access. + */ +public class JsonUtils { + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(JsonUtils.class); + + public static final Gson GSON = new GsonBuilder() + .registerTypeAdapter(SecureServicePermission.class, new SecureServicePermissionDeserializer()).create(); + + public static final Gson GSON_JPA_MODEL = new GsonBuilder() + .registerTypeAdapter(Instant.class, new InstantSerializer()) + .registerTypeAdapter(Instant.class, new InstantDeserializer()).setPrettyPrinting() + .excludeFieldsWithoutExposeAnnotation().create(); + + private JsonUtils() { + } +} diff --git a/src/main/java/org/onap/clamp/clds/util/LogMessages.java b/src/main/java/org/onap/clamp/clds/util/LogMessages.java new file mode 100644 index 000000000..7f4c8781f --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/util/LogMessages.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.util; + +import com.att.eelf.i18n.EELFResolvableErrorEnum; +import com.att.eelf.i18n.EELFResourceManager; + +public enum LogMessages implements EELFResolvableErrorEnum { + LOGSERVICE_HELLO_MESSAGE, LOGSERVICE_EMAIL_ERROR, LOGSERVICE_EMAIL_CLASS, LOGSERVICE_EMAIL_CLASS_NULL, + PROCESS_INSTANCE_ID; + + static { + EELFResourceManager.loadMessageBundle("logmessages"); + } +} diff --git a/src/main/java/org/onap/clamp/clds/util/LoggingUtils.java b/src/main/java/org/onap/clamp/clds/util/LoggingUtils.java new file mode 100644 index 000000000..0ac1a14fc --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/util/LoggingUtils.java @@ -0,0 +1,414 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2017-2018 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.onap.clamp.clds.util; + +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.TimeZone; +import java.util.UUID; +import javax.net.ssl.HttpsURLConnection; +import javax.servlet.http.HttpServletRequest; +import javax.validation.constraints.NotNull; +import org.onap.clamp.authorization.AuthorizationController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.event.Level; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * This class handles the special info that appear in the log, like RequestID, + * time context, ... + */ +public class LoggingUtils { + + protected static final Logger logger = LoggerFactory.getLogger(LoggingUtils.class); + + private static final DateFormat DATE_FORMAT = createDateFormat(); + + private static final String DATE_FORMATTER_ISO = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + + /** String constant for messages <tt>ENTERING</tt>, <tt>EXITING</tt>, etc. */ + private static final String EMPTY_MESSAGE = ""; + + /** Logger delegate. */ + private Logger mlogger; + + /** Automatic UUID, overrideable per adapter or per invocation. */ + private static UUID sInstanceUUID = UUID.randomUUID(); + + /** + * Constructor. + */ + public LoggingUtils(final Logger loggerP) { + this.mlogger = checkNotNull(loggerP); + } + + /** + * Set request related logging variables in thread local data via MDC. + * + * @param service Service Name of API (ex. "PUT template") + * @param partner Partner name (client or user invoking API) + */ + public static void setRequestContext(String service, String partner) { + MDC.put("RequestId", UUID.randomUUID().toString()); + MDC.put("ServiceName", service); + MDC.put("PartnerName", partner); + // Defaulting to HTTP/1.1 protocol + MDC.put("Protocol", "HTTP/1.1"); + try { + MDC.put("ServerFQDN", InetAddress.getLocalHost().getCanonicalHostName()); + MDC.put("ServerIPAddress", InetAddress.getLocalHost().getHostAddress()); + } catch (UnknownHostException e) { + logger.error("Failed to initiate setRequestContext", e); + } + } + + /** + * Set time related logging variables in thread local data via MDC. + * + * @param beginTimeStamp Start time + * @param endTimeStamp End time + */ + public static void setTimeContext(@NotNull Date beginTimeStamp, @NotNull Date endTimeStamp) { + MDC.put("EntryTimestamp", generateTimestampStr(beginTimeStamp)); + MDC.put("EndTimestamp", generateTimestampStr(endTimeStamp)); + MDC.put("ElapsedTime", String.valueOf(endTimeStamp.getTime() - beginTimeStamp.getTime())); + } + + /** + * Set response related logging variables in thread local data via MDC. + * + * @param code Response code ("0" indicates success) + * @param description Response description + * @param className class name of invoking class + */ + public static void setResponseContext(String code, String description, String className) { + MDC.put("ResponseCode", code); + MDC.put("StatusCode", "0".equals(code) ? "COMPLETE" : "ERROR"); + MDC.put("ResponseDescription", description != null ? description : ""); + MDC.put("ClassName", className != null ? className : ""); + } + + /** + * Set target related logging variables in thread local data via MDC. + * + * @param targetEntity Target entity (an external/sub component, for ex. "sdc") + * @param targetServiceName Target service name (name of API invoked on target) + */ + public static void setTargetContext(String targetEntity, String targetServiceName) { + MDC.put("TargetEntity", targetEntity != null ? targetEntity : ""); + MDC.put("TargetServiceName", targetServiceName != null ? targetServiceName : ""); + } + + /** + * Set error related logging variables in thread local data via MDC. + * + * @param code Error code + * @param description Error description + */ + public static void setErrorContext(String code, String description) { + MDC.put("ErrorCode", code); + MDC.put("ErrorDescription", description != null ? description : ""); + } + + private static String generateTimestampStr(Date timeStamp) { + return DATE_FORMAT.format(timeStamp); + } + + /** + * Get a previously stored RequestID for the thread local data via MDC. If + * one was not previously stored, generate one, store it, and return that + * one. + * + * @return A string with the request ID + */ + public static String getRequestId() { + String requestId = MDC.get(OnapLogConstants.Mdcs.REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = UUID.randomUUID().toString(); + MDC.put(OnapLogConstants.Mdcs.REQUEST_ID, requestId); + } + return requestId; + } + + private static DateFormat createDateFormat() { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat; + } + + /********************************************************************************************* + * Method for ONAP Application Logging Specification v1.2 + ********************************************************************************************/ + + /** + * Report <tt>ENTERING</tt> marker. + * + * @param request non-null incoming request (wrapper) + * @param serviceName service name + */ + public void entering(HttpServletRequest request, String serviceName) { + // MDC.clear(); + checkNotNull(request); + // Extract MDC values from standard HTTP headers. + final String requestId = + defaultToUuid(request.getHeader(OnapLogConstants.Headers.REQUEST_ID)); + final String invocationId = + defaultToUuid(request.getHeader(OnapLogConstants.Headers.INVOCATION_ID)); + final String partnerName = + defaultToEmpty(request.getHeader(OnapLogConstants.Headers.PARTNER_NAME)); + + // Default the partner name to the user name used to login to clamp + if (partnerName.equalsIgnoreCase(EMPTY_MESSAGE)) { + MDC.put(OnapLogConstants.Mdcs.PARTNER_NAME, + AuthorizationController.getPrincipalName(SecurityContextHolder.getContext())); + } + + // Set standard MDCs. Override this entire method if you want to set + // others, OR set them BEFORE or AFTER the invocation of #entering, + // depending on where you need them to appear, OR extend the + // ServiceDescriptor to add them. + MDC.put(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP, ZonedDateTime.now(ZoneOffset.UTC) + .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO))); + MDC.put(OnapLogConstants.Mdcs.REQUEST_ID, requestId); + MDC.put(OnapLogConstants.Mdcs.INVOCATION_ID, invocationId); + MDC.put(OnapLogConstants.Mdcs.CLIENT_IP_ADDRESS, defaultToEmpty(request.getRemoteAddr())); + MDC.put(OnapLogConstants.Mdcs.SERVER_FQDN, defaultToEmpty(request.getServerName())); + MDC.put(OnapLogConstants.Mdcs.INSTANCE_UUID, defaultToEmpty(sInstanceUUID)); + + // Default the service name to the requestURI, in the event that + // no value has been provided. + if (serviceName == null || serviceName.equalsIgnoreCase(EMPTY_MESSAGE)) { + MDC.put(OnapLogConstants.Mdcs.SERVICE_NAME, request.getRequestURI()); + } else { + MDC.put(OnapLogConstants.Mdcs.SERVICE_NAME, serviceName); + } + + // Set the Response Status code to in progress + MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE, + OnapLogConstants.ResponseStatus.INPROGRESS.toString()); + setElapsedTime(); + + this.mlogger.info(OnapLogConstants.Markers.ENTRY, "Entering"); + } + + /** + * Report <tt>EXITING</tt> marker. + * + * + * @param code response code + * @param descrption response description + * @param severity response severity + * @param status response status code + */ + public void exiting(int code, String descrption, Level severity, + OnapLogConstants.ResponseStatus status) { + try { + + MDC.put(OnapLogConstants.Mdcs.RESPONSE_CODE, defaultToEmpty(code)); + MDC.put(OnapLogConstants.Mdcs.RESPONSE_DESCRIPTION, defaultToEmpty(descrption)); + MDC.put(OnapLogConstants.Mdcs.RESPONSE_SEVERITY, defaultToEmpty(severity)); + MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE, defaultToEmpty(status)); + + setElapsedTime(); + this.mlogger.info(OnapLogConstants.Markers.EXIT, "Exiting"); + } finally { + MDC.clear(); + } + } + + private void setElapsedTime() { + ZonedDateTime startTime = + ZonedDateTime.parse(MDC.get(OnapLogConstants.Mdcs.ENTRY_TIMESTAMP), + DateTimeFormatter.ISO_DATE_TIME.withZone(ZoneOffset.UTC)); + ZonedDateTime endTime = ZonedDateTime.now(ZoneOffset.UTC); + long duration = ChronoUnit.MILLIS.between(startTime, endTime); + MDC.put(OnapLogConstants.Mdcs.ELAPSED_TIME, String.valueOf(duration)); + } + + /** + * Get the property value. + * + * @param name The name of the property + * @return The value of the property + */ + public String getProperties(String name) { + return MDC.get(name); + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param con The HTTP url connection + * @param targetEntity The target entity + * @param targetServiceName The target service name + * @return The HTTP url connection + */ + public HttpURLConnection invoke(final HttpURLConnection con, String targetEntity, + String targetServiceName) { + return this.invokeGeneric(con, targetEntity, targetServiceName); + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param targetEntity The target entity + * @param targetServiceName The target service name + */ + public void invoke(String targetEntity, String targetServiceName) { + final String invocationId = UUID.randomUUID().toString(); + + invokeContext(targetEntity, targetServiceName, invocationId); + + // Log INVOKE*, with the invocationID as the message body. + // (We didn't really want this kind of behavior in the standard, + // but is it worse than new, single-message MDC?) + this.mlogger.info(OnapLogConstants.Markers.INVOKE, "INVOKE"); + this.mlogger.info(OnapLogConstants.Markers.INVOKE_SYNCHRONOUS + "{" + invocationId + "}"); + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param con The HTTPS url connection + * @param targetEntity The target entity + * @param targetServiceName The target service name + * @return The HTTPS url connection + */ + public HttpsURLConnection invokeHttps(final HttpsURLConnection con, String targetEntity, + String targetServiceName) { + return this.invokeGeneric(con, targetEntity, targetServiceName); + } + + /** + * Report pending invocation with <tt>INVOKE-RETURN</tt> marker. + */ + public void invokeReturn() { + MDC.put(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE, + OnapLogConstants.ResponseStatus.COMPLETE.toString()); + // Add the Invoke-return marker and clear the needed MDC + this.mlogger.info(OnapLogConstants.Markers.INVOKE_RETURN, "INVOKE-RETURN"); + invokeReturnContext(); + } + + /** + * Dependency-free nullcheck. + * + * @param in to be checked + * @param <T> argument (and return) type + * @return input arg + */ + private static <T> T checkNotNull(final T in) { + if (in == null) { + throw new NullPointerException(); + } + return in; + } + + /** + * Dependency-free string default. + * + * @param in to be filtered + * @return input string or null + */ + private static String defaultToEmpty(final Object in) { + if (in == null) { + return ""; + } + return in.toString(); + } + + /** + * Dependency-free string default. + * + * @param in to be filtered + * @return input string or null + */ + private static String defaultToUuid(final String in) { + if (in == null) { + return UUID.randomUUID().toString(); + } + return in; + } + + /** + * Set target related logging variables in thread local data via MDC. + * + * @param targetEntity Target entity (an external/sub component, for ex. "sdc") + * @param targetServiceName Target service name (name of API invoked on target) + * @param invocationId The invocation ID + */ + private void invokeContext(String targetEntity, String targetServiceName, String invocationId) { + MDC.put(OnapLogConstants.Mdcs.TARGET_ENTITY, defaultToEmpty(targetEntity)); + MDC.put(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME, defaultToEmpty(targetServiceName)); + MDC.put(OnapLogConstants.Mdcs.INVOCATIONID_OUT, invocationId); + MDC.put(OnapLogConstants.Mdcs.INVOKE_TIMESTAMP, ZonedDateTime.now(ZoneOffset.UTC) + .format(DateTimeFormatter.ofPattern(DATE_FORMATTER_ISO))); + } + + /** + * Clear target related logging variables in thread local data via MDC. + */ + private void invokeReturnContext() { + MDC.remove(OnapLogConstants.Mdcs.TARGET_ENTITY); + MDC.remove(OnapLogConstants.Mdcs.TARGET_SERVICE_NAME); + MDC.remove(OnapLogConstants.Mdcs.INVOCATIONID_OUT); + MDC.remove(OnapLogConstants.Mdcs.INVOKE_TIMESTAMP); + MDC.remove(OnapLogConstants.Mdcs.RESPONSE_STATUS_CODE); + } + + private <T extends URLConnection> T invokeGeneric(final T con, String targetEntity, + String targetServiceName) { + final String invocationId = UUID.randomUUID().toString(); + + // Set standard HTTP headers on (southbound request) builder. + con.setRequestProperty(OnapLogConstants.Headers.REQUEST_ID, + defaultToEmpty(MDC.get(OnapLogConstants.Mdcs.REQUEST_ID))); + con.setRequestProperty(OnapLogConstants.Headers.INVOCATION_ID, invocationId); + con.setRequestProperty(OnapLogConstants.Headers.PARTNER_NAME, + defaultToEmpty(MDC.get(OnapLogConstants.Mdcs.PARTNER_NAME))); + + invokeContext(targetEntity, targetServiceName, invocationId); + + // Log INVOKE*, with the invocationID as the message body. + // (We didn't really want this kind of behavior in the standard, + // but is it worse than new, single-message MDC?) + this.mlogger.info(OnapLogConstants.Markers.INVOKE, ""); + this.mlogger.info(OnapLogConstants.Markers.INVOKE_SYNCHRONOUS + "{" + invocationId + "}"); + return con; + } +} diff --git a/src/main/java/org/onap/clamp/clds/util/OnapLogConstants.java b/src/main/java/org/onap/clamp/clds/util/OnapLogConstants.java new file mode 100644 index 000000000..8952e5df1 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/util/OnapLogConstants.java @@ -0,0 +1,304 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.clds.util; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +/** + * Constants for standard ONAP headers, MDCs, etc. + */ +public final class OnapLogConstants { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private OnapLogConstants() { + throw new UnsupportedOperationException(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Marker constants. + */ + public static final class Markers { + + /** Marker reporting invocation. */ + public static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); + + /** Marker reporting invocation return. */ + public static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + + /** Marker reporting synchronous invocation. */ + public static final Marker INVOKE_SYNCHRONOUS = build("INVOKE", "SYNCHRONOUS"); + + /** Marker reporting asynchronous invocation. */ + public static final Marker INVOKE_ASYNCHRONOUS = build("INVOKE", "ASYNCHRONOUS"); + + /** Marker reporting entry into a component. */ + public static final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); + + /** Marker reporting exit from a component. */ + public static final Marker EXIT = MarkerFactory.getMarker("EXIT"); + + /** + * Build nested, detached marker. + * + * @param m1 top token. + * @param m2 sub-token. + * @return detached Marker. + */ + private static Marker build(final String m1, final String m2) { + final Marker marker = MarkerFactory.getDetachedMarker(m1); + marker.add(MarkerFactory.getDetachedMarker(m2)); + return marker; + } + + /** + * Hide and forbid construction. + */ + private Markers() { + throw new UnsupportedOperationException(); + } + } + + /** + * MDC name constants. + */ + public static final class Mdcs { + + // Tracing. //////////////////////////////////////////////////////////// + + /** MDC correlating messages for an invocation. */ + public static final String INVOCATION_ID = "InvocationID"; + + public static final String SERVER_INVOCATION_ID = "ServerInvocationId"; + + public static final String CLIENT_INVOCATION_ID = "ClientInvocationId"; + + /** MDC correlating messages for a logical transaction. */ + public static final String REQUEST_ID = "RequestID"; + + /** MDC recording calling partner name. */ + public static final String PARTNER_NAME = "PartnerName"; + + /** MDC recording current service. */ + public static final String SERVICE_NAME = "ServiceName"; + + /** MDC recording target service. */ + public static final String TARGET_SERVICE_NAME = "TargetServiceName"; + + /** MDC recording InvocationID Out. */ + public static final String INVOCATIONID_OUT = "InvocationIDOut"; + + /** MDC recording target entity. */ + public static final String TARGET_ENTITY = "TargetEntity"; + + /** MDC recording target element. */ + public static final String TARGET_ELEMENT = "TargetElement"; + + /** MDC recording current service instance id. */ + public static final String SERVICE_INSTANCE_ID = "ServiceInstanceID"; + + /** MDC recording current instance id. */ + public static final String INSTANCE_UUID = "InstanceID"; + + // Network. //////////////////////////////////////////////////////////// + + /** MDC recording caller address. */ + public static final String CLIENT_IP_ADDRESS = "ClientIPAddress"; + + /** MDC recording server IP address. */ + public static final String SERVER_IP_ADDRESS = "ServerIPAddress"; + + /** MDC recording server FQDN. */ + public static final String SERVER_FQDN = "ServerFQDN"; + + /** MDC recording virtual server name. */ + public static final String VIRTUAL_SERVER_NAME = "VirtualServerName"; + + /** MDC recording context name. */ + public static final String CONTEXT_NAME = "ContextName"; + + /** + * MDC recording timestamp at the start of the current request, + * with the same scope as {@link #REQUEST_ID}. + * + * <p> + * Open issues: + * <ul> + * <ul> + * Easily confused with {@link #INVOKE_TIMESTAMP}. + * </ul> + * <ul> + * No mechanism for propagation between components, e.g. via HTTP headers. + * </ul> + * <ul> + * Whatever mechanism we define, it's going to be costly. + * </ul> + * </ul> + * </p> + */ + public static final String ENTRY_TIMESTAMP = "EntryTimestamp"; + + /** MDC recording timestamp at the start of the current invocation. */ + public static final String INVOKE_TIMESTAMP = "InvokeTimestamp"; + + /** MDC recording elapsed time. */ + public static final String ELAPSED_TIME = "ElapsedTime"; + + /** MDC recording log timestamp. */ + public static final String LOG_TIMESTAMP = "LogTimestamp"; + + // Outcomes. /////////////////////////////////////////////////////////// + + /** MDC reporting outcome code. */ + public static final String RESPONSE_CODE = "ResponseCode"; + + /** MDC reporting outcome description. */ + public static final String RESPONSE_DESCRIPTION = "ResponseDesc"; + + /** MDC reporting severity */ + public static final String RESPONSE_SEVERITY = "Severity"; + + /** MDC reporting response status code */ + public static final String RESPONSE_STATUS_CODE = "StatusCode"; + + /** MDC recording error code. */ + public static final String ERROR_CODE = "ErrorCode"; + + /** MDC recording error description. */ + public static final String ERROR_DESC = "ErrorDesc"; + + // Unsorted. /////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private Mdcs() { + throw new UnsupportedOperationException(); + } + } + + /** + * Header name constants. + */ + public static final class Headers { + + /** HTTP <tt>X-ONAP-RequestID</tt> header. */ + public static final String REQUEST_ID = "X-ONAP-RequestID"; + + /** HTTP <tt>X-InvocationID</tt> header. */ + public static final String INVOCATION_ID = "X-ONAP-InvocationID"; + + /** HTTP <tt>X-ONAP-PartnerName</tt> header. */ + public static final String PARTNER_NAME = "X-ONAP-PartnerName"; + + /** + * Hide and forbid construction. + */ + private Headers() { + throw new UnsupportedOperationException(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Enums. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Response success or not, for setting <tt>StatusCode</tt>. + */ + public enum ResponseStatus { + + /** Success. */ + COMPLETE, + + /** Not. */ + ERROR, + + /** In Progress. */ + INPROGRESS + } + + /** + * Synchronous or asynchronous execution, for setting invocation marker. + */ + public enum InvocationMode { + + /** Synchronous, blocking. */ + SYNCHRONOUS("SYNCHRONOUS", Markers.INVOKE_SYNCHRONOUS), + + /** Asynchronous, non-blocking. */ + ASYNCHRONOUS("ASYNCHRONOUS", Markers.INVOKE_ASYNCHRONOUS); + + /** Enum value. */ + private String mString; + + /** Corresponding marker. */ + private Marker mMarker; + + /** + * Construct enum. + * + * @param s enum value. + * @param m corresponding Marker. + */ + InvocationMode(final String s, final Marker m) { + this.mString = s; + this.mMarker = m; + } + + /** + * Get Marker for enum. + * + * @return Marker. + */ + public Marker getMarker() { + return this.mMarker; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.mString; + } + } + +} diff --git a/src/main/java/org/onap/clamp/clds/util/ResourceFileUtils.java b/src/main/java/org/onap/clamp/clds/util/ResourceFileUtils.java new file mode 100644 index 000000000..f858ed2b8 --- /dev/null +++ b/src/main/java/org/onap/clamp/clds/util/ResourceFileUtils.java @@ -0,0 +1,89 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * 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.onap.clamp.clds.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Scanner; + +/** + * Utility methods supporting resources accesses. + */ +public final class ResourceFileUtils { + + /** + * getResourceAsStram supports the "file:" prefix as they use URL. + * So here we want to eliminate classpath: prefix, so that this class can get + * files from jar resource or file system. + */ + + private static final String CLASSPATH_PREFIX = "classpath:"; + + /** + * Private constructor to avoid creating instances of util class. + */ + private ResourceFileUtils() { + } + + /** + * Method to access a file from the jar resource folder or file system. + * Give the prefix "classpath:" so that it accesses the jar resource folder (default case) + * or the prefix "file:" so that it accesses the file system. + * + * @param fileName The path of the resource (no prefix it will be a classpath access, + * "classpath:/myfilename" or "file:/myfilename") + * @return The file as inputStream + */ + public static InputStream getResourceAsStream(String fileName) { + InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( + fileName.startsWith(CLASSPATH_PREFIX) ? fileName.replaceFirst(CLASSPATH_PREFIX, "") : fileName); + if (is == null) { + throw new IllegalArgumentException("Unable to find resource: " + fileName); + } + return is; + } + + /** + * Method to access a resource file as a string. + * Give the prefix "classpath:" so that it accesses the jar resource folder (default case) + * or the prefix "file:" so that it accesses the file system. + * + * @param fileName The path of the resource (no prefix it will be a classpath access, + * "classpath:/myfilename" or "file:/myfilename") + * @return The file as String + * @throws IOException In case of failure to find the file. + */ + public static String getResourceAsString(String fileName) throws IOException { + try (InputStream is = getResourceAsStream(fileName)) { + return streamToString(is); + } + } + + private static String streamToString(InputStream inputStream) { + try (Scanner scanner = new Scanner(inputStream)) { + Scanner delimitedScanner = scanner.useDelimiter("\\A"); + return delimitedScanner.hasNext() ? delimitedScanner.next() : ""; + } + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/configuration/ClampGsonDataFormat.java b/src/main/java/org/onap/clamp/configuration/ClampGsonDataFormat.java new file mode 100644 index 000000000..ca5f37656 --- /dev/null +++ b/src/main/java/org/onap/clamp/configuration/ClampGsonDataFormat.java @@ -0,0 +1,172 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.configuration; + +import com.google.gson.Gson; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; + +import org.apache.camel.Exchange; +import org.apache.camel.spi.DataFormat; +import org.apache.camel.spi.DataFormatName; +import org.apache.camel.support.ServiceSupport; +import org.apache.camel.util.IOHelper; +import org.onap.clamp.clds.util.JsonUtils; + +public class ClampGsonDataFormat extends ServiceSupport implements DataFormat, DataFormatName { + private Gson gson; + private Class<?> unmarshalType; + private Type unmarshalGenericType; + private boolean contentTypeHeader = true; + + public ClampGsonDataFormat() { + this(Object.class); + } + + /** + * Use the default Gson {@link Gson} and with a custom unmarshal type. + * + * @param unmarshalType the custom unmarshal type + */ + public ClampGsonDataFormat(Class<?> unmarshalType) { + this(null, unmarshalType); + } + + /** + * Use a custom Gson mapper and and unmarshal type. + * + * @param gson the custom mapper + * @param unmarshalType the custom unmarshal type + */ + public ClampGsonDataFormat(Gson gson, Class<?> unmarshalType) { + this.gson = gson; + this.unmarshalType = unmarshalType; + } + + /** + * Use the default Gson {@link Gson} and with a custom unmarshal generic type. + * + * @param unmarshalGenericType the custom unmarshal generic type + */ + public ClampGsonDataFormat(Type unmarshalGenericType) { + this(null, unmarshalGenericType); + } + + /** + * Use a custom Gson mapper and and unmarshal token type. + * + * @param gson the custom mapper + * @param unmarshalGenericType the custom unmarshal generic type + */ + public ClampGsonDataFormat(Gson gson, Type unmarshalGenericType) { + this.gson = gson; + this.unmarshalGenericType = unmarshalGenericType; + } + + @Override + public String getDataFormatName() { + return "clamp-gson"; + } + + @Override + public void marshal(final Exchange exchange, final Object graph, final OutputStream stream) throws Exception { + try (final OutputStreamWriter osw = new OutputStreamWriter(stream, StandardCharsets.UTF_8); + final BufferedWriter writer = IOHelper.buffered(osw)) { + gson.toJson(graph, writer); + } + + if (contentTypeHeader) { + if (exchange.hasOut()) { + exchange.getOut().setHeader(Exchange.CONTENT_TYPE, "application/json"); + } else { + exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json"); + } + } + } + + @Override + public Object unmarshal(final Exchange exchange, final InputStream stream) throws Exception { + try (final InputStreamReader isr = new InputStreamReader(stream, StandardCharsets.UTF_8); + final BufferedReader reader = IOHelper.buffered(isr)) { + if (unmarshalGenericType == null) { + return gson.fromJson(reader, unmarshalType); + } else { + return gson.fromJson(reader, unmarshalGenericType); + } + } + } + + @Override + protected void doStart() throws Exception { + if (gson == null) { + gson = JsonUtils.GSON_JPA_MODEL; + } + } + + @Override + protected void doStop() throws Exception { + // noop + } + + // Properties + // ------------------------------------------------------------------------- + + public Class<?> getUnmarshalType() { + return this.unmarshalType; + } + + public void setUnmarshalType(Class<?> unmarshalType) { + this.unmarshalType = unmarshalType; + } + + public Type getUnmarshalGenericType() { + return this.unmarshalGenericType; + } + + public void setUnmarshalGenericType(Type unmarshalGenericType) { + this.unmarshalGenericType = unmarshalGenericType; + } + + public boolean isContentTypeHeader() { + return contentTypeHeader; + } + + /** + * If enabled then Gson will set the Content-Type header to + * <tt>application/json</tt> when marshalling. + */ + public void setContentTypeHeader(boolean contentTypeHeader) { + this.contentTypeHeader = contentTypeHeader; + } + + public Gson getGson() { + return this.gson; + } +} diff --git a/src/main/java/org/onap/clamp/dao/model/gson/converter/InstantDeserializer.java b/src/main/java/org/onap/clamp/dao/model/gson/converter/InstantDeserializer.java new file mode 100644 index 000000000..2d63e55fa --- /dev/null +++ b/src/main/java/org/onap/clamp/dao/model/gson/converter/InstantDeserializer.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.dao.model.gson.converter; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; + +import java.lang.reflect.Type; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Locale; + +public class InstantDeserializer implements JsonDeserializer<Instant> { + + DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.US) + .withZone(ZoneId.systemDefault()); + + @Override + public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) { + return Instant.parse(json.getAsString()); + + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/dao/model/gson/converter/InstantSerializer.java b/src/main/java/org/onap/clamp/dao/model/gson/converter/InstantSerializer.java new file mode 100644 index 000000000..cdb439e46 --- /dev/null +++ b/src/main/java/org/onap/clamp/dao/model/gson/converter/InstantSerializer.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.dao.model.gson.converter; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; +import java.time.Instant; +import java.time.format.DateTimeFormatter; + +public class InstantSerializer implements JsonSerializer<Instant> { + + @Override + public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(DateTimeFormatter.ISO_INSTANT.format(src)); + } +}
\ No newline at end of file diff --git a/src/main/java/org/onap/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java b/src/main/java/org/onap/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java new file mode 100644 index 000000000..f5aba4e11 --- /dev/null +++ b/src/main/java/org/onap/clamp/dao/model/jsontype/JsonStringSqlTypeDescriptor.java @@ -0,0 +1,109 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.dao.model.jsontype; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.BasicExtractor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +public class JsonStringSqlTypeDescriptor implements SqlTypeDescriptor { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 1103168570216921981L; + + public static final JsonStringSqlTypeDescriptor INSTANCE = new JsonStringSqlTypeDescriptor(); + + @Override + public int getSqlType() { + return Types.OTHER; + } + + @Override + public boolean canBeRemapped() { + return true; + } + + @Override + public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) { + return new BasicBinder<X>(javaTypeDescriptor, this) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setString(index, javaTypeDescriptor.unwrap(value, String.class, options)); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + st.setString(name, javaTypeDescriptor.unwrap(value, String.class, options)); + } + }; + } + + @Override + public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) { + return new BasicExtractor<X>(javaTypeDescriptor, this) { + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap(extractJson(rs, name), options); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap(extractJson(statement, index), options); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return javaTypeDescriptor.wrap(extractJson(statement, name), options); + } + }; + } + + protected Object extractJson(ResultSet rs, String name) throws SQLException { + return rs.getObject(name); + } + + protected Object extractJson(CallableStatement statement, int index) throws SQLException { + return statement.getObject(index); + } + + protected Object extractJson(CallableStatement statement, String name) throws SQLException { + return statement.getObject(name); + } + +} diff --git a/src/main/java/org/onap/clamp/dao/model/jsontype/JsonTypeDescriptor.java b/src/main/java/org/onap/clamp/dao/model/jsontype/JsonTypeDescriptor.java new file mode 100644 index 000000000..518ec2d04 --- /dev/null +++ b/src/main/java/org/onap/clamp/dao/model/jsontype/JsonTypeDescriptor.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.dao.model.jsontype; + +import com.google.gson.JsonObject; + +import java.io.Serializable; + +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; +import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan; +import org.onap.clamp.clds.util.JsonUtils; + +public class JsonTypeDescriptor extends AbstractTypeDescriptor<JsonObject> { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -3439698221196089003L; + + public static final JsonTypeDescriptor INSTANCE = new JsonTypeDescriptor(); + + /** + * Creates an instance of JsonTypeDescriptor. + */ + public JsonTypeDescriptor() { + super(JsonObject.class, new ImmutableMutabilityPlan<JsonObject>() { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 1169396106518110214L; + + @Override + public Serializable disassemble(JsonObject value) { + return JsonUtils.GSON_JPA_MODEL.toJson(value); + } + + @Override + public JsonObject assemble(Serializable cached) { + return JsonUtils.GSON_JPA_MODEL.fromJson((String) cached, JsonObject.class); + } + + }); + } + + @Override + public String toString(JsonObject value) { + return JsonUtils.GSON_JPA_MODEL.toJson(value); + } + + @Override + public JsonObject fromString(String string) { + return JsonUtils.GSON_JPA_MODEL.fromJson(string, JsonObject.class); + } + + @Override + public <X> X unwrap(JsonObject value, Class<X> type, WrapperOptions options) { + if (value == null) { + return null; + } + + if (String.class.isAssignableFrom(type)) { + return (X) toString(value); + } + + if (JsonObject.class.isAssignableFrom(type)) { + return (X) JsonUtils.GSON_JPA_MODEL.toJson(toString(value)); + } + throw unknownUnwrap(type); + } + + @Override + public <X> JsonObject wrap(X value, WrapperOptions options) { + if (value == null) { + return null; + } + + if (String.class.isInstance(value)) { + return JsonUtils.GSON_JPA_MODEL.fromJson((String) value, JsonObject.class); + } + + throw unknownWrap(value.getClass()); + } + +} diff --git a/src/main/java/org/onap/clamp/dao/model/jsontype/StringJsonUserType.java b/src/main/java/org/onap/clamp/dao/model/jsontype/StringJsonUserType.java new file mode 100644 index 000000000..621fa8dad --- /dev/null +++ b/src/main/java/org/onap/clamp/dao/model/jsontype/StringJsonUserType.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.dao.model.jsontype; + +import com.google.gson.JsonObject; + +import org.hibernate.type.AbstractSingleColumnStandardBasicType; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +public class StringJsonUserType extends AbstractSingleColumnStandardBasicType<JsonObject> { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = -7929809808079327767L; + + public StringJsonUserType() { + super(JsonStringSqlTypeDescriptor.INSTANCE, JsonTypeDescriptor.INSTANCE); + } + + public StringJsonUserType(SqlTypeDescriptor sqlTypeDescriptor, JavaTypeDescriptor<JsonObject> javaTypeDescriptor) { + super(sqlTypeDescriptor, javaTypeDescriptor); + } + + @Override + public String getName() { + return "json"; + } + +} diff --git a/src/main/java/org/onap/clamp/flow/log/FlowLogOperation.java b/src/main/java/org/onap/clamp/flow/log/FlowLogOperation.java new file mode 100644 index 000000000..e31406b2c --- /dev/null +++ b/src/main/java/org/onap/clamp/flow/log/FlowLogOperation.java @@ -0,0 +1,101 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.flow.log; + +import javax.servlet.http.HttpServletRequest; +import org.apache.camel.Exchange; +import org.onap.clamp.clds.util.LoggingUtils; +import org.onap.clamp.clds.util.OnapLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * The Flow log operations. + */ +@Component +public class FlowLogOperation { + + protected static final Logger logger = LoggerFactory.getLogger(FlowLogOperation.class); + private LoggingUtils util = new LoggingUtils(logger); + + @Autowired + private HttpServletRequest request; + + /** + * Generate the entry log. + * + * @param serviceDesc + * The service description the loop name + */ + public void startLog(Exchange exchange, String serviceDesc) { + util.entering(request, serviceDesc); + exchange.setProperty(OnapLogConstants.Headers.REQUEST_ID, + util.getProperties(OnapLogConstants.Mdcs.REQUEST_ID)); + exchange.setProperty(OnapLogConstants.Headers.INVOCATION_ID, + util.getProperties(OnapLogConstants.Mdcs.INVOCATION_ID)); + exchange.setProperty(OnapLogConstants.Headers.PARTNER_NAME, + util.getProperties(OnapLogConstants.Mdcs.PARTNER_NAME)); + } + + /** + * Generate the exiting log. + */ + public void endLog() { + util.exiting(HttpStatus.OK.value(), "Successful", Level.INFO, + OnapLogConstants.ResponseStatus.COMPLETE); + } + + /** + * Generate the error exiting log. + */ + public void errorLog() { + util.exiting(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Failed", Level.INFO, + OnapLogConstants.ResponseStatus.ERROR); + } + + /** + * Generate the error exiting log. + */ + public void httpErrorLog() { + + } + + /** + * Generate the invoke log. + */ + public void invokeLog(String targetEntity, String targetServiceName) { + util.invoke(targetEntity, targetServiceName); + } + + /** + * Generate the invoke return marker. + */ + public void invokeReturnLog() { + util.invokeReturn(); + } +} diff --git a/src/main/java/org/onap/clamp/loop/CsarInstaller.java b/src/main/java/org/onap/clamp/loop/CsarInstaller.java new file mode 100644 index 000000000..6752a1a36 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/CsarInstaller.java @@ -0,0 +1,210 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Map.Entry; +import org.json.simple.parser.ParseException; +import org.onap.clamp.clds.client.DcaeInventoryServices; +import org.onap.clamp.clds.client.PolicyEngineServices; +import org.onap.clamp.clds.exception.sdc.controller.BlueprintParserException; +import org.onap.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.clamp.clds.model.dcae.DcaeInventoryResponse; +import org.onap.clamp.clds.sdc.controller.installer.BlueprintArtifact; +import org.onap.clamp.clds.sdc.controller.installer.BlueprintMicroService; +import org.onap.clamp.clds.sdc.controller.installer.BlueprintParser; +import org.onap.clamp.clds.sdc.controller.installer.ChainGenerator; +import org.onap.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.clamp.loop.cds.CdsDataInstaller; +import org.onap.clamp.loop.service.CsarServiceInstaller; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.loop.template.LoopElementModel; +import org.onap.clamp.loop.template.LoopTemplate; +import org.onap.clamp.loop.template.LoopTemplatesRepository; +import org.onap.clamp.loop.template.PolicyModel; +import org.onap.clamp.loop.template.PolicyModelId; +import org.onap.clamp.loop.template.PolicyModelsRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +/** + * This class will be instantiated by spring config, and used by Sdc Controller. + * There is no state kept by the bean. It's used to deploy the csar/notification + * received from SDC in DB. + */ +@Component +@Qualifier("csarInstaller") +public class CsarInstaller { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarInstaller.class); + + @Autowired + private PolicyModelsRepository policyModelsRepository; + + @Autowired + private LoopTemplatesRepository loopTemplatesRepository; + + @Autowired + private ChainGenerator chainGenerator; + + @Autowired + private DcaeInventoryServices dcaeInventoryService; + + @Autowired + private CsarServiceInstaller csarServiceInstaller; + + @Autowired + private CdsDataInstaller cdsDataInstaller; + + @Autowired + private PolicyEngineServices policyEngineServices; + + /** + * Verify whether Csar is deployed. + * + * @param csar The Csar Handler + * @return The flag indicating whether Csar is deployed + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + */ + public boolean isCsarAlreadyDeployed(CsarHandler csar) throws SdcArtifactInstallerException { + boolean alreadyInstalled = csarServiceInstaller.isServiceAlreadyDeployed(csar); + + for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) { + alreadyInstalled = alreadyInstalled + && loopTemplatesRepository.existsById(LoopTemplate.generateLoopTemplateName( + csar.getSdcNotification().getServiceName(), csar.getSdcNotification().getServiceVersion(), + blueprint.getValue().getResourceAttached().getResourceInstanceName(), + blueprint.getValue().getBlueprintArtifactName())); + } + return alreadyInstalled; + } + + /** + * Install the service and loop templates from the csar. + * + * @param csar The Csar Handler + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + * @throws InterruptedException The InterruptedException + * @throws BlueprintParserException In case of issues with the blueprint + * parsing + */ + public void installTheCsar(CsarHandler csar) + throws SdcArtifactInstallerException, InterruptedException, BlueprintParserException { + logger.info("Installing the CSAR " + csar.getFilePath()); + Service associatedService = csarServiceInstaller.installTheService(csar); + cdsDataInstaller.installCdsServiceProperties(csar, associatedService); + + installTheLoopTemplates(csar, associatedService); + logger.info("Successfully installed the CSAR " + csar.getFilePath()); + } + + /** + * Install the loop templates from the csar. + * + * @param csar The Csar Handler + * @param service The service object that is related to the loop + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + * @throws InterruptedException The InterruptedException + * @throws BlueprintParserException In case of issues with the blueprint + * parsing + */ + public void installTheLoopTemplates(CsarHandler csar, Service service) + throws SdcArtifactInstallerException, InterruptedException, BlueprintParserException { + try { + logger.info("Installing the Loops"); + for (Entry<String, BlueprintArtifact> blueprint : csar.getMapOfBlueprints().entrySet()) { + logger.info("Processing blueprint " + blueprint.getValue().getBlueprintArtifactName()); + loopTemplatesRepository.save(createLoopTemplateFromBlueprint(csar, blueprint.getValue(), service)); + } + logger.info("Successfully installed the Loops "); + } catch (IOException e) { + throw new SdcArtifactInstallerException("Exception caught during the Loop installation in database", e); + } catch (ParseException e) { + throw new SdcArtifactInstallerException("Exception caught during the Dcae query to get ServiceTypeId", e); + } + } + + private LoopTemplate createLoopTemplateFromBlueprint(CsarHandler csar, BlueprintArtifact blueprintArtifact, + Service service) + throws IOException, ParseException, InterruptedException, BlueprintParserException, + SdcArtifactInstallerException { + LoopTemplate newLoopTemplate = new LoopTemplate(); + newLoopTemplate.setBlueprint(blueprintArtifact.getDcaeBlueprint()); + newLoopTemplate.setName(LoopTemplate.generateLoopTemplateName(csar.getSdcNotification().getServiceName(), + csar.getSdcNotification().getServiceVersion(), + blueprintArtifact.getResourceAttached().getResourceInstanceName(), + blueprintArtifact.getBlueprintArtifactName())); + List<BlueprintMicroService> microServicesChain = chainGenerator + .getChainOfMicroServices(BlueprintParser.getMicroServices(blueprintArtifact.getDcaeBlueprint())); + if (microServicesChain.isEmpty()) { + microServicesChain = BlueprintParser.fallbackToOneMicroService(); + } + newLoopTemplate.setModelService(service); + newLoopTemplate.addLoopElementModels(createMicroServiceModels(blueprintArtifact, microServicesChain)); + newLoopTemplate.setMaximumInstancesAllowed(0); + DcaeInventoryResponse dcaeResponse = queryDcaeToGetServiceTypeId(blueprintArtifact); + newLoopTemplate.setDcaeBlueprintId(dcaeResponse.getTypeId()); + return newLoopTemplate; + } + + private HashSet<LoopElementModel> createMicroServiceModels(BlueprintArtifact blueprintArtifact, + List<BlueprintMicroService> microServicesChain) + throws SdcArtifactInstallerException { + HashSet<LoopElementModel> newSet = new HashSet<>(); + for (BlueprintMicroService microService : microServicesChain) { + LoopElementModel loopElementModel = + new LoopElementModel(microService.getModelType(), LoopElementModel.MICRO_SERVICE_TYPE, + null); + newSet.add(loopElementModel); + PolicyModel newPolicyModel = policyEngineServices.createPolicyModelFromPolicyEngine(microService); + if (newPolicyModel != null) { + loopElementModel.addPolicyModel(newPolicyModel); + } else { + throw new SdcArtifactInstallerException( + "Unable to find the policy specified in the blueprint " + + blueprintArtifact.getBlueprintArtifactName() + ") on the Policy Engine:" + + microService.getModelType() + "/" + microService.getModelVersion()); + } + } + return newSet; + } + + /** + * Get the service blueprint Id in the Dcae inventory using the SDC UUID. + * + * @return The DcaeInventoryResponse object containing the dcae values + */ + private DcaeInventoryResponse queryDcaeToGetServiceTypeId(BlueprintArtifact blueprintArtifact) + throws IOException, ParseException, InterruptedException { + return dcaeInventoryService.getDcaeInformation(blueprintArtifact.getBlueprintArtifactName(), + blueprintArtifact.getBlueprintInvariantServiceUuid(), + blueprintArtifact.getResourceAttached().getResourceInvariantUUID()); + } + +} diff --git a/src/main/java/org/onap/clamp/loop/Loop.java b/src/main/java/org/onap/clamp/loop/Loop.java new file mode 100644 index 000000000..36f74221e --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/Loop.java @@ -0,0 +1,391 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.hibernate.annotations.SortNatural; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.clamp.loop.common.AuditEntity; +import org.onap.clamp.loop.components.external.DcaeComponent; +import org.onap.clamp.loop.components.external.ExternalComponent; +import org.onap.clamp.loop.components.external.PolicyComponent; +import org.onap.clamp.loop.deploy.DcaeDeployParameters; +import org.onap.clamp.loop.log.LoopLog; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.loop.template.LoopElementModel; +import org.onap.clamp.loop.template.LoopTemplate; +import org.onap.clamp.policy.microservice.MicroServicePolicy; +import org.onap.clamp.policy.operational.OperationalPolicy; + +@Entity +@Table(name = "loops") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class Loop extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388642L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dcae_deployment_id") + private String dcaeDeploymentId; + + @Expose + @Column(name = "dcae_deployment_status_url") + private String dcaeDeploymentStatusUrl; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "global_properties_json") + private JsonObject globalPropertiesJson; + + @Expose + @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) + @JoinColumn(name = "service_uuid") + private Service modelService; + + @Expose + @Column(nullable = false, name = "last_computed_state") + @Enumerated(EnumType.STRING) + private LoopState lastComputedState; + + @Expose + @Transient + private final Map<String, ExternalComponent> components = new HashMap<>(); + + @Expose + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "loop", orphanRemoval = true) + private Set<OperationalPolicy> operationalPolicies = new HashSet<>(); + + @Expose + @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER) + @JoinTable(name = "loops_to_microservicepolicies", joinColumns = @JoinColumn(name = "loop_name"), + inverseJoinColumns = @JoinColumn(name = "microservicepolicy_name")) + private Set<MicroServicePolicy> microServicePolicies = new HashSet<>(); + + @Expose + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "loop", orphanRemoval = true) + @SortNatural + private SortedSet<LoopLog> loopLogs = new TreeSet<>(); + + @Expose + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER) + @JoinColumn(name = "loop_template_name", nullable = false) + private LoopTemplate loopTemplate; + + private void initializeExternalComponents() { + this.addComponent(new PolicyComponent()); + this.addComponent(new DcaeComponent()); + } + + /** + * Public constructor. + */ + public Loop() { + initializeExternalComponents(); + } + + /** + * Constructor. + */ + public Loop(String name) { + this.name = name; + this.lastComputedState = LoopState.DESIGN; + this.globalPropertiesJson = new JsonObject(); + initializeExternalComponents(); + } + + /** + * This constructor creates a loop from a loop template. + * + * @param name The loop name + * @param loopTemplate The loop template from which a new loop instance must be created + */ + public Loop(String name, LoopTemplate loopTemplate, ToscaConverterWithDictionarySupport toscaConverter) { + this(name); + this.setLoopTemplate(loopTemplate); + this.setModelService(loopTemplate.getModelService()); + loopTemplate.getLoopElementModelsUsed().forEach(element -> { + if (LoopElementModel.MICRO_SERVICE_TYPE.equals(element.getLoopElementModel().getLoopElementType())) { + this.addMicroServicePolicy((MicroServicePolicy) element.getLoopElementModel() + .createPolicyInstance(this, toscaConverter)); + } + else if (LoopElementModel.OPERATIONAL_POLICY_TYPE + .equals(element.getLoopElementModel().getLoopElementType())) { + this.addOperationalPolicy((OperationalPolicy) element.getLoopElementModel() + .createPolicyInstance(this, toscaConverter)); + } + }); + this.setGlobalPropertiesJson(DcaeDeployParameters.getDcaeDeploymentParametersInJson(this)); + } + + public String getName() { + return name; + } + + void setName(String name) { + this.name = name; + } + + public String getDcaeDeploymentId() { + return dcaeDeploymentId; + } + + void setDcaeDeploymentId(String dcaeDeploymentId) { + this.dcaeDeploymentId = dcaeDeploymentId; + } + + public String getDcaeDeploymentStatusUrl() { + return dcaeDeploymentStatusUrl; + } + + void setDcaeDeploymentStatusUrl(String dcaeDeploymentStatusUrl) { + this.dcaeDeploymentStatusUrl = dcaeDeploymentStatusUrl; + } + + public LoopState getLastComputedState() { + return lastComputedState; + } + + void setLastComputedState(LoopState lastComputedState) { + this.lastComputedState = lastComputedState; + } + + public Set<OperationalPolicy> getOperationalPolicies() { + return operationalPolicies; + } + + void setOperationalPolicies(Set<OperationalPolicy> operationalPolicies) { + this.operationalPolicies = operationalPolicies; + } + + public Set<MicroServicePolicy> getMicroServicePolicies() { + return microServicePolicies; + } + + void setMicroServicePolicies(Set<MicroServicePolicy> microServicePolicies) { + this.microServicePolicies = microServicePolicies; + } + + public JsonObject getGlobalPropertiesJson() { + return globalPropertiesJson; + } + + void setGlobalPropertiesJson(JsonObject globalPropertiesJson) { + this.globalPropertiesJson = globalPropertiesJson; + } + + public Set<LoopLog> getLoopLogs() { + return loopLogs; + } + + void setLoopLogs(SortedSet<LoopLog> loopLogs) { + this.loopLogs = loopLogs; + } + + /** + * This method adds an operational policy to the loop. + * + * @param opPolicy the operationalPolicy to add + */ + public void addOperationalPolicy(OperationalPolicy opPolicy) { + operationalPolicies.add(opPolicy); + opPolicy.setLoop(this); + } + + /** + * This method removes an operational policy to the loop. + * + * @param opPolicy the operationalPolicy to add + */ + public void removeOperationalPolicy(OperationalPolicy opPolicy) { + operationalPolicies.remove(opPolicy); + } + + /** + * This method adds an micro service policy to the loop. + * + * @param microServicePolicy the micro service to add + */ + public void addMicroServicePolicy(MicroServicePolicy microServicePolicy) { + microServicePolicies.add(microServicePolicy); + microServicePolicy.getUsedByLoops().add(this); + } + + public void addLog(LoopLog log) { + log.setLoop(this); + this.loopLogs.add(log); + } + + public Service getModelService() { + return modelService; + } + + void setModelService(Service modelService) { + this.modelService = modelService; + } + + public Map<String, ExternalComponent> getComponents() { + refreshDcaeComponents(); + return components; + } + + public ExternalComponent getComponent(String componentName) { + refreshDcaeComponents(); + return this.components.get(componentName); + } + + public void addComponent(ExternalComponent component) { + this.components.put(component.getComponentName(), component); + } + + public LoopTemplate getLoopTemplate() { + return loopTemplate; + } + + public void setLoopTemplate(LoopTemplate loopTemplate) { + this.loopTemplate = loopTemplate; + } + + private void refreshDcaeComponents() { + if (!this.loopTemplate.getUniqueBlueprint()) { + this.components.remove("DCAE"); + for (MicroServicePolicy policy : this.microServicePolicies) { + if (!this.components.containsKey("DCAE_" + policy.getName())) { + this.addComponent(new DcaeComponent(policy.getName())); + } + } + } + } + + /** + * Return the operationalPolicy object with the opPolicyName. + * + * @param opPolicyName The operationalPolicy name + * @return The OperationalPolicy object found in loop object + */ + public OperationalPolicy getOperationalPolicy(String opPolicyName) { + for (OperationalPolicy operationalPolicy : this.getOperationalPolicies()) { + if (operationalPolicy.getName().equals(opPolicyName)) { + return operationalPolicy; + } + } + return null; + } + + /** + * Return the microServicePolicy object with the msPolicyName. + * + * @param msPolicyName The microServicePolicy name + * @return The MicroServicePolicy object found in loop object + */ + public MicroServicePolicy getMicroServicePolicy(String msPolicyName) { + for (MicroServicePolicy microServicePolicy : this.getMicroServicePolicies()) { + if (microServicePolicy.getName().equals(msPolicyName)) { + return microServicePolicy; + } + } + return null; + } + + /** + * Generate the loop name. + * + * @param serviceName The service name + * @param serviceVersion The service version + * @param resourceName The resource name + * @param blueprintFileName The blueprint file name + * @return The generated loop name + */ + public static String generateLoopName(String serviceName, String serviceVersion, String resourceName, + String blueprintFileName) { + StringBuilder buffer = new StringBuilder("LOOP_").append(serviceName).append("_v").append(serviceVersion) + .append("_").append(resourceName).append("_").append(blueprintFileName.replaceAll(".yaml", "")); + return buffer.toString().replace('.', '_').replaceAll(" ", ""); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Loop other = (Loop) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } + else if (!name.equals(other.name)) { + return false; + } + return true; + } + +} diff --git a/src/main/java/org/onap/clamp/loop/LoopController.java b/src/main/java/org/onap/clamp/loop/LoopController.java new file mode 100644 index 000000000..603726f56 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/LoopController.java @@ -0,0 +1,204 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.loop; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.List; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.policy.microservice.MicroServicePolicy; +import org.onap.clamp.policy.microservice.MicroServicePolicyService; +import org.onap.clamp.policy.operational.OperationalPolicy; +import org.onap.clamp.policy.operational.OperationalPolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +@Controller +public class LoopController { + + private final LoopService loopService; + + private final ToscaConverterWithDictionarySupport toscaConverter; + + private final OperationalPolicyService operationalPolicyService; + + private final MicroServicePolicyService microServicePolicyService; + + private static final Type OPERATIONAL_POLICY_TYPE = new TypeToken<List<OperationalPolicy>>() { + }.getType(); + + private static final Type MICROSERVICE_POLICY_TYPE = new TypeToken<List<MicroServicePolicy>>() { + }.getType(); + + + /** + * Constructor. + * + * @param loopService loopService + * @param operationalPolicyService operationalPolicyService + * @param microServicePolicyService microServicePolicyService + * @param toscaConverter toscaConverter + */ + @Autowired + public LoopController(LoopService loopService, OperationalPolicyService operationalPolicyService, + MicroServicePolicyService microServicePolicyService, + ToscaConverterWithDictionarySupport toscaConverter) { + this.loopService = loopService; + this.toscaConverter = toscaConverter; + this.operationalPolicyService = operationalPolicyService; + this.microServicePolicyService = microServicePolicyService; + } + + public Loop createLoop(String loopName, String templateName) { + return loopService.createLoopFromTemplate(loopName, templateName); + } + + public List<String> getLoopNames() { + return loopService.getClosedLoopNames(); + } + + public Loop getLoop(String loopName) { + return loopService.getLoop(loopName); + } + + /** + * Update the Operational Policy properties. + * + * @param loopName The loop name + * @param operationalPoliciesJson The new Operational Policy properties + * @return The updated loop + */ + public Loop updateOperationalPolicies(String loopName, JsonArray operationalPoliciesJson) { + List<OperationalPolicy> operationalPolicies = JsonUtils.GSON_JPA_MODEL.fromJson(operationalPoliciesJson, + OPERATIONAL_POLICY_TYPE); + return loopService.updateAndSaveOperationalPolicies(loopName, operationalPolicies); + } + + /** + * Update the whole array of MicroService policies properties. + * + * @param loopName The loop name + * @param microServicePoliciesJson The array of all MicroService policies + * properties + * @return The updated loop + */ + public Loop updateMicroservicePolicies(String loopName, JsonArray microServicePoliciesJson) { + List<MicroServicePolicy> microservicePolicies = JsonUtils.GSON_JPA_MODEL.fromJson(microServicePoliciesJson, + MICROSERVICE_POLICY_TYPE); + return loopService.updateAndSaveMicroservicePolicies(loopName, microservicePolicies); + } + + /** + * Update the global properties. + * + * @param loopName The loop name + * @param globalProperties The updated global properties + * @return The updated loop + */ + public Loop updateGlobalPropertiesJson(String loopName, JsonObject globalProperties) { + return loopService.updateAndSaveGlobalPropertiesJson(loopName, globalProperties); + } + + /** + * This method add an operational policy to a loop instance. + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + public Loop addOperationalPolicy(String loopName, String policyType, String policyVersion) throws IOException { + return loopService.addOperationalPolicy(loopName, policyType, policyVersion); + } + + /** + * This method removes an operational policy from a loop instance. + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + public Loop removeOperationalPolicy(String loopName, String policyType, String policyVersion) { + return loopService.removeOperationalPolicy(loopName, policyType, policyVersion); + } + + /** + * This method deletes the loop. + * + * @param loopName The loop Name + */ + public void deleteLoop(String loopName) { + loopService.deleteLoop(loopName); + } + + /** + * Update one MicroService policy properties. + * + * @param loopName The loop name + * @param newMicroservicePolicy The new MicroService policy properties + * @return The updated MicroService policy + */ + public MicroServicePolicy updateMicroservicePolicy(String loopName, MicroServicePolicy newMicroservicePolicy) { + return loopService.updateMicroservicePolicy(loopName, newMicroservicePolicy); + } + + /** + * Refresh the Operational Policy Json representation of the loop. + * + * @param loop The loop + * @param operationalPolicyName The operational policy name that needs a refresh + * @return The loop object + */ + public Loop refreshOperationalPolicyJsonRepresentation(Loop loop, String operationalPolicyName) { + for (OperationalPolicy operationalPolicy : loop.getOperationalPolicies()) { + if (operationalPolicy.getName().equals(operationalPolicyName)) { + this.operationalPolicyService + .refreshOperationalPolicyJsonRepresentation(operationalPolicy, toscaConverter); + } + } + return loop; + } + + /** + * Refresh the Config Policy Json representation of the loop. + * + * @param loop The loop + * @param microServicePolicyName The microservice policy name that needs a refresh + * @return The loop object + */ + public Loop refreshMicroServicePolicyJsonRepresentation(Loop loop, String microServicePolicyName) { + for (MicroServicePolicy microServicePolicy : loop.getMicroServicePolicies()) { + if (microServicePolicy.getName().equals(microServicePolicyName)) { + this.microServicePolicyService + .refreshMicroServicePolicyJsonRepresentation(microServicePolicy, toscaConverter, loop); + } + } + return loop; + } +} diff --git a/src/main/java/org/onap/clamp/loop/LoopService.java b/src/main/java/org/onap/clamp/loop/LoopService.java new file mode 100644 index 000000000..5f0822816 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/LoopService.java @@ -0,0 +1,190 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.loop; + +import com.google.gson.JsonObject; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import javax.persistence.EntityNotFoundException; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.loop.template.LoopTemplatesService; +import org.onap.clamp.loop.template.PolicyModel; +import org.onap.clamp.loop.template.PolicyModelsService; +import org.onap.clamp.policy.microservice.MicroServicePolicy; +import org.onap.clamp.policy.microservice.MicroServicePolicyService; +import org.onap.clamp.policy.operational.OperationalPolicy; +import org.onap.clamp.policy.operational.OperationalPolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class LoopService { + + @Autowired + private LoopsRepository loopsRepository; + + @Autowired + private MicroServicePolicyService microservicePolicyService; + + @Autowired + private OperationalPolicyService operationalPolicyService; + + @Autowired + private PolicyModelsService policyModelsService; + + @Autowired + private LoopTemplatesService loopTemplateService; + + @Autowired + private ToscaConverterWithDictionarySupport toscaConverter; + + Loop saveOrUpdateLoop(Loop loop) { + return loopsRepository.save(loop); + } + + List<String> getClosedLoopNames() { + return loopsRepository.getAllLoopNames(); + } + + public Loop getLoop(String loopName) { + return loopsRepository.findById(loopName).orElse(null); + } + + public void deleteLoop(String loopName) { + loopsRepository.deleteById(loopName); + } + + /** + * Creates a Loop Instance from Loop Template Name. + * + * @param loopName Name of the Loop to be created + * @param templateName Loop Template to used for Loop + * @return Loop Instance + */ + public Loop createLoopFromTemplate(String loopName, String templateName) { + return loopsRepository + .save(new Loop(loopName, loopTemplateService.getLoopTemplate(templateName), toscaConverter)); + } + + /** + * This method is used to refresh the DCAE deployment status fields. + * + * @param loop The loop instance to be modified + * @param deploymentId The deployment ID as returned by DCAE + * @param deploymentUrl The Deployment URL as returned by DCAE + */ + public void updateDcaeDeploymentFields(Loop loop, String deploymentId, String deploymentUrl) { + loop.setDcaeDeploymentId(deploymentId); + loop.setDcaeDeploymentStatusUrl(deploymentUrl); + loopsRepository.saveAndFlush(loop); + } + + public void updateLoopState(Loop loop, String newState) { + loop.setLastComputedState(LoopState.valueOf(newState)); + loopsRepository.save(loop); + } + + /** + * This method add an operational policy to a loop instance. + * This creates an operational policy from the policy model info and not the loop element model + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + Loop addOperationalPolicy(String loopName, String policyType, String policyVersion) throws IOException { + Loop loop = getLoop(loopName); + PolicyModel policyModel = policyModelsService.getPolicyModel(policyType, policyVersion); + Set<OperationalPolicy> opPolicySet = loop.getOperationalPolicies(); + for (OperationalPolicy opPolicy : opPolicySet) { + if (opPolicy.getPolicyModel().equals(policyModel)) { + throw new IllegalArgumentException( + "This type of Operational Policy is already added to the loop. Please choose another one."); + } + } + if (policyModel == null) { + return null; + } + loop.addOperationalPolicy( + new OperationalPolicy(loop, loop.getModelService(), policyModel, toscaConverter)); + return loopsRepository.saveAndFlush(loop); + } + + /** + * This method remove an operational policy to a loop instance. + * + * @param loopName The loop name + * @param policyType The policy model type + * @param policyVersion The policy model version + * @return The loop modified + */ + Loop removeOperationalPolicy(String loopName, String policyType, String policyVersion) { + Loop loop = getLoop(loopName); + PolicyModel policyModel = policyModelsService.getPolicyModel(policyType, policyVersion); + if (policyModel == null) { + return null; + } + for (OperationalPolicy opPolicy : loop.getOperationalPolicies()) { + if (opPolicy.getPolicyModel().getPolicyModelType().equals(policyType) + && opPolicy.getPolicyModel().getVersion().equals(policyVersion)) { + loop.removeOperationalPolicy(opPolicy); + break; + } + } + return loopsRepository.saveAndFlush(loop); + } + + Loop updateAndSaveOperationalPolicies(String loopName, List<OperationalPolicy> newOperationalPolicies) { + Loop loop = findClosedLoopByName(loopName); + Set<OperationalPolicy> newPolicies = operationalPolicyService.updatePolicies(loop, newOperationalPolicies); + loop.setOperationalPolicies(newPolicies); + return loopsRepository.save(loop); + } + + Loop updateAndSaveMicroservicePolicies(String loopName, List<MicroServicePolicy> newMicroservicePolicies) { + Loop loop = findClosedLoopByName(loopName); + Set<MicroServicePolicy> newPolicies = microservicePolicyService.updatePolicies(loop, newMicroservicePolicies); + loop.setMicroServicePolicies(newPolicies); + return loopsRepository.save(loop); + } + + Loop updateAndSaveGlobalPropertiesJson(String loopName, JsonObject newGlobalPropertiesJson) { + Loop loop = findClosedLoopByName(loopName); + loop.setGlobalPropertiesJson(newGlobalPropertiesJson); + return loopsRepository.save(loop); + } + + MicroServicePolicy updateMicroservicePolicy(String loopName, MicroServicePolicy newMicroservicePolicy) { + Loop loop = findClosedLoopByName(loopName); + return microservicePolicyService.getAndUpdateMicroServicePolicy(loop, newMicroservicePolicy); + } + + private Loop findClosedLoopByName(String loopName) { + return loopsRepository.findById(loopName) + .orElseThrow(() -> new EntityNotFoundException("Couldn't find closed loop named: " + loopName)); + } +} + diff --git a/src/main/java/org/onap/clamp/loop/LoopState.java b/src/main/java/org/onap/clamp/loop/LoopState.java new file mode 100644 index 000000000..4707730ce --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/LoopState.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop; + +public enum LoopState { + DESIGN, SUBMITTED, DEPLOYED, RUNNING, STOPPED, IN_ERROR, WAITING; +} diff --git a/src/main/java/org/onap/clamp/loop/LoopsRepository.java b/src/main/java/org/onap/clamp/loop/LoopsRepository.java new file mode 100644 index 000000000..aaa49116f --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/LoopsRepository.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopsRepository extends JpaRepository<Loop, String> { + + @Query("SELECT loop.name FROM Loop as loop") + List<String> getAllLoopNames(); +} diff --git a/src/main/java/org/onap/clamp/loop/cds/CdsDataInstaller.java b/src/main/java/org/onap/clamp/loop/cds/CdsDataInstaller.java new file mode 100644 index 000000000..d18cae1d6 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/cds/CdsDataInstaller.java @@ -0,0 +1,173 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights + * reserved. + * * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.onap.clamp.loop.cds; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import org.onap.clamp.clds.client.CdsServices; +import org.onap.clamp.clds.model.cds.CdsBpWorkFlowListResponse; +import org.onap.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.loop.service.ServicesRepository; +import org.onap.sdc.tosca.parser.enums.SdcTypes; +import org.onap.sdc.toscaparser.api.NodeTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +/** + * This class installs the cds data in the service model properties. + * This can be refreshed later on by clicking on the button refresh, when recomputing the json schema. + */ +@Component +public class CdsDataInstaller { + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CdsDataInstaller.class); + + @Autowired + CdsServices cdsServices; + + @Autowired + ServicesRepository serviceRepository; + + public static final String CONTROLLER_PROPERTIES = "controllerProperties"; + public static final String SDNC_MODEL_NAME = "sdnc_model_name"; + public static final String SDNC_MODEL_VERSION = "sdnc_model_version"; + + /** + * This method installs the service model properties for CDS in the service object given in input. + * + * @param csar The csar from sdc + * @param service the service object already provisioned with csar data + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public Service installCdsServiceProperties(CsarHandler csar, Service service) { + // Iterate on all types defined in the tosca lib + for (SdcTypes type : SdcTypes.values()) { + JsonObject resourcesPropByType = service.getResourceByType(type.getValue()); + // For each type, get the metadata of each nodetemplate + for (NodeTemplate nodeTemplate : csar.getSdcCsarHelper().getServiceNodeTemplateBySdcType(type)) { + // get cds artifact information and save in resources Prop + if (SdcTypes.PNF == type || SdcTypes.VF == type) { + JsonObject controllerProperties = createCdsArtifactProperties( + String.valueOf(nodeTemplate.getPropertyValue(SDNC_MODEL_NAME)), + String.valueOf(nodeTemplate.getPropertyValue(SDNC_MODEL_VERSION))); + if (controllerProperties != null) { + resourcesPropByType.getAsJsonObject(nodeTemplate.getName()) + .add(CONTROLLER_PROPERTIES, controllerProperties); + logger.info("Successfully installed the CDS data in Service"); + } + else { + logger.warn("Skipping CDS data installation in Service, as sdnc_model_name and " + + "sdnc_model_version are not provided in the CSAR"); + } + } + } + } + serviceRepository.save(service); + + return service; + } + + /** + * This method updates the service model properties for CDS in the service object given in input. + * + * @param service the service object already provisioned with csar data + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public Service updateCdsServiceProperties(Service service) { + // Iterate on all types defined in the tosca lib + for (SdcTypes type : SdcTypes.values()) { + JsonObject resourcesPropByType = service.getResourceByType(type.getValue()); + for (String resourceName : resourcesPropByType.keySet()) { + // get cds artifact information and save in resources Prop + if ((SdcTypes.PNF == type || SdcTypes.VF == type) && resourcesPropByType.getAsJsonObject(resourceName) + .getAsJsonObject(CONTROLLER_PROPERTIES) != null) { + JsonObject controllerProperties = + createCdsArtifactProperties(resourcesPropByType.getAsJsonObject(resourceName) + .getAsJsonObject(CONTROLLER_PROPERTIES).get(SDNC_MODEL_NAME) + .getAsString(), + resourcesPropByType.getAsJsonObject(resourceName) + .getAsJsonObject(CONTROLLER_PROPERTIES).get(SDNC_MODEL_VERSION) + .getAsString()); + if (controllerProperties != null) { + resourcesPropByType.getAsJsonObject(resourceName) + .add(CONTROLLER_PROPERTIES, controllerProperties); + } + } + } + } + serviceRepository.save(service); + logger.info("Successfully updated the CDS data in Service"); + return service; + } + + /** + * Retrieve CDS artifacts information from node template and save in resource object. + * + * @param sdncModelName sdnc model name + * @param sdncModelVersion sdnc model version + * @return Returns CDS artifacts information + */ + private JsonObject createCdsArtifactProperties(String sdncModelName, String sdncModelVersion) { + if (sdncModelName != null && !"null".equals(sdncModelName) + && sdncModelVersion != null && !"null".equals(sdncModelVersion)) { + JsonObject controllerProperties = new JsonObject(); + controllerProperties.addProperty(SDNC_MODEL_NAME, sdncModelName); + controllerProperties.addProperty(SDNC_MODEL_VERSION, sdncModelVersion); + + CdsBpWorkFlowListResponse response = + queryCdsToGetWorkFlowList(sdncModelName, sdncModelVersion); + if (response == null) { + return controllerProperties; + } + + JsonObject workFlowProps = new JsonObject(); + for (String workFlow : response.getWorkflows()) { + logger.info("Found CDS workflow " + workFlow + " for model name " + sdncModelName + " and version " + + sdncModelVersion); + JsonObject inputs = queryCdsToGetWorkFlowInputProperties(response.getBlueprintName(), + response.getVersion(), workFlow); + workFlowProps.add(workFlow, inputs); + } + + controllerProperties.add("workflows", workFlowProps); + return controllerProperties; + } + return null; + } + + + private CdsBpWorkFlowListResponse queryCdsToGetWorkFlowList(String artifactName, String artifactVersion) { + return cdsServices.getBlueprintWorkflowList(artifactName, artifactVersion); + } + + private JsonObject queryCdsToGetWorkFlowInputProperties(String artifactName, String artifactVersion, + String workFlow) { + return cdsServices.getWorkflowInputProperties(artifactName, artifactVersion, workFlow); + } +} diff --git a/src/main/java/org/onap/clamp/loop/common/AuditEntity.java b/src/main/java/org/onap/clamp/loop/common/AuditEntity.java new file mode 100644 index 000000000..7ce12ec6b --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/common/AuditEntity.java @@ -0,0 +1,148 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.loop.common; + +import com.google.gson.annotations.Expose; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import javax.persistence.Column; +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +/** + * This class is the parent of the hibernate entities requiring to be audited. + */ +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class AuditEntity { + + @Expose + @CreatedDate + @Column(name = "created_timestamp", nullable = false, updatable = false) + private Instant createdDate; + + @Expose + @LastModifiedDate + @Column(name = "updated_timestamp", nullable = false) + private Instant updatedDate; + + @Expose + @LastModifiedBy + @Column(name = "updated_by") + private String updatedBy; + + @Expose + @CreatedBy + @Column(name = "created_by") + private String createdBy; + + public Instant getCreatedDate() { + return createdDate; + } + + /** + * createdDate setter. + * + * @param createdDate The created Date object + */ + public void setCreatedDate(Instant createdDate) { + if (createdDate != null) { + this.createdDate = createdDate.truncatedTo(ChronoUnit.SECONDS); + } + else { + this.createdDate = null; + } + } + + /** + * updatedDate getter. + * + * @return the updatedDate + */ + public Instant getUpdatedDate() { + return updatedDate; + } + + /** + * updatedDate setter. + * + * @param updatedDate updatedDate to set + */ + public void setUpdatedDate(Instant updatedDate) { + if (updatedDate != null) { + this.updatedDate = updatedDate.truncatedTo(ChronoUnit.SECONDS); + } + else { + this.updatedDate = null; + } + } + + /** + * updatedBy getter. + * + * @return the updatedBy + */ + public String getUpdatedBy() { + return updatedBy; + } + + /** + * updatedBy setter. + * + * @param updatedBy the updatedBy + */ + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + /** + * createdBy getter. + * + * @return the createdBy + */ + public String getCreatedBy() { + return createdBy; + } + + /** + * createdBy setter. + * + * @param createdBy the createdBy to set + */ + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + /** + * Empty constructor. + */ + public AuditEntity() { + } + +} diff --git a/src/main/java/org/onap/clamp/loop/components/external/DcaeComponent.java b/src/main/java/org/onap/clamp/loop/components/external/DcaeComponent.java new file mode 100644 index 000000000..8b8547195 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/components/external/DcaeComponent.java @@ -0,0 +1,253 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.components.external; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +import javax.persistence.Transient; +import org.apache.camel.Exchange; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.onap.clamp.clds.model.dcae.DcaeInventoryResponse; +import org.onap.clamp.clds.model.dcae.DcaeOperationStatusResponse; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.policy.microservice.MicroServicePolicy; + +public class DcaeComponent extends ExternalComponent { + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(DcaeComponent.class); + + private static final String DCAE_DEPLOYMENT_PREFIX = "CLAMP_"; + private static final String DEPLOYMENT_PARAMETER = "dcaeDeployParameters"; + private static final String DCAE_SERVICETYPE_ID = "serviceTypeId"; + private static final String DCAE_INPUTS = "inputs"; + public static final String UNIQUE_BLUEPRINT_PARAMETERS = "uniqueBlueprintParameters"; + + private String name; + + public static final ExternalComponentState BLUEPRINT_DEPLOYED = new ExternalComponentState("BLUEPRINT_DEPLOYED", + "The DCAE blueprint has been found in the DCAE inventory but not yet instancianted for this loop"); + public static final ExternalComponentState PROCESSING_MICROSERVICE_INSTALLATION = new ExternalComponentState( + "PROCESSING_MICROSERVICE_INSTALLATION", "Clamp has requested DCAE to install the microservices " + + "defined in the DCAE blueprint and it's currently processing the request"); + public static final ExternalComponentState MICROSERVICE_INSTALLATION_FAILED = new ExternalComponentState( + "MICROSERVICE_INSTALLATION_FAILED", + "Clamp has requested DCAE to install the microservices defined in the DCAE blueprint and it failed"); + public static final ExternalComponentState MICROSERVICE_INSTALLED_SUCCESSFULLY = new ExternalComponentState( + "MICROSERVICE_INSTALLED_SUCCESSFULLY", + "Clamp has requested DCAE to install the DCAE blueprint and it has been installed successfully"); + public static final ExternalComponentState PROCESSING_MICROSERVICE_UNINSTALLATION = new ExternalComponentState( + "PROCESSING_MICROSERVICE_UNINSTALLATION", "Clamp has requested DCAE to uninstall the microservices " + + "defined in the DCAE blueprint and it's currently processing the request"); + public static final ExternalComponentState MICROSERVICE_UNINSTALLATION_FAILED = new ExternalComponentState( + "MICROSERVICE_UNINSTALLATION_FAILED", + "Clamp has requested DCAE to uninstall the microservices defined in the DCAE blueprint and it failed"); + public static final ExternalComponentState MICROSERVICE_UNINSTALLED_SUCCESSFULLY = new ExternalComponentState( + "MICROSERVICE_UNINSTALLED_SUCCESSFULLY", + "Clamp has requested DCAE to uninstall the DCAE blueprint and it has been uninstalled successfully"); + public static final ExternalComponentState IN_ERROR = new ExternalComponentState("IN_ERROR", + "There was an error during the request done to DCAE, look at the logs or try again"); + + public DcaeComponent() { + super(BLUEPRINT_DEPLOYED); + this.name = "DCAE"; + } + + public DcaeComponent(String name) { + super(BLUEPRINT_DEPLOYED); + this.name = "DCAE_" + name; + } + + @Override + public String getComponentName() { + return name; + } + + + /** + * Convert the json response to a DcaeOperationStatusResponse. + * + * @param responseBody The DCAE response Json paylaod + * @return The dcae object provisioned + */ + public static DcaeOperationStatusResponse convertDcaeResponse(String responseBody) { + if (responseBody != null && !responseBody.isEmpty()) { + return JsonUtils.GSON_JPA_MODEL.fromJson(responseBody, DcaeOperationStatusResponse.class); + } else { + return null; + } + } + + /** + * Generate the deployment id, it's random. + * + * @return The deployment id + */ + public static String generateDeploymentId() { + return DCAE_DEPLOYMENT_PREFIX + UUID.randomUUID(); + } + + /** + * This method prepare the url returned by DCAE to check the status if fine. It + * extracts it from the dcaeResponse. + * + * @param dcaeResponse The dcae response object + * @return the Right Url modified if needed + */ + public static String getStatusUrl(DcaeOperationStatusResponse dcaeResponse) { + return dcaeResponse.getLinks().getStatus().replaceAll("http:", "http4:").replaceAll("https:", "https4:"); + } + + /** + * Return the deploy payload for DCAE. + * + * @param loop The loop object + * @return The payload used to send deploy closed loop request + */ + public static String getDeployPayload(Loop loop) { + JsonObject globalProp = loop.getGlobalPropertiesJson(); + JsonObject deploymentProp = globalProp.getAsJsonObject(DEPLOYMENT_PARAMETER).getAsJsonObject( + UNIQUE_BLUEPRINT_PARAMETERS); + + String serviceTypeId = loop.getLoopTemplate().getDcaeBlueprintId(); + + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, serviceTypeId); + if (deploymentProp != null) { + rootObject.add(DCAE_INPUTS, deploymentProp); + } + logger.info("DCAE Deploy payload for unique blueprint: " + rootObject.toString()); + return rootObject.toString(); + } + + /** + * Return the deploy payload for DCAE. + * + * @param loop The loop object + * @param microServicePolicy The micro service policy + * @return The payload used to send deploy closed loop request + */ + public static String getDeployPayload(Loop loop, MicroServicePolicy microServicePolicy) { + JsonObject globalProp = loop.getGlobalPropertiesJson(); + JsonObject deploymentProp = + globalProp.getAsJsonObject(DEPLOYMENT_PARAMETER).getAsJsonObject(microServicePolicy.getName()); + + String serviceTypeId = microServicePolicy.getDcaeBlueprintId(); + + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, serviceTypeId); + if (deploymentProp != null) { + rootObject.add(DCAE_INPUTS, deploymentProp); + } + logger.info("DCAE Deploy payload for multiple blueprints: " + rootObject.toString()); + return rootObject.toString(); + } + + /** + * Return the uninstallation payload for DCAE. + * + * @param loop The loop object + * @return The payload in string (json) + */ + public static String getUndeployPayload(Loop loop) { + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, loop.getLoopTemplate().getDcaeBlueprintId()); + logger.info("DCAE Undeploy payload for unique blueprint: " + rootObject.toString()); + return rootObject.toString(); + } + + /** + * Return the uninstallation payload for DCAE. + * + * @param policy The microServicePolicy object + * @return The payload in string (json) + */ + public static String getUndeployPayload(MicroServicePolicy policy) { + JsonObject rootObject = new JsonObject(); + rootObject.addProperty(DCAE_SERVICETYPE_ID, policy.getDcaeBlueprintId()); + logger.info("DCAE Undeploy payload for multiple blueprints: " + rootObject.toString()); + return rootObject.toString(); + } + + @Override + public ExternalComponentState computeState(Exchange camelExchange) { + + DcaeOperationStatusResponse dcaeResponse = (DcaeOperationStatusResponse) camelExchange.getIn().getExchange() + .getProperty("dcaeResponse"); + + if (dcaeResponse == null) { + setState(BLUEPRINT_DEPLOYED); + } else if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus().equals("succeeded")) { + setState(MICROSERVICE_INSTALLED_SUCCESSFULLY); + } else if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus().equals("processing")) { + setState(PROCESSING_MICROSERVICE_INSTALLATION); + } else if (dcaeResponse.getOperationType().equals("install") && dcaeResponse.getStatus().equals("failed")) { + setState(MICROSERVICE_INSTALLATION_FAILED); + } else if (dcaeResponse.getOperationType().equals("uninstall") + && dcaeResponse.getStatus().equals("succeeded")) { + setState(MICROSERVICE_UNINSTALLED_SUCCESSFULLY); + } else if (dcaeResponse.getOperationType().equals("uninstall") + && dcaeResponse.getStatus().equals("processing")) { + setState(PROCESSING_MICROSERVICE_UNINSTALLATION); + } else if (dcaeResponse.getOperationType().equals("uninstall") && dcaeResponse.getStatus().equals("failed")) { + setState(MICROSERVICE_UNINSTALLATION_FAILED); + } else { + setState(IN_ERROR); + } + return this.getState(); + } + + /** + * Convert the json response to a DcaeInventoryResponse. + * + * @param responseBody The DCAE response Json paylaod + * @return list of DcaeInventoryResponse + * @throws ParseException In case of issues with the Json parsing + */ + public static List<DcaeInventoryResponse> convertToDcaeInventoryResponse(String responseBody) + throws ParseException { + JSONParser parser = new JSONParser(); + JSONObject jsonObj = (JSONObject) parser.parse(responseBody); + JSONArray itemsArray = (JSONArray) jsonObj.get("items"); + Iterator it = itemsArray.iterator(); + List<DcaeInventoryResponse> inventoryResponseList = new LinkedList<>(); + while (it.hasNext()) { + JSONObject item = (JSONObject) it.next(); + DcaeInventoryResponse response = JsonUtils.GSON.fromJson(item.toString(), DcaeInventoryResponse.class); + inventoryResponseList.add(response); + } + return inventoryResponseList; + } +} diff --git a/src/main/java/org/onap/clamp/loop/components/external/ExternalComponent.java b/src/main/java/org/onap/clamp/loop/components/external/ExternalComponent.java new file mode 100644 index 000000000..2be707fe4 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/components/external/ExternalComponent.java @@ -0,0 +1,59 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.components.external; + +import com.google.gson.annotations.Expose; + +import org.apache.camel.Exchange; + +/** + * Should be abstract but Gson can't instantiate it if it's an abstract. + */ +public class ExternalComponent { + @Expose + private ExternalComponentState componentState; + + public void setState(ExternalComponentState newState) { + this.componentState = newState; + } + + public ExternalComponentState getState() { + return this.componentState; + } + + public String getComponentName() { + return null; + } + + public ExternalComponentState computeState(Exchange camelExchange) { + return new ExternalComponentState("INIT", "no desc", 0); + } + + public ExternalComponent(ExternalComponentState initialState) { + setState(initialState); + } + + public ExternalComponent() { + } +} diff --git a/src/main/java/org/onap/clamp/loop/components/external/ExternalComponentState.java b/src/main/java/org/onap/clamp/loop/components/external/ExternalComponentState.java new file mode 100644 index 000000000..a57234af0 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/components/external/ExternalComponentState.java @@ -0,0 +1,128 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.components.external; + +import com.google.gson.annotations.Expose; + +/** + * This is a transient state reflecting the deployment status of a component. It + * can be Policy, DCAE, or whatever... This is object is generic. Clamp is now + * stateless, so it triggers the different components at runtime, the status per + * component is stored here. The state level is used to re-compute the global + * state when multiple sub states are required for that computation (generally + * provided sequentially to the method computeState from the camel routes. + * + */ +public class ExternalComponentState implements Comparable<ExternalComponentState> { + @Expose + private String stateName; + @Expose + private String description; + private int stateLevel; + + /** + * Constructor taking stateName, description and its level. + * + * @param stateName The stateName in string + * @param description The description in string + * @param level The level, higher value has higher priority and can't be + * down-graded + */ + public ExternalComponentState(String stateName, String description, int level) { + this.stateName = stateName; + this.description = description; + this.stateLevel = level; + } + + public ExternalComponentState(String stateName, String description) { + this(stateName, description, 0); + } + + public ExternalComponentState() { + } + + public String getStateName() { + return stateName; + } + + public String getDescription() { + return description; + } + + @Override + public String toString() { + return stateName; + } + + public int getLevel() { + return stateLevel; + } + + public void setLevel(int priority) { + this.stateLevel = priority; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((stateName == null) ? 0 : stateName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ExternalComponentState other = (ExternalComponentState) obj; + if (stateName == null) { + if (other.stateName != null) { + return false; + } + } else if (!stateName.equals(other.stateName)) { + return false; + } + return true; + } + + /** + * This method compares this object by using the level of them. + * + * @param stateToCompare The state to compare to the current object + * @return If the one given in input has a higher level than the current object + * it returns -1, 1 otherwise and 0 if equals. + */ + @Override + public int compareTo(ExternalComponentState stateToCompare) { + return Integer.compare(this.getLevel(), stateToCompare.getLevel()); + } + +} diff --git a/src/main/java/org/onap/clamp/loop/components/external/PolicyComponent.java b/src/main/java/org/onap/clamp/loop/components/external/PolicyComponent.java new file mode 100644 index 000000000..4ea5b7118 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/components/external/PolicyComponent.java @@ -0,0 +1,195 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.components.external; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.persistence.Transient; +import org.apache.camel.Exchange; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.policy.microservice.MicroServicePolicy; +import org.onap.clamp.policy.operational.OperationalPolicy; + +public class PolicyComponent extends ExternalComponent { + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyComponent.class); + + public static final ExternalComponentState IN_ERROR = new ExternalComponentState("IN_ERROR", + "There was an error during the sending to policy, the policy engine may be corrupted or inconsistent", 100); + public static final ExternalComponentState NOT_SENT = new ExternalComponentState("NOT_SENT", + "The policies defined have NOT yet been created on the policy engine", 90); + public static final ExternalComponentState SENT = new ExternalComponentState("SENT", + "The policies defined have been created but NOT deployed on the policy engine", 50); + public static final ExternalComponentState SENT_AND_DEPLOYED = new ExternalComponentState("SENT_AND_DEPLOYED", + "The policies defined have been created and deployed on the policy engine", 10); + public static final ExternalComponentState UNKNOWN = new ExternalComponentState("UNKNOWN", + "The current status is not clear. Need to refresh the status to get the current status.", 0); + + /** + * Default constructor. + */ + public PolicyComponent() { + /* + * We assume it's good by default as we will receive the state for each policy + * on by one, each time we increase the level we can't decrease it anymore. + * That's why it starts with the lowest one SENT_AND_DEPLOYED. + */ + super(UNKNOWN); + } + + @Override + public String getComponentName() { + return "POLICY"; + } + + /** + * Generates the Json that must be sent to policy to add all policies to Active + * PDP group. + * @param loop the loop object + * @param action POST (to add policy to group) or DELETE (to delete policy from group) + * @return The json, payload to send + */ + public static String createPoliciesPayloadPdpGroup(Loop loop, String action) { + Map<String, Map<String, List<JsonObject>>> pdpGroupMap = new HashMap<>(); + for (OperationalPolicy opPolicy : loop.getOperationalPolicies()) { + updatePdpGroupMap(opPolicy.getPdpGroup(), opPolicy.getPdpSubgroup(), + opPolicy.getName(), + "1.0.0", pdpGroupMap); + } + + for (MicroServicePolicy msPolicy : loop.getMicroServicePolicies()) { + updatePdpGroupMap(msPolicy.getPdpGroup(), msPolicy.getPdpSubgroup(), + msPolicy.getName(), + "1.0.0", pdpGroupMap); + } + + String payload = new GsonBuilder().setPrettyPrinting().create() + .toJson(generateActivatePdpGroupPayload(pdpGroupMap, action)); + logger.info("PdpGroup policy payload: " + payload); + return payload; + } + + private static void updatePdpGroupMap(String pdpGroup, + String pdpSubGroup, + String policyName, + String policyVersion, + Map<String, Map<String, + List<JsonObject>>> pdpGroupMap) { + JsonObject policyJson = new JsonObject(); + policyJson.addProperty("name", policyName); + policyJson.addProperty("version", policyVersion); + Map<String, List<JsonObject>> pdpSubGroupMap; + List<JsonObject> policyList; + if (pdpGroupMap.get(pdpGroup) == null) { + pdpSubGroupMap = new HashMap<>(); + policyList = new LinkedList<>(); + } + else { + pdpSubGroupMap = pdpGroupMap.get(pdpGroup); + if (pdpSubGroupMap.get(pdpSubGroup) == null) { + policyList = new LinkedList<>(); + } + else { + policyList = (List<JsonObject>) pdpSubGroupMap.get(pdpSubGroup); + } + } + policyList.add(policyJson); + pdpSubGroupMap.put(pdpSubGroup, policyList); + pdpGroupMap.put(pdpGroup, pdpSubGroupMap); + } + + private static JsonObject generateActivatePdpGroupPayload( + Map<String, Map<String, List<JsonObject>>> pdpGroupMap, String action) { + JsonArray payloadArray = new JsonArray(); + for (Entry<String, Map<String, List<JsonObject>>> pdpGroupInfo : pdpGroupMap.entrySet()) { + JsonObject pdpGroupNode = new JsonObject(); + JsonArray subPdpArray = new JsonArray(); + pdpGroupNode.addProperty("name", pdpGroupInfo.getKey()); + pdpGroupNode.add("deploymentSubgroups", subPdpArray); + + for (Entry<String, List<JsonObject>> pdpSubGroupInfo : pdpGroupInfo.getValue().entrySet()) { + JsonObject pdpSubGroupNode = new JsonObject(); + subPdpArray.add(pdpSubGroupNode); + pdpSubGroupNode.addProperty("pdpType", pdpSubGroupInfo.getKey()); + pdpSubGroupNode.addProperty("action", action); + + JsonArray policyArray = new JsonArray(); + pdpSubGroupNode.add("policies", policyArray); + + for (JsonObject policy : pdpSubGroupInfo.getValue()) { + policyArray.add(policy); + } + } + payloadArray.add(pdpGroupNode); + } + JsonObject jsonObject = new JsonObject(); + jsonObject.add("groups", payloadArray); + return jsonObject; + } + + private static ExternalComponentState findNewState(boolean found, boolean deployed) { + + ExternalComponentState newState = NOT_SENT; + if (found && deployed) { + newState = SENT_AND_DEPLOYED; + } + else if (found) { + newState = SENT; + } + else if (deployed) { + newState = IN_ERROR; + } + return newState; + } + + private static ExternalComponentState mergeStates(ExternalComponentState oldState, + ExternalComponentState newState) { + return (oldState.compareTo(newState) < 0) ? newState : oldState; + } + + /** + * This is a method that expect the results of the queries getPolicy and + * getPolicyDeployed for a unique policy (op, config, etc ...). It + * re-computes the global policy state for each policy results given. Therefore + * this method is called multiple times from the camel route and must be reset + * for a new global policy state retrieval. The state to compute the global + * policy state is stored in this class. + */ + @Override + public ExternalComponentState computeState(Exchange camelExchange) { + this.setState(mergeStates(this.getState(), + findNewState((boolean) camelExchange.getIn().getExchange().getProperty("policyFound"), + (boolean) camelExchange.getIn().getExchange().getProperty("policyDeployed")))); + return this.getState(); + } +} diff --git a/src/main/java/org/onap/clamp/loop/deploy/DcaeDeployParameters.java b/src/main/java/org/onap/clamp/loop/deploy/DcaeDeployParameters.java new file mode 100644 index 000000000..65506a479 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/deploy/DcaeDeployParameters.java @@ -0,0 +1,119 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.deploy; + +import com.google.gson.JsonObject; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.loop.components.external.DcaeComponent; +import org.onap.clamp.policy.microservice.MicroServicePolicy; +import org.yaml.snakeyaml.Yaml; + +/** + * To decode the bluprint input parameters. + */ +public class DcaeDeployParameters { + + private static LinkedHashMap<String, JsonObject> init(Loop loop) { + LinkedHashMap<String, JsonObject> deploymentParamMap = new LinkedHashMap<>(); + Set<MicroServicePolicy> microServiceList = loop.getMicroServicePolicies(); + + for (MicroServicePolicy microService : microServiceList) { + deploymentParamMap.put(microService.getName(), + generateDcaeDeployParameter(microService)); + } + return deploymentParamMap; + } + + private static JsonObject generateDcaeDeployParameter(MicroServicePolicy microService) { + return generateDcaeDeployParameter(microService.getLoopElementModel().getBlueprint(), + microService.getName()); + } + + private static JsonObject generateDcaeDeployParameter(String blueprint, String policyId) { + JsonObject deployJsonBody = new JsonObject(); + Yaml yaml = new Yaml(); + Map<String, Object> inputsNodes = ((Map<String, Object>) ((Map<String, Object>) yaml + .load(blueprint)).get("inputs")); + inputsNodes.entrySet().stream().filter(e -> !e.getKey().contains("policy_id")).forEach(elem -> { + Object defaultValue = ((Map<String, Object>) elem.getValue()).get("default"); + if (defaultValue != null) { + addPropertyToNode(deployJsonBody, elem.getKey(), defaultValue); + } + else { + deployJsonBody.addProperty(elem.getKey(), ""); + } + }); + deployJsonBody.addProperty("policy_id", policyId); + return deployJsonBody; + } + + private static void addPropertyToNode(JsonObject node, String key, Object value) { + if (value instanceof String) { + node.addProperty(key, (String) value); + } + else if (value instanceof Number) { + node.addProperty(key, (Number) value); + } + else if (value instanceof Boolean) { + node.addProperty(key, (Boolean) value); + } + else if (value instanceof Character) { + node.addProperty(key, (Character) value); + } + else { + node.addProperty(key, JsonUtils.GSON.toJson(value)); + } + } + + /** + * Convert the object in Json. + * + * @return The deploymentParameters in Json + */ + public static JsonObject getDcaeDeploymentParametersInJson(Loop loop) { + JsonObject globalProperties = new JsonObject(); + JsonObject deployParamJson = new JsonObject(); + if (loop.getLoopTemplate().getUniqueBlueprint()) { + // Normally the unique blueprint could contain multiple microservices but then we can't guess + // the policy id params that will be used, so here we expect only one by default. + deployParamJson.add(DcaeComponent.UNIQUE_BLUEPRINT_PARAMETERS, + generateDcaeDeployParameter(loop.getLoopTemplate().getBlueprint(), + ((MicroServicePolicy) loop.getMicroServicePolicies().toArray()[0]).getName())); + + } + else { + LinkedHashMap<String, JsonObject> deploymentParamMap = init(loop); + for (Map.Entry<String, JsonObject> mapElement : deploymentParamMap.entrySet()) { + deployParamJson.add(mapElement.getKey(), mapElement.getValue()); + } + } + globalProperties.add("dcaeDeployParameters", deployParamJson); + return globalProperties; + } + +} diff --git a/src/main/java/org/onap/clamp/loop/log/LogType.java b/src/main/java/org/onap/clamp/loop/log/LogType.java new file mode 100644 index 000000000..13d9dccf8 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/log/LogType.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.log; + +public enum LogType { + INFO, WARNING, ERROR; +} diff --git a/src/main/java/org/onap/clamp/loop/log/LoopLog.java b/src/main/java/org/onap/clamp/loop/log/LoopLog.java new file mode 100644 index 000000000..e49598879 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/log/LoopLog.java @@ -0,0 +1,196 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.log; + +import com.google.gson.annotations.Expose; + +import java.io.Serializable; +import java.time.Instant; +import java.time.temporal.ChronoUnit; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.onap.clamp.loop.Loop; + +/** + * This class holds the logs created by the Clamp Backend. The Instant is always + * rounded to the nearest second as the nano seconds can't be stored in the + * database. The logs can be therefore exposed to the UI or the client doing + * some GET Loop on the backend. + * + */ +@Entity +@Table(name = "loop_logs") +public class LoopLog implements Serializable, Comparable<LoopLog> { + /** + * The serial version ID. + */ + private static final long serialVersionUID = 1988276670074437631L; + + @Expose + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + @Expose + @Column(name = "log_type", nullable = false) + @Enumerated(EnumType.STRING) + private LogType logType; + + @Expose + @Column(name = "log_component", nullable = false) + private String logComponent; + + @Expose + @Column(name = "message", columnDefinition = "MEDIUMTEXT", nullable = false) + private String message; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "loop_id", nullable = false) + private Loop loop; + + @Expose + @Column(name = "log_instant", nullable = false) + private Instant logInstant = Instant.now().truncatedTo(ChronoUnit.SECONDS); + + public LoopLog() { + } + + /** + * Constructor For LoopLog taking message and logtype, logComponent and loop + * reference. + * + * @param message The message as string + * @param logType Type like INFO, WARN, DEBUG + * @param logComponent A String with DCAE, POLICY, CLAMP ,etc... + * @param loop The loop object that this log is about + */ + public LoopLog(String message, LogType logType, String logComponent, Loop loop) { + this.message = message; + this.logType = logType; + this.loop = loop; + this.logComponent = logComponent; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public LogType getLogType() { + return logType; + } + + public void setLogType(LogType logType) { + this.logType = logType; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Loop getLoop() { + return loop; + } + + public void setLoop(Loop loop) { + this.loop = loop; + } + + public Instant getLogInstant() { + return logInstant; + } + + public void setLogInstant(Instant logInstant) { + this.logInstant = logInstant.truncatedTo(ChronoUnit.SECONDS); + } + + public String getLogComponent() { + return logComponent; + } + + public void setLogComponent(String logComponent) { + this.logComponent = logComponent; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((id == null) ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopLog other = (LoopLog) obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + return true; + } + + @Override + public int compareTo(LoopLog arg0) { + // Reverse it, so that by default we have the latest + if (getId() == null) { + return 1; + } + if (arg0.getId() == null) { + return -1; + } + return arg0.getId().compareTo(this.getId()); + } + +} diff --git a/src/main/java/org/onap/clamp/loop/log/LoopLogRepository.java b/src/main/java/org/onap/clamp/loop/log/LoopLogRepository.java new file mode 100644 index 000000000..0b3c34ec0 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/log/LoopLogRepository.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.log; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopLogRepository extends JpaRepository<LoopLog, Long> { + +} diff --git a/src/main/java/org/onap/clamp/loop/log/LoopLogService.java b/src/main/java/org/onap/clamp/loop/log/LoopLogService.java new file mode 100644 index 000000000..d02d0b278 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/log/LoopLogService.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.loop.log; + +import org.onap.clamp.loop.Loop; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class LoopLogService { + + private final LoopLogRepository repository; + + @Autowired + public LoopLogService(LoopLogRepository repository) { + this.repository = repository; + } + + public void addLog(String message, String logType, Loop loop) { + this.addLogForComponent(message, logType, "CLAMP", loop); + } + + public void addLogForComponent(String message, String logType, String component, Loop loop) { + loop.addLog(repository.save(new LoopLog(message, LogType.valueOf(logType), component, loop))); + } + + public boolean isExisting(Long logId) { + return repository.existsById(logId); + } +} diff --git a/src/main/java/org/onap/clamp/loop/service/CsarServiceInstaller.java b/src/main/java/org/onap/clamp/loop/service/CsarServiceInstaller.java new file mode 100644 index 000000000..c43f2cb6d --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/service/CsarServiceInstaller.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.onap.clamp.loop.service; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import java.util.Map.Entry; +import org.onap.clamp.clds.exception.sdc.controller.SdcArtifactInstallerException; +import org.onap.clamp.clds.sdc.controller.installer.CsarHandler; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.sdc.tosca.parser.api.IEntityDetails; +import org.onap.sdc.tosca.parser.elements.queries.EntityQuery; +import org.onap.sdc.tosca.parser.elements.queries.TopologyTemplateQuery; +import org.onap.sdc.tosca.parser.enums.EntityTemplateType; +import org.onap.sdc.tosca.parser.enums.SdcTypes; +import org.onap.sdc.toscaparser.api.NodeTemplate; +import org.onap.sdc.toscaparser.api.Property; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Qualifier("csarInstaller") +public class CsarServiceInstaller { + private static final EELFLogger logger = EELFManager.getInstance().getLogger(CsarServiceInstaller.class); + + @Autowired + ServicesRepository serviceRepository; + + /** + * Install the Service from the csar. + * + * @param csar The Csar Handler + * @return The service object + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public Service installTheService(CsarHandler csar) { + logger.info("Start to install the Service from csar"); + JsonObject serviceDetails = JsonUtils.GSON.fromJson( + JsonUtils.GSON.toJson(csar.getSdcCsarHelper().getServiceMetadataAllProperties()), JsonObject.class); + + // Add properties details for each type, VfModule, VF, VFC, .... + JsonObject resourcesProp = createServicePropertiesByType(csar); + resourcesProp.add("VFModule", createVfModuleProperties(csar)); + + Service modelService = new Service(serviceDetails, resourcesProp, + csar.getSdcNotification().getServiceVersion()); + + serviceRepository.save(modelService); + logger.info("Successfully installed the Service"); + return modelService; + } + + private JsonObject createServicePropertiesByType(CsarHandler csar) { + JsonObject resourcesProp = new JsonObject(); + // Iterate on all types defined in the tosca lib + for (SdcTypes type : SdcTypes.values()) { + JsonObject resourcesPropByType = new JsonObject(); + // For each type, get the metadata of each nodetemplate + for (NodeTemplate nodeTemplate : csar.getSdcCsarHelper().getServiceNodeTemplateBySdcType(type)) { + resourcesPropByType.add(nodeTemplate.getName(), + JsonUtils.GSON.toJsonTree(nodeTemplate.getMetaData().getAllProperties())); + } + resourcesProp.add(type.getValue(), resourcesPropByType); + } + return resourcesProp; + } + + private static JsonObject createVfModuleProperties(CsarHandler csar) { + JsonObject vfModuleProps = new JsonObject(); + // Loop on all Groups defined in the service (VFModule entries type: + // org.openecomp.groups.VfModule) + for (IEntityDetails entity : csar.getSdcCsarHelper().getEntity( + EntityQuery.newBuilder(EntityTemplateType.GROUP).build(), + TopologyTemplateQuery.newBuilder(SdcTypes.SERVICE).build(), false)) { + // Get all metadata info + JsonObject allVfProps = (JsonObject) JsonUtils.GSON.toJsonTree(entity.getMetadata().getAllProperties()); + vfModuleProps.add(entity.getMetadata().getAllProperties().get("vfModuleModelName"), allVfProps); + // now append the properties section so that we can also have isBase, + // volume_group, etc ... fields under the VFmodule name + for (Entry<String, Property> additionalProp : entity.getProperties().entrySet()) { + allVfProps.add(additionalProp.getValue().getName(), + JsonUtils.GSON.toJsonTree(additionalProp.getValue().getValue())); + } + } + return vfModuleProps; + } + + /** + * Verify whether Service in Csar is deployed. + * + * @param csar The Csar Handler + * @return The flag indicating whether Service is deployed + * @throws SdcArtifactInstallerException The SdcArtifactInstallerException + */ + public boolean isServiceAlreadyDeployed(CsarHandler csar) throws SdcArtifactInstallerException { + boolean alreadyInstalled = true; + JsonObject serviceDetails = JsonUtils.GSON.fromJson( + JsonUtils.GSON.toJson(csar.getSdcCsarHelper().getServiceMetadataAllProperties()), JsonObject.class); + alreadyInstalled = serviceRepository.existsById(serviceDetails.get("UUID").getAsString()); + + return alreadyInstalled; + } +} diff --git a/src/main/java/org/onap/clamp/loop/service/Service.java b/src/main/java/org/onap/clamp/loop/service/Service.java new file mode 100644 index 000000000..338032a16 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/service/Service.java @@ -0,0 +1,168 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.service; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.dao.model.jsontype.StringJsonUserType; + +@Entity +@Table(name = "services") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class Service implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = 1331119060272760758L; + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(Service.class); + + @Id + @Column(name = "service_uuid", unique = true) + private String serviceUuid; + + @Column(nullable = false, name = "name") + private String name; + + @Column(name = "version") + private String version; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "service_details") + private JsonObject serviceDetails; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "resource_details") + private JsonObject resourceDetails; + + /** + * Default constructor for serialization. + */ + public Service() { + } + + /** + * Constructor with string. + */ + public Service(String serviceDetails, String resourceDetails) { + JsonObject serviceDetailsJson = JsonUtils.GSON.fromJson(serviceDetails, JsonObject.class); + this.name = serviceDetailsJson.get("name").getAsString(); + this.serviceUuid = serviceDetailsJson.get("UUID").getAsString(); + this.serviceDetails = serviceDetailsJson; + this.resourceDetails = JsonUtils.GSON.fromJson(resourceDetails, JsonObject.class); + } + + /** + * Constructor with Json Object. + */ + public Service(JsonObject serviceDetails, JsonObject resourceDetails, String version) { + this.name = serviceDetails.get("name").getAsString(); + this.serviceUuid = serviceDetails.get("UUID").getAsString(); + this.serviceDetails = serviceDetails; + this.resourceDetails = resourceDetails; + this.version = version; + } + + public String getServiceUuid() { + return serviceUuid; + } + + public JsonObject getServiceDetails() { + return serviceDetails; + } + + public JsonObject getResourceDetails() { + return resourceDetails; + } + + public JsonObject getResourceByType(String type) { + return (JsonObject) resourceDetails.get(type); + } + + /** + * Name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Version getter. + * + * @return the version + */ + public String getVersion() { + return version; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((serviceUuid == null) ? 0 : serviceUuid.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Service other = (Service) obj; + if (serviceUuid == null) { + if (other.serviceUuid != null) { + return false; + } + } + else if (!serviceUuid.equals(other.serviceUuid)) { + return false; + } + return true; + } + +} diff --git a/src/main/java/org/onap/clamp/loop/service/ServicesRepository.java b/src/main/java/org/onap/clamp/loop/service/ServicesRepository.java new file mode 100644 index 000000000..fe5ba8ed0 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/service/ServicesRepository.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.loop.service; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ServicesRepository extends JpaRepository<Service, String> { +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopElementModel.java b/src/main/java/org/onap/clamp/loop/template/LoopElementModel.java new file mode 100644 index 000000000..70cdbe233 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopElementModel.java @@ -0,0 +1,298 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2018 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.onap.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import org.hibernate.annotations.SortNatural; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.loop.common.AuditEntity; +import org.onap.clamp.policy.Policy; +import org.onap.clamp.policy.microservice.MicroServicePolicy; +import org.onap.clamp.policy.operational.OperationalPolicy; + +/** + * This class represents a micro service/operational/... model for a loop template. + * So it's an element in the flow (a box shown in the loop). + */ + +@Entity +@Table(name = "loop_element_models") +public class LoopElementModel extends AuditEntity implements Serializable { + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701376645L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dcae_blueprint_id") + private String dcaeBlueprintId; + + /** + * Here we store the blueprint coming from DCAE, it can be null if this is not a micro service model. + */ + @Column(columnDefinition = "MEDIUMTEXT", name = "blueprint_yaml") + private String blueprint; + + public static final String MICRO_SERVICE_TYPE = "MICRO_SERVICE_TYPE"; + public static final String OPERATIONAL_POLICY_TYPE = "OPERATIONAL_POLICY_TYPE"; + /** + * The type of element. + */ + @Expose + @Column(nullable = false, name = "loop_element_type") + private String loopElementType; + + /** + * This variable is used to display the micro-service name in the SVG. + */ + @Expose + @Column(name = "short_name") + private String shortName; + + /** + * This variable is used to store the type mentioned in the micro-service + * blueprint. + */ + @Expose + @ManyToMany( + fetch = FetchType.EAGER, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) + @JoinTable( + name = "loopelementmodels_to_policymodels", + joinColumns = @JoinColumn(name = "loop_element_name", referencedColumnName = "name"), + inverseJoinColumns = { + @JoinColumn(name = "policy_model_type", referencedColumnName = "policy_model_type"), + @JoinColumn(name = "policy_model_version", referencedColumnName = "version")}) + @SortNatural + private SortedSet<PolicyModel> policyModels = new TreeSet<>(); + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "loopElementModel", orphanRemoval = true) + private Set<LoopTemplateLoopElementModel> usedByLoopTemplates = new HashSet<>(); + + /** + * policyModels getter. + * + * @return the policyModel + */ + public SortedSet<PolicyModel> getPolicyModels() { + return policyModels; + } + + /** + * Method to add a new policyModel to the list. + * + * @param policyModel The policy model + */ + public void addPolicyModel(PolicyModel policyModel) { + policyModels.add(policyModel); + policyModel.getUsedByElementModels().add(this); + } + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * blueprint getter. + * + * @return the blueprint + */ + public String getBlueprint() { + return blueprint; + } + + /** + * blueprint setter. + * + * @param blueprint the blueprint to set + */ + public void setBlueprint(String blueprint) { + this.blueprint = blueprint; + } + + /** + * dcaeBlueprintId getter. + * + * @return the dcaeBlueprintId + */ + public String getDcaeBlueprintId() { + return dcaeBlueprintId; + } + + /** + * dcaeBlueprintId setter. + * + * @param dcaeBlueprintId the dcaeBlueprintId to set + */ + public void setDcaeBlueprintId(String dcaeBlueprintId) { + this.dcaeBlueprintId = dcaeBlueprintId; + } + + /** + * loopElementType getter. + * + * @return the loopElementType + */ + public String getLoopElementType() { + return loopElementType; + } + + /** + * loopElementType setter. + * + * @param loopElementType the loopElementType to set + */ + public void setLoopElementType(String loopElementType) { + this.loopElementType = loopElementType; + } + + /** + * shortName getter. + * + * @return the shortName + */ + public String getShortName() { + return shortName; + } + + /** + * @param shortName the shortName to set. + */ + public void setShortName(String shortName) { + this.shortName = shortName; + } + + /** + * usedByLoopTemplates getter. + * + * @return the usedByLoopTemplates + */ + public Set<LoopTemplateLoopElementModel> getUsedByLoopTemplates() { + return usedByLoopTemplates; + } + + /** + * Default constructor for serialization. + */ + public LoopElementModel() { + } + + /** + * Constructor. + * + * @param name The name id + * @param loopElementType The type of loop element + * @param blueprint The blueprint defined for dcae that contains the + * policy type to use + */ + public LoopElementModel(String name, String loopElementType, String blueprint) { + this.name = name; + this.loopElementType = loopElementType; + this.blueprint = blueprint; + } + + /** + * Create a policy instance from the current loop element model. + * + * @return A Policy object. + */ + public Policy createPolicyInstance(Loop loop, ToscaConverterWithDictionarySupport toscaConverter) { + if (LoopElementModel.MICRO_SERVICE_TYPE.equals(this.getLoopElementType())) { + return new MicroServicePolicy(loop, loop.getModelService(), this, toscaConverter); + } + else if (LoopElementModel.OPERATIONAL_POLICY_TYPE.equals(this.getLoopElementType())) { + return new OperationalPolicy(loop, loop.getModelService(), this, toscaConverter); + } + else { + return null; + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopElementModel other = (LoopElementModel) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } + else if (!name.equals(other.name)) { + return false; + } + return true; + } + +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopElementModelsRepository.java b/src/main/java/org/onap/clamp/loop/template/LoopElementModelsRepository.java new file mode 100644 index 000000000..27b82189c --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopElementModelsRepository.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopElementModelsRepository extends JpaRepository<LoopElementModel, String> { +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopTemplate.java b/src/main/java/org/onap/clamp/loop/template/LoopTemplate.java new file mode 100644 index 000000000..6f896f3d4 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopTemplate.java @@ -0,0 +1,341 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import org.hibernate.annotations.SortNatural; +import org.onap.clamp.loop.common.AuditEntity; +import org.onap.clamp.loop.service.Service; + +@Entity +@Table(name = "loop_templates") +public class LoopTemplate extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388642L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dcae_blueprint_id") + private String dcaeBlueprintId; + + /** + * This field is used when we have a blueprint defining all microservices. The + * other option would be to have independent blueprint for each microservices. + * In that case they are stored in each MicroServiceModel + */ + @Column(columnDefinition = "MEDIUMTEXT", name = "blueprint_yaml") + private String blueprint; + + @Expose + @OneToMany( + cascade = CascadeType.ALL, + fetch = FetchType.EAGER, + mappedBy = "loopTemplate", + orphanRemoval = true) + @SortNatural + private SortedSet<LoopTemplateLoopElementModel> loopElementModelsUsed = new TreeSet<>(); + + @Expose + @ManyToOne( + fetch = FetchType.EAGER, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}) + @JoinColumn(name = "service_uuid") + private Service modelService; + + @Expose + @Column(name = "maximum_instances_allowed") + private Integer maximumInstancesAllowed; + + @Expose + @Column(name = "unique_blueprint", columnDefinition = "boolean default false") + private boolean uniqueBlueprint; + + /** + * Type of Loop allowed to be created. + */ + @Expose + @Column(name = "allowed_loop_type") + @Convert(converter = LoopTypeConvertor.class) + private LoopType allowedLoopType = LoopType.CLOSED; + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * blueprint getter. + * + * @return the blueprint + */ + public String getBlueprint() { + return blueprint; + } + + /** + * dcaeBlueprintId getter. + * + * @return the dcaeBlueprintId + */ + public String getDcaeBlueprintId() { + return dcaeBlueprintId; + } + + /** + * dcaeBlueprintId setter. + * + * @param dcaeBlueprintId the dcaeBlueprintId to set + */ + public void setDcaeBlueprintId(String dcaeBlueprintId) { + this.dcaeBlueprintId = dcaeBlueprintId; + } + + /** + * blueprint setter. + * + * @param blueprint the blueprint to set + */ + public void setBlueprint(String blueprint) { + this.blueprint = blueprint; + if (blueprint == null) { + this.uniqueBlueprint = false; + } else { + this.uniqueBlueprint = true; + } + } + + /** + * loopElementModelsUsed getter. + * + * @return the loopElementModelsUsed + */ + public SortedSet<LoopTemplateLoopElementModel> getLoopElementModelsUsed() { + return loopElementModelsUsed; + } + + /** + * maximumInstancesAllowed getter. + * + * @return the maximumInstancesAllowed + */ + public Integer getMaximumInstancesAllowed() { + return maximumInstancesAllowed; + } + + /** + * maximumInstancesAllowed setter. + * + * @param maximumInstancesAllowed the maximumInstancesAllowed to set + */ + public void setMaximumInstancesAllowed(Integer maximumInstancesAllowed) { + this.maximumInstancesAllowed = maximumInstancesAllowed; + } + + /** + * allowedLoopType getter. + * + * @return the allowedLoopType Type of Loop allowed to be created + */ + public LoopType getAllowedLoopType() { + return allowedLoopType; + } + + /** + * allowedLoopType setter. + * + * @param allowedLoopType the allowedLoopType to set + */ + public void setAllowedLoopType(LoopType allowedLoopType) { + this.allowedLoopType = allowedLoopType; + } + + /** + * Add list of loopElements to the current template, each loopElementModel is + * added at the end of the list so the flowOrder is computed automatically. + * + * @param loopElementModels The loopElementModel set to add + */ + public void addLoopElementModels(Set<LoopElementModel> loopElementModels) { + for (LoopElementModel loopElementModel : loopElementModels) { + addLoopElementModel(loopElementModel); + } + } + + /** + * Add a loopElement to the current template, the loopElementModel is added at + * the end of the list so the flowOrder is computed automatically. + * + * @param loopElementModel The loopElementModel to add + */ + public void addLoopElementModel(LoopElementModel loopElementModel) { + this.addLoopElementModel(loopElementModel,this.loopElementModelsUsed.size()); + } + + /** + * Add a loopElement model to the current template, the flow order must be + * specified manually. + * + * @param loopElementModel The loopElementModel to add + * @param listPosition The position in the flow + */ + public void addLoopElementModel(LoopElementModel loopElementModel, Integer listPosition) { + LoopTemplateLoopElementModel jointEntry = + new LoopTemplateLoopElementModel(this, loopElementModel, listPosition); + this.loopElementModelsUsed.add(jointEntry); + loopElementModel.getUsedByLoopTemplates().add(jointEntry); + } + + /** + * modelService getter. + * + * @return the modelService + */ + public Service getModelService() { + return modelService; + } + + /** + * modelService setter. + * + * @param modelService the modelService to set + */ + public void setModelService(Service modelService) { + this.modelService = modelService; + } + + /** + * uniqueBlueprint getter. + * + * @return the uniqueBlueprint + */ + public boolean getUniqueBlueprint() { + return uniqueBlueprint; + } + + /** + * Default constructor for serialization. + */ + public LoopTemplate() { + + } + + /** + * Constructor. + * + * @param name The loop template name id + * @param blueprint The blueprint containing all microservices (legacy + * case) + * @param maxInstancesAllowed The maximum number of instances that can be + * created from that template + * @param service The service associated to that loop template + */ + public LoopTemplate(String name, String blueprint, Integer maxInstancesAllowed, Service service) { + this.name = name; + this.setBlueprint(blueprint); + + this.maximumInstancesAllowed = maxInstancesAllowed; + this.modelService = service; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopTemplate other = (LoopTemplate) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + + /** + * Generate the loop template name. + * + * @param serviceName The service name + * @param serviceVersion The service version + * @param resourceName The resource name + * @param blueprintFileName The blueprint file name + * @return The generated loop template name + */ + public static String generateLoopTemplateName(String serviceName, String serviceVersion, + String resourceName, String blueprintFileName) { + StringBuilder buffer = new StringBuilder("LOOP_TEMPLATE_").append(serviceName).append("_v") + .append(serviceVersion).append("_").append(resourceName).append("_") + .append(blueprintFileName.replaceAll(".yaml", "")); + return buffer.toString().replace('.', '_').replaceAll(" ", ""); + } +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopTemplateLoopElementModel.java b/src/main/java/org/onap/clamp/loop/template/LoopTemplateLoopElementModel.java new file mode 100644 index 000000000..aca16bc04 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopTemplateLoopElementModel.java @@ -0,0 +1,194 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import com.google.gson.annotations.Expose; + +import java.io.Serializable; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import javax.persistence.Table; + +@Entity +@Table(name = "looptemplates_to_loopelementmodels") +public class LoopTemplateLoopElementModel implements Serializable, Comparable<LoopTemplateLoopElementModel> { + + /** + * Serial ID. + */ + private static final long serialVersionUID = 5924989899078094245L; + + @EmbeddedId + private LoopTemplateLoopElementModelId loopTemplateLoopElementModelId; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("loopTemplateName") + @JoinColumn(name = "loop_template_name") + private LoopTemplate loopTemplate; + + @Expose + @ManyToOne(fetch = FetchType.EAGER, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }) + @MapsId("loopElementModelName") + @JoinColumn(name = "loop_element_model_name") + private LoopElementModel loopElementModel; + + @Expose + @Column(nullable = false, name = "flow_order") + private Integer flowOrder; + + /** + * Default constructor for serialization. + */ + public LoopTemplateLoopElementModel() { + + } + + /** + * Constructor. + * + * @param loopTemplate The loop template object + * @param loopElementModel The loopElementModel object + * @param flowOrder The position of the micro service in the flow + */ + public LoopTemplateLoopElementModel(LoopTemplate loopTemplate, LoopElementModel loopElementModel, + Integer flowOrder) { + this.loopTemplate = loopTemplate; + this.loopElementModel = loopElementModel; + this.flowOrder = flowOrder; + this.loopTemplateLoopElementModelId = new LoopTemplateLoopElementModelId(loopTemplate.getName(), + loopElementModel.getName()); + } + + /** + * loopTemplate getter. + * + * @return the loopTemplate + */ + public LoopTemplate getLoopTemplate() { + return loopTemplate; + } + + /** + * loopTemplate setter. + * + * @param loopTemplate the loopTemplate to set + */ + public void setLoopTemplate(LoopTemplate loopTemplate) { + this.loopTemplate = loopTemplate; + } + + /** + * loopElementModel getter. + * + * @return the loopElementModel + */ + public LoopElementModel getLoopElementModel() { + return loopElementModel; + } + + /** + * loopElementModel setter. + * + * @param loopElementModel the loopElementModel to set + */ + public void setLoopElementModel(LoopElementModel loopElementModel) { + this.loopElementModel = loopElementModel; + } + + /** + * flowOrder getter. + * + * @return the flowOrder + */ + public Integer getFlowOrder() { + return flowOrder; + } + + /** + * flowOrder setter. + * + * @param flowOrder the flowOrder to set + */ + public void setFlowOrder(Integer flowOrder) { + this.flowOrder = flowOrder; + } + + @Override + public int compareTo(LoopTemplateLoopElementModel arg0) { + // Reverse it, so that by default we have the latest + if (getFlowOrder() == null) { + return 1; + } + if (arg0.getFlowOrder() == null) { + return -1; + } + return arg0.getFlowOrder().compareTo(this.getFlowOrder()); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((loopTemplate == null) ? 0 : loopTemplate.hashCode()); + result = prime * result + ((loopElementModel == null) ? 0 : loopElementModel.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LoopTemplateLoopElementModel other = (LoopTemplateLoopElementModel) obj; + if (loopTemplate == null) { + if (other.loopTemplate != null) { + return false; + } + } else if (!loopTemplate.equals(other.loopTemplate)) { + return false; + } + if (loopElementModel == null) { + if (other.loopElementModel != null) { + return false; + } + } else if (!loopElementModel.equals(other.loopElementModel)) { + return false; + } + return true; + } + +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopTemplateLoopElementModelId.java b/src/main/java/org/onap/clamp/loop/template/LoopTemplateLoopElementModelId.java new file mode 100644 index 000000000..cac5f088a --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopTemplateLoopElementModelId.java @@ -0,0 +1,100 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import javax.persistence.Column; +import javax.persistence.Embeddable; + +@Embeddable +public class LoopTemplateLoopElementModelId implements Serializable { + + /** + * Serial ID. + */ + private static final long serialVersionUID = 4089888115504914773L; + + @Expose + @Column(name = "loop_template_name") + private String loopTemplateName; + + @Expose + @Column(name = "loop_element_model_name") + private String loopElementModelName; + + /** + * Default constructor for serialization. + */ + public LoopTemplateLoopElementModelId() { + + } + + /** + * Constructor. + * + * @param loopTemplateName The loop template name id + * @param microServiceModelName THe micro Service name id + */ + public LoopTemplateLoopElementModelId(String loopTemplateName, String microServiceModelName) { + this.loopTemplateName = loopTemplateName; + this.loopElementModelName = microServiceModelName; + } + + /** + * loopTemplateName getter. + * + * @return the loopTemplateName + */ + public String getLoopTemplateName() { + return loopTemplateName; + } + + /** + * loopTemplateName setter. + * + * @param loopTemplateName the loopTemplateName to set + */ + public void setLoopTemplateName(String loopTemplateName) { + this.loopTemplateName = loopTemplateName; + } + + /** + * microServiceModelName getter. + * + * @return the microServiceModelName + */ + public String getLoopElementModelName() { + return loopElementModelName; + } + + /** + * loopElementModelName setter. + * + * @param loopElementModelName the loopElementModelName to set + */ + public void setLoopElementModelName(String loopElementModelName) { + this.loopElementModelName = loopElementModelName; + } +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopTemplatesRepository.java b/src/main/java/org/onap/clamp/loop/template/LoopTemplatesRepository.java new file mode 100644 index 000000000..07f304de7 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopTemplatesRepository.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface LoopTemplatesRepository extends JpaRepository<LoopTemplate, String> { + + @Query("SELECT looptemplate.name FROM LoopTemplate as looptemplate") + List<String> getAllLoopTemplateNames(); +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopTemplatesService.java b/src/main/java/org/onap/clamp/loop/template/LoopTemplatesService.java new file mode 100644 index 000000000..29382137e --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopTemplatesService.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.loop.template; + +import java.util.List; +import org.onap.clamp.clds.sdc.controller.installer.ChainGenerator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class LoopTemplatesService { + + private final LoopTemplatesRepository loopTemplatesRepository; + + @Autowired + ChainGenerator chainGenerator; + + /** + * Constructor. + */ + @Autowired + public LoopTemplatesService(LoopTemplatesRepository loopTemplatesRepository) { + this.loopTemplatesRepository = loopTemplatesRepository; + + } + + public LoopTemplate saveOrUpdateLoopTemplate(LoopTemplate loopTemplate) { + return loopTemplatesRepository.save(loopTemplate); + } + + public List<String> getLoopTemplateNames() { + return loopTemplatesRepository.getAllLoopTemplateNames(); + } + + public List<LoopTemplate> getAllLoopTemplates() { + return loopTemplatesRepository.findAll(); + } + + public LoopTemplate getLoopTemplate(String name) { + return loopTemplatesRepository.findById(name).orElse(null); + } + + public void deleteLoopTemplate(String name) { + loopTemplatesRepository.deleteById(name); + } +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopType.java b/src/main/java/org/onap/clamp/loop/template/LoopType.java new file mode 100644 index 000000000..ccbc62a83 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopType.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.loop.template; + +/** + * Enums for AllowedLoopType in LoopTemplate enity. + * + */ +public enum LoopType { + OPEN("OPEN"), CLOSED("CLOSED"), HYBRID("HYBRID"); + + private String value; + + private LoopType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/org/onap/clamp/loop/template/LoopTypeConvertor.java b/src/main/java/org/onap/clamp/loop/template/LoopTypeConvertor.java new file mode 100644 index 000000000..0b05613cb --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/LoopTypeConvertor.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.loop.template; + +import java.util.stream.Stream; +import javax.persistence.AttributeConverter; + +/** + * Attribute Converter to allow using LoopType Enum values in DB and Java classes. + * + */ +public class LoopTypeConvertor implements AttributeConverter<LoopType, String> { + + @Override + public String convertToDatabaseColumn(LoopType loopType) { + if (loopType == null) { + return null; + } + return loopType.getValue(); + } + + @Override + public LoopType convertToEntityAttribute(String value) { + if (value == null) { + return null; + } + + return Stream.of(LoopType.values()).filter(c -> c.getValue().equals(value)).findFirst() + .orElseThrow(IllegalArgumentException::new); + } +} diff --git a/src/main/java/org/onap/clamp/loop/template/PolicyModel.java b/src/main/java/org/onap/clamp/loop/template/PolicyModel.java new file mode 100644 index 000000000..3f45d0551 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/PolicyModel.java @@ -0,0 +1,282 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.clamp.loop.common.AuditEntity; +import org.onap.clamp.util.SemanticVersioning; + +/** + * This class represents the policy model tosca revision that we can have to a + * specific microservice. + */ +@Entity +@Table(name = "policy_models") +@IdClass(PolicyModelId.class) +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class PolicyModel extends AuditEntity implements Serializable, Comparable<PolicyModel> { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522705701376645L; + + /** + * This variable is used to store the type mentioned in the micro-service + * blueprint. + */ + @Id + @Expose + @Column(nullable = false, name = "policy_model_type") + private String policyModelType; + + /** + * Semantic versioning on policy side. + */ + @Id + @Expose + @Column(name = "version", nullable = false) + private String version; + + @Column(columnDefinition = "MEDIUMTEXT", name = "policy_tosca") + private String policyModelTosca; + + @Expose + @Column(name = "policy_acronym") + private String policyAcronym; + + @ManyToMany(mappedBy = "policyModels", fetch = FetchType.EAGER) + private Set<LoopElementModel> usedByElementModels = new HashSet<>(); + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "policy_pdp_group") + private JsonObject policyPdpGroup; + + /** + * usedByElementModels getter. + * + * @return the usedByElementModels + */ + public Set<LoopElementModel> getUsedByElementModels() { + return usedByElementModels; + } + + /** + * policyPdpGroup getter. + * + * @return the policyPdpGroup + */ + public JsonObject getPolicyPdpGroup() { + return policyPdpGroup; + } + + /** + * policyPdpGroup setter. + * + * @param policyPdpGroup the policyPdpGroup to set + */ + public void setPolicyPdpGroup(JsonObject policyPdpGroup) { + this.policyPdpGroup = policyPdpGroup; + } + + /** + * policyModelTosca getter. + * + * @return the policyModelTosca + */ + public String getPolicyModelTosca() { + return policyModelTosca; + } + + /** + * policyModelTosca setter. + * + * @param policyModelTosca the policyModelTosca to set + */ + public void setPolicyModelTosca(String policyModelTosca) { + this.policyModelTosca = policyModelTosca; + } + + /** + * policyModelType getter. + * + * @return the modelType + */ + public String getPolicyModelType() { + return policyModelType; + } + + /** + * policyModelType setter. + * + * @param modelType the modelType to set + */ + public void setPolicyModelType(String modelType) { + this.policyModelType = modelType; + } + + /** + * version getter. + * + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * version setter. + * + * @param version the version to set + */ + public void setVersion(String version) { + // Try to convert it before + this.version = version; + } + + /** + * policyAcronym getter. + * + * @return the policyAcronym value + */ + public String getPolicyAcronym() { + return policyAcronym; + } + + /** + * policyAcronym setter. + * + * @param policyAcronym The policyAcronym to set + */ + public void setPolicyAcronym(String policyAcronym) { + this.policyAcronym = policyAcronym; + } + + /** + * Default constructor for serialization. + */ + public PolicyModel() { + } + + /** + * Constructor. + * + * @param policyType The policyType (referenced in the blueprint + * @param policyModelTosca The policy tosca model in yaml + * @param version the version like 1.0.0 + * @param policyAcronym Subtype for policy if it exists (could be used by UI) + */ + public PolicyModel(String policyType, String policyModelTosca, String version, + String policyAcronym) { + this.policyModelType = policyType; + this.policyModelTosca = policyModelTosca; + this.version = version; + this.policyAcronym = policyAcronym; + if (this.policyAcronym == null) { + this.policyAcronym = createDefaultPolicyAcronym(policyType); + } + } + + /** + * Constructor with acronym generated by default from policyType. + * + * @param policyType The policyType (referenced in the blueprint + * @param policyModelTosca The policy tosca model in yaml + * @param version the version like 1.0.0 + */ + public PolicyModel(String policyType, String policyModelTosca, String version) { + this(policyType, policyModelTosca, version, null); + } + + public static String createDefaultPolicyAcronym(String policyType) { + String[] policyNameArray = policyType.split("\\."); + return policyNameArray[policyNameArray.length - 1]; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((policyModelType == null) ? 0 : policyModelType.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PolicyModel other = (PolicyModel) obj; + if (policyModelType == null) { + if (other.policyModelType != null) { + return false; + } + } else if (!policyModelType.equals(other.policyModelType)) { + return false; + } + if (version == null) { + if (other.version != null) { + return false; + } + } else if (!version.equals(other.version)) { + return false; + } + return true; + } + + @Override + public int compareTo(PolicyModel arg0) { + + if (this.getPolicyModelType().equals(arg0.getPolicyModelType())) { + // Reverse it, so that by default we have the latest in they are same model type + return SemanticVersioning.compare(arg0.getVersion(), this.version); + } else { + return this.getPolicyModelType().compareTo(arg0.getPolicyModelType()); + } + + } +} diff --git a/src/main/java/org/onap/clamp/loop/template/PolicyModelId.java b/src/main/java/org/onap/clamp/loop/template/PolicyModelId.java new file mode 100644 index 000000000..c4dd1933b --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/PolicyModelId.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import com.google.gson.annotations.Expose; + +import java.io.Serializable; + +public class PolicyModelId implements Serializable { + + /** + * Serial Id. + */ + private static final long serialVersionUID = -2846526482064334745L; + + @Expose + private String policyModelType; + + @Expose + private String version; + + /** + * Default constructor for serialization. + */ + public PolicyModelId() { + + } + + /** + * Constructor. + */ + public PolicyModelId(String policyModelType, String version) { + this.policyModelType = policyModelType; + this.version = version; + } + + /** + * policyModelType getter. + * + * @return the policyModelType + */ + public String getPolicyModelType() { + return policyModelType; + } + + /** + * policyModelType setter. + * + * @param policyModelType the policyModelType to set + */ + public void setPolicyModelType(String policyModelType) { + this.policyModelType = policyModelType; + } + + /** + * version getter. + * + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * version setter. + * + * @param version the version to set + */ + public void setVersion(String version) { + this.version = version; + } +} diff --git a/src/main/java/org/onap/clamp/loop/template/PolicyModelsRepository.java b/src/main/java/org/onap/clamp/loop/template/PolicyModelsRepository.java new file mode 100644 index 000000000..a76e386b5 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/PolicyModelsRepository.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.loop.template; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface PolicyModelsRepository extends JpaRepository<PolicyModel, PolicyModelId> { + @Query("SELECT policymodel.policyModelType FROM PolicyModel as policymodel") + List<String> getAllPolicyModelType(); + + List<PolicyModel> findByPolicyModelType(String policyModelType); +} diff --git a/src/main/java/org/onap/clamp/loop/template/PolicyModelsService.java b/src/main/java/org/onap/clamp/loop/template/PolicyModelsService.java new file mode 100644 index 000000000..17cf5c1c8 --- /dev/null +++ b/src/main/java/org/onap/clamp/loop/template/PolicyModelsService.java @@ -0,0 +1,173 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.loop.template; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.onap.clamp.clds.tosca.ToscaSchemaConstants; +import org.onap.clamp.clds.tosca.ToscaYamlToJsonConvertor; +import org.onap.clamp.policy.pdpgroup.PdpGroup; +import org.onap.clamp.util.SemanticVersioning; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class PolicyModelsService { + private final PolicyModelsRepository policyModelsRepository; + private ToscaYamlToJsonConvertor toscaYamlToJsonConvertor; + + @Autowired + public PolicyModelsService(PolicyModelsRepository policyModelrepo, + ToscaYamlToJsonConvertor convertor) { + policyModelsRepository = policyModelrepo; + toscaYamlToJsonConvertor = convertor; + } + + /** + * Save or Update Policy Model. + * + * @param policyModel The policyModel + * @return The Policy Model + */ + public PolicyModel saveOrUpdatePolicyModel(PolicyModel policyModel) { + return policyModelsRepository.saveAndFlush(policyModel); + } + + /** + * Verify whether Policy Model exist by ID. + * + * @param policyModelId The policyModel Id + * @return The flag indicates whether Policy Model exist + */ + public boolean existsById(PolicyModelId policyModelId) { + return policyModelsRepository.existsById(policyModelId); + } + + /** + * Creates or updates the Tosca Policy Model. + * + * @param policyModelTosca The Policymodel object + * @return The Policy Model created + */ + public PolicyModel createNewPolicyModelFromTosca(String policyModelTosca) { + JsonObject jsonObject = toscaYamlToJsonConvertor.validateAndConvertToJson(policyModelTosca); + String policyModelTypeFromTosca = toscaYamlToJsonConvertor.getValueFromMetadata(jsonObject, + ToscaSchemaConstants.METADATA_POLICY_MODEL_TYPE); + Iterable<PolicyModel> models = getAllPolicyModelsByType(policyModelTypeFromTosca); + Collections.sort((List<PolicyModel>) models); + PolicyModel newPolicyModel = new PolicyModel(policyModelTypeFromTosca, policyModelTosca, + SemanticVersioning.incrementMajorVersion(((ArrayList) models).isEmpty() ? null + : ((ArrayList<PolicyModel>) models).get(0).getVersion()), + toscaYamlToJsonConvertor.getValueFromMetadata(jsonObject, + ToscaSchemaConstants.METADATA_ACRONYM)); + return saveOrUpdatePolicyModel(newPolicyModel); + } + + /** + * Update an existing Tosca Policy Model. + * + * @param policyModelType The policy Model type in Tosca yaml + * @param policyModelVersion The policy Version to update + * @param policyModelTosca The Policy Model tosca + * @return The Policy Model updated + */ + public PolicyModel updatePolicyModelTosca(String policyModelType, String policyModelVersion, + String policyModelTosca) { + JsonObject jsonObject = toscaYamlToJsonConvertor.validateAndConvertToJson(policyModelTosca); + PolicyModel thePolicyModel = getPolicyModel(policyModelType, policyModelVersion); + thePolicyModel.setPolicyAcronym(toscaYamlToJsonConvertor.getValueFromMetadata(jsonObject, + ToscaSchemaConstants.METADATA_ACRONYM)); + thePolicyModel.setPolicyModelTosca(policyModelTosca); + return saveOrUpdatePolicyModel(thePolicyModel); + } + + public List<String> getAllPolicyModelTypes() { + return policyModelsRepository.getAllPolicyModelType(); + } + + public Iterable<PolicyModel> getAllPolicyModels() { + return policyModelsRepository.findAll(); + } + + public PolicyModel getPolicyModel(String type, String version) { + return policyModelsRepository.findById(new PolicyModelId(type, version)).orElse(null); + } + + public Iterable<PolicyModel> getAllPolicyModelsByType(String type) { + return policyModelsRepository.findByPolicyModelType(type); + } + + /** + * Retrieves the Tosca model Yaml string. + * + * @param type The Policy Model Type + * @param version The policy model version + * @return The Tosca model Yaml string + */ + public String getPolicyModelTosca(String type, String version) { + return policyModelsRepository.findById(new PolicyModelId(type, version)) + .orElse(new PolicyModel()).getPolicyModelTosca(); + } + + /** + * This method creates an PolicyModel in Db if it does not exist. + * + * @param policyModel The policyModel to save + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public PolicyModel savePolicyModelInNewTransaction(PolicyModel policyModel) { + return policyModelsRepository.saveAndFlush(policyModel); + } + + /** + * Update the Pdp Group info in Policy Model DB. + * + * @param pdpGroupList The list of Pdp Group info received from Policy Engine + */ + public void updatePdpGroupInfo(List<PdpGroup> pdpGroupList) { + List<PolicyModel> policyModelList = policyModelsRepository.findAll(); + for (PolicyModel policyModel : policyModelList) { + JsonArray supportedPdpGroups = new JsonArray(); + for (PdpGroup pdpGroup : pdpGroupList) { + JsonObject supportedPdpGroup = pdpGroup.getSupportedSubgroups( + policyModel.getPolicyModelType(), policyModel.getVersion()); + if (supportedPdpGroup != null) { + supportedPdpGroups.add(supportedPdpGroup); + } + } + + if (supportedPdpGroups.size() > 0) { + JsonObject supportedPdpJson = new JsonObject(); + supportedPdpJson.add("supportedPdpGroups", supportedPdpGroups); + policyModel.setPolicyPdpGroup(supportedPdpJson); + policyModelsRepository.saveAndFlush(policyModel); + } + } + } +} diff --git a/src/main/java/org/onap/clamp/policy/Policy.java b/src/main/java/org/onap/clamp/policy/Policy.java new file mode 100644 index 000000000..d84f2c8a0 --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/Policy.java @@ -0,0 +1,287 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.policy; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.UnsupportedEncodingException; +import java.util.Map; +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; +import javax.persistence.Transient; +import org.hibernate.annotations.Type; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.json.JSONObject; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.clamp.loop.common.AuditEntity; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.loop.template.LoopElementModel; +import org.onap.clamp.loop.template.PolicyModel; +import org.yaml.snakeyaml.Yaml; + +@MappedSuperclass +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public abstract class Policy extends AuditEntity { + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(Policy.class); + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "json_representation", nullable = false) + private JsonObject jsonRepresentation; + + @Expose + @Type(type = "json") + @Column(columnDefinition = "json", name = "configurations_json") + private JsonObject configurationsJson; + + /** + * This attribute can be null when the user add a policy on the loop instance, not the template. + * When null, It therefore indicates that this policy is not by default in the loop template. + */ + @Expose + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "loop_element_model_id") + private LoopElementModel loopElementModel; + + @Expose + @Column(name = "pdp_group") + private String pdpGroup; + + @Expose + @Column(name = "pdp_sub_group") + private String pdpSubgroup; + + @Expose + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumns({@JoinColumn(name = "policy_model_type", referencedColumnName = "policy_model_type"), + @JoinColumn(name = "policy_model_version", referencedColumnName = "version")}) + private PolicyModel policyModel; + + private JsonObject createJsonFromPolicyTosca() { + Map<String, Object> map = + new Yaml().load(this.getPolicyModel() != null ? this.getPolicyModel().getPolicyModelTosca() : ""); + JSONObject jsonObject = new JSONObject(map); + return new Gson().fromJson(jsonObject.toString(), JsonObject.class); + } + + /** + * This method create the policy payload that must be sent to PEF. + * + * @return A String containing the payload + * @throws UnsupportedEncodingException In case of failure + */ + public String createPolicyPayload() throws UnsupportedEncodingException { + JsonObject toscaJson = createJsonFromPolicyTosca(); + + JsonObject policyPayloadResult = new JsonObject(); + + policyPayloadResult.add("tosca_definitions_version", toscaJson.get("tosca_definitions_version")); + + JsonObject topologyTemplateNode = new JsonObject(); + policyPayloadResult.add("topology_template", topologyTemplateNode); + + JsonArray policiesArray = new JsonArray(); + topologyTemplateNode.add("policies", policiesArray); + + JsonObject thisPolicy = new JsonObject(); + policiesArray.add(thisPolicy); + + JsonObject policyDetails = new JsonObject(); + thisPolicy.add(this.getName(), policyDetails); + policyDetails.addProperty("type", this.getPolicyModel().getPolicyModelType()); + policyDetails.addProperty("type_version", this.getPolicyModel().getVersion()); + policyDetails.addProperty("version", this.getPolicyModel().getVersion()); + + JsonObject policyMetadata = new JsonObject(); + policyDetails.add("metadata", policyMetadata); + policyMetadata.addProperty("policy-id", this.getName()); + + policyDetails.add("properties", this.getConfigurationsJson()); + + String policyPayload = new GsonBuilder().setPrettyPrinting().create().toJson(policyPayloadResult); + logger.info("Policy payload: " + policyPayload); + return policyPayload; + } + + + /** + * Name getter. + * + * @return the name + */ + public abstract String getName(); + + /** + * Name setter. + */ + public abstract void setName(String name); + + /** + * jsonRepresentation getter. + * + * @return the jsonRepresentation + */ + public JsonObject getJsonRepresentation() { + return jsonRepresentation; + } + + /** + * jsonRepresentation setter. + * + * @param jsonRepresentation The jsonRepresentation to set + */ + public void setJsonRepresentation(JsonObject jsonRepresentation) { + this.jsonRepresentation = jsonRepresentation; + } + + /** + * Regenerate the Policy Json Representation. + * + * @param toscaConverter The tosca converter required to regenerate the json schema + * @param serviceModel The service model associated + */ + public abstract void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, + Service serviceModel); + + /** + * policyModel getter. + * + * @return the policyModel + */ + public PolicyModel getPolicyModel() { + return policyModel; + } + + /** + * policyModel setter. + * + * @param policyModel The new policyModel + */ + public void setPolicyModel(PolicyModel policyModel) { + this.policyModel = policyModel; + } + + /** + * configurationsJson getter. + * + * @return The configurationsJson + */ + public JsonObject getConfigurationsJson() { + return configurationsJson; + } + + /** + * configurationsJson setter. + * + * @param configurationsJson the configurationsJson to set + */ + public void setConfigurationsJson(JsonObject configurationsJson) { + this.configurationsJson = configurationsJson; + } + + /** + * loopElementModel getter. + * + * @return the loopElementModel + */ + public LoopElementModel getLoopElementModel() { + return loopElementModel; + } + + /** + * loopElementModel setter. + * + * @param loopElementModel the loopElementModel to set + */ + public void setLoopElementModel(LoopElementModel loopElementModel) { + this.loopElementModel = loopElementModel; + } + + /** + * pdpGroup getter. + * + * @return the pdpGroup + */ + public String getPdpGroup() { + return pdpGroup; + } + + /** + * pdpGroup setter. + * + * @param pdpGroup the pdpGroup to set + */ + public void setPdpGroup(String pdpGroup) { + this.pdpGroup = pdpGroup; + } + + /** + * pdpSubgroup getter. + * + * @return the pdpSubgroup + */ + public String getPdpSubgroup() { + return pdpSubgroup; + } + + /** + * pdpSubgroup setter. + * + * @param pdpSubgroup the pdpSubgroup to set + */ + public void setPdpSubgroup(String pdpSubgroup) { + this.pdpSubgroup = pdpSubgroup; + } + + /** + * Generate the policy name. + * + * @param policyType The policy type + * @param serviceName The service name + * @param serviceVersion The service version + * @param resourceName The resource name + * @param blueprintFilename The blueprint file name + * @return The generated policy name + */ + public static String generatePolicyName(String policyType, String serviceName, String serviceVersion, + String resourceName, String blueprintFilename) { + StringBuilder buffer = new StringBuilder(policyType).append("_").append(serviceName).append("_v") + .append(serviceVersion).append("_").append(resourceName).append("_") + .append(blueprintFilename.replaceAll(".yaml", "")); + return buffer.toString().replace('.', '_').replaceAll(" ", ""); + } +} diff --git a/src/main/java/org/onap/clamp/policy/PolicyService.java b/src/main/java/org/onap/clamp/policy/PolicyService.java new file mode 100644 index 000000000..ae15f86da --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/PolicyService.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.policy; + +import java.util.List; +import java.util.Set; + +import org.onap.clamp.loop.Loop; + +public interface PolicyService<T extends Policy> { + + Set<T> updatePolicies(Loop loop, List<T> newPolicies); + + boolean isExisting(String policyName); +} diff --git a/src/main/java/org/onap/clamp/policy/downloader/PolicyEngineController.java b/src/main/java/org/onap/clamp/policy/downloader/PolicyEngineController.java new file mode 100644 index 000000000..0c3f677a1 --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/downloader/PolicyEngineController.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.policy.downloader; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; + +import java.time.Instant; + +import org.json.simple.parser.ParseException; +import org.onap.clamp.clds.client.PolicyEngineServices; +import org.onap.clamp.loop.template.PolicyModelsRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.Scheduled; + +/** + * This class implements a periodic job that is done in the background to + * synchronize policy models available on the policy engine and the clamp + * database table PolicyModel. + */ +@Configuration +@Profile("clamp-policy-controller") +public class PolicyEngineController { + + protected static final EELFLogger logger = EELFManager.getInstance().getLogger(PolicyEngineController.class); + protected static final EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger(); + protected static final EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger(); + public static final String POLICY_RETRY_INTERVAL = "policy.retry.interval"; + public static final String POLICY_RETRY_LIMIT = "policy.retry.limit"; + + private final PolicyEngineServices policyEngineServices; + + private Instant lastInstantExecuted; + + @Autowired + public PolicyEngineController(PolicyEngineServices policyEngineService, + PolicyModelsRepository policyModelsRepository) { + this.policyEngineServices = policyEngineService; + } + + @Scheduled(fixedRate = 300000) + public synchronized void synchronizeAllPolicies() { + policyEngineServices.synchronizeAllPolicies(); + lastInstantExecuted = Instant.now(); + } + + public Instant getLastInstantExecuted() { + return lastInstantExecuted; + } + + @Scheduled(fixedRate = 300000) + public synchronized void downloadPdpGroups() throws ParseException { + policyEngineServices.downloadPdpGroups(); + } +} diff --git a/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicy.java b/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicy.java new file mode 100644 index 000000000..77627a31a --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicy.java @@ -0,0 +1,276 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.policy.microservice; + +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.apache.commons.lang3.RandomStringUtils; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.loop.template.LoopElementModel; +import org.onap.clamp.loop.template.PolicyModel; +import org.onap.clamp.policy.Policy; + +@Entity +@Table(name = "micro_service_policies") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class MicroServicePolicy extends Policy implements Serializable { + /** + * The serial version ID. + */ + private static final long serialVersionUID = 6271238288583332616L; + + @Expose + @Id + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "context") + private String context; + + @Expose + @Column(name = "device_type_scope") + private String deviceTypeScope; + + @Expose + @Column(name = "shared", nullable = false) + private Boolean shared; + + @ManyToMany(mappedBy = "microServicePolicies", fetch = FetchType.EAGER) + private Set<Loop> usedByLoops = new HashSet<>(); + + @Expose + @Column(name = "dcae_deployment_id") + private String dcaeDeploymentId; + + @Expose + @Column(name = "dcae_deployment_status_url") + private String dcaeDeploymentStatusUrl; + + @Expose + @Column(name = "dcae_blueprint_id") + private String dcaeBlueprintId; + + /** + * Constructor for serialization. + */ + public MicroServicePolicy() { + } + + /** + * The constructor that does not make use of ToscaYamlToJsonConvertor but take + * the jsonRepresentation instead. + * + * @param name The name of the MicroService + * @param policyModel The policy model type of the MicroService + * @param shared The flag indicate whether the MicroService is + * shared + * @param jsonRepresentation The UI representation in json format + * @param loopElementModel The loop element model from which this instance should be created + * @param pdpGroup The Pdp Group info + * @param pdpSubgroup The Pdp Subgroup info + */ + public MicroServicePolicy(String name, PolicyModel policyModel, Boolean shared, + JsonObject jsonRepresentation, LoopElementModel loopElementModel, String pdpGroup, + String pdpSubgroup) { + this.name = name; + this.setPolicyModel(policyModel); + this.shared = shared; + this.setJsonRepresentation(jsonRepresentation); + this.setLoopElementModel(loopElementModel); + this.setPdpGroup(pdpGroup); + this.setPdpSubgroup(pdpSubgroup); + } + + /** + * Constructor with tosca converter. + * + * @param loop The loop instance + * @param service The service model object + * @param loopElementModel The loop element model from which this microservice instance is created + * @param toscaConverter The tosca converter that will used to convert the tosca policy model + */ + public MicroServicePolicy(Loop loop, Service service, LoopElementModel loopElementModel, + ToscaConverterWithDictionarySupport toscaConverter) { + this(Policy.generatePolicyName("MICROSERVICE", service.getName(), service.getVersion(), + loopElementModel.getPolicyModels().first().getPolicyAcronym() + '_' + + loopElementModel.getPolicyModels().first().getVersion(), + RandomStringUtils.randomAlphanumeric(3)), + loopElementModel.getPolicyModels().first(), false, new JsonObject(), loopElementModel, null, null); + this.updateJsonRepresentation(toscaConverter, service); + } + + @Override + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, Service serviceModel) { + this.setJsonRepresentation( + toscaConverter.convertToscaToJsonSchemaObject(this.getPolicyModel().getPolicyModelTosca(), + this.getPolicyModel().getPolicyModelType(), serviceModel)); + } + + public Boolean getShared() { + return shared; + } + + void setShared(Boolean shared) { + this.shared = shared; + } + + public Set<Loop> getUsedByLoops() { + return usedByLoops; + } + + void setUsedByLoops(Set<Loop> usedBy) { + this.usedByLoops = usedBy; + } + + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public String getDeviceTypeScope() { + return deviceTypeScope; + } + + public void setDeviceTypeScope(String deviceTypeScope) { + this.deviceTypeScope = deviceTypeScope; + } + + /** + * dcaeDeploymentId getter. + * + * @return the dcaeDeploymentId + */ + public String getDcaeDeploymentId() { + return dcaeDeploymentId; + } + + /** + * dcaeDeploymentId setter. + * + * @param dcaeDeploymentId the dcaeDeploymentId to set + */ + public void setDcaeDeploymentId(String dcaeDeploymentId) { + this.dcaeDeploymentId = dcaeDeploymentId; + } + + /** + * dcaeDeploymentStatusUrl getter. + * + * @return the dcaeDeploymentStatusUrl + */ + public String getDcaeDeploymentStatusUrl() { + return dcaeDeploymentStatusUrl; + } + + /** + * dcaeDeploymentStatusUrl setter. + * + * @param dcaeDeploymentStatusUrl the dcaeDeploymentStatusUrl to set + */ + public void setDcaeDeploymentStatusUrl(String dcaeDeploymentStatusUrl) { + this.dcaeDeploymentStatusUrl = dcaeDeploymentStatusUrl; + } + + /** + * dcaeBlueprintId getter. + * + * @return the dcaeBlueprintId + */ + public String getDcaeBlueprintId() { + return dcaeBlueprintId; + } + + /** + * dcaeBlueprintId setter. + * + * @param dcaeBlueprintId the dcaeBlueprintId to set + */ + void setDcaeBlueprintId(String dcaeBlueprintId) { + this.dcaeBlueprintId = dcaeBlueprintId; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MicroServicePolicy other = (MicroServicePolicy) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } + else if (!name.equals(other.name)) { + return false; + } + return true; + } +} diff --git a/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicyRepository.java b/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicyRepository.java new file mode 100644 index 000000000..38b310ce8 --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicyRepository.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.policy.microservice; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MicroServicePolicyRepository extends JpaRepository<MicroServicePolicy, String> { + +} diff --git a/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicyService.java b/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicyService.java new file mode 100644 index 000000000..060e79a63 --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/microservice/MicroServicePolicyService.java @@ -0,0 +1,112 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.policy.microservice; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.policy.PolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MicroServicePolicyService implements PolicyService<MicroServicePolicy> { + + private final MicroServicePolicyRepository microServiceRepository; + + @Autowired + public MicroServicePolicyService(MicroServicePolicyRepository microServiceRepository) { + this.microServiceRepository = microServiceRepository; + } + + @Override + public Set<MicroServicePolicy> updatePolicies(Loop loop, List<MicroServicePolicy> newMicroservicePolicies) { + return newMicroservicePolicies.stream().map(policy -> getAndUpdateMicroServicePolicy(loop, policy)) + .collect(Collectors.toSet()); + } + + @Override + public boolean isExisting(String policyName) { + return microServiceRepository.existsById(policyName); + } + + /** + * Get and update the MicroService policy properties. + * + * @param loop The loop + * @param policy The new MicroService policy + * @return The updated MicroService policy + */ + public MicroServicePolicy getAndUpdateMicroServicePolicy(Loop loop, MicroServicePolicy policy) { + return microServiceRepository.save( + microServiceRepository + .findById(policy.getName()).map(p -> updateMicroservicePolicyProperties(p, policy, loop)) + .orElse(new MicroServicePolicy(policy.getName(), policy.getPolicyModel(), + policy.getShared(), policy.getJsonRepresentation(), null, policy.getPdpGroup(), + policy.getPdpSubgroup()))); + } + + private MicroServicePolicy updateMicroservicePolicyProperties(MicroServicePolicy oldPolicy, + MicroServicePolicy newPolicy, Loop loop) { + oldPolicy.setConfigurationsJson(newPolicy.getConfigurationsJson()); + if (!oldPolicy.getUsedByLoops().contains(loop)) { + oldPolicy.getUsedByLoops().add(loop); + } + oldPolicy.setPdpGroup(newPolicy.getPdpGroup()); + oldPolicy.setPdpSubgroup(newPolicy.getPdpSubgroup()); + return oldPolicy; + } + + /** + * Update the MicroService policy deployment related parameters. + * + * @param microServicePolicy The micro service policy + * @param deploymentId The deployment ID as returned by DCAE + * @param deploymentUrl The Deployment URL as returned by DCAE + */ + public void updateDcaeDeploymentFields(MicroServicePolicy microServicePolicy, String deploymentId, + String deploymentUrl) { + microServicePolicy.setDcaeDeploymentId(deploymentId); + microServicePolicy.setDcaeDeploymentStatusUrl(deploymentUrl); + microServiceRepository.saveAndFlush(microServicePolicy); + } + + + /** + * Api to refresh the MicroService Policy UI window. + * + * @param microServicePolicy The micro Service policy object + * @param toscaConverter The tosca converter required to convert the tosca model to json schema + * @param loop As a microservice object can belong to multiple loops, we need it here + */ + public void refreshMicroServicePolicyJsonRepresentation(MicroServicePolicy microServicePolicy, + ToscaConverterWithDictionarySupport toscaConverter, + Loop loop) { + microServicePolicy.updateJsonRepresentation(toscaConverter, loop.getModelService()); + this.microServiceRepository.saveAndFlush(microServicePolicy); + + } +} diff --git a/src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java new file mode 100644 index 000000000..4b052427f --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicy.java @@ -0,0 +1,218 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.onap.clamp.policy.operational; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import javax.persistence.Transient; +import org.apache.commons.lang3.RandomStringUtils; +import org.hibernate.annotations.TypeDef; +import org.hibernate.annotations.TypeDefs; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.dao.model.jsontype.StringJsonUserType; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.loop.service.Service; +import org.onap.clamp.loop.template.LoopElementModel; +import org.onap.clamp.loop.template.PolicyModel; +import org.onap.clamp.policy.Policy; + +@Entity +@Table(name = "operational_policies") +@TypeDefs({@TypeDef(name = "json", typeClass = StringJsonUserType.class)}) +public class OperationalPolicy extends Policy implements Serializable { + /** + * The serial version ID. + */ + private static final long serialVersionUID = 6117076450841538255L; + + @Transient + private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicy.class); + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "loop_id", nullable = false) + private Loop loop; + + /** + * Constructor for serialization. + */ + public OperationalPolicy() { + } + + /** + * The constructor. + * + * @param name The name of the operational policy + * @param configurationsJson The operational policy property in the format of + * json + * @param jsonRepresentation The jsonObject defining the json schema + * @param policyModel The policy model associated if any, can be null + * @param loopElementModel The loop element from which this instance is supposed to be created + * @param pdpGroup The Pdp Group info + * @param pdpSubgroup The Pdp Subgroup info + */ + public OperationalPolicy(String name, JsonObject configurationsJson, + JsonObject jsonRepresentation, PolicyModel policyModel, + LoopElementModel loopElementModel, String pdpGroup, String pdpSubgroup) { + this.name = name; + this.setPolicyModel(policyModel); + this.setConfigurationsJson(configurationsJson); + this.setPdpGroup(pdpGroup); + this.setPdpSubgroup(pdpSubgroup); + this.setLoopElementModel(loopElementModel); + this.setJsonRepresentation(jsonRepresentation); + + } + + /** + * Create an operational policy from a loop element model. + * + * @param loop The parent loop + * @param service The loop service + * @param loopElementModel The loop element model + * @param toscaConverter The tosca converter that must be used to create the Json representation + */ + public OperationalPolicy(Loop loop, Service service, LoopElementModel loopElementModel, + ToscaConverterWithDictionarySupport toscaConverter) { + this(Policy.generatePolicyName("OPERATIONAL", service.getName(), service.getVersion(), + loopElementModel.getPolicyModels().first().getPolicyAcronym() + '_' + + loopElementModel.getPolicyModels().first().getVersion(), + RandomStringUtils.randomAlphanumeric(3)), new JsonObject(), + new JsonObject(), loopElementModel.getPolicyModels().first(), loopElementModel, null, null); + this.setLoop(loop); + this.updateJsonRepresentation(toscaConverter, service); + } + + /** + * Create an operational policy from a policy model. + * + * @param loop The parent loop + * @param service The loop service + * @param policyModel The policy model + * @param toscaConverter The tosca converter that must be used to create the Json representation + */ + public OperationalPolicy(Loop loop, Service service, PolicyModel policyModel, + ToscaConverterWithDictionarySupport toscaConverter) { + this(Policy.generatePolicyName("OPERATIONAL", service.getName(), service.getVersion(), + policyModel.getPolicyAcronym() + '_' + policyModel.getVersion(), + RandomStringUtils.randomAlphanumeric(3)), + new JsonObject(), + new JsonObject(), policyModel, null, null, null); + this.setLoop(loop); + this.updateJsonRepresentation(toscaConverter, service); + } + + public void setLoop(Loop loopName) { + this.loop = loopName; + } + + public Loop getLoop() { + return loop; + } + + @Override + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public void updateJsonRepresentation(ToscaConverterWithDictionarySupport toscaConverter, Service serviceModel) { + { + this.setJsonRepresentation(new JsonObject()); + if (this.getPolicyModel() == null) { + return; + } + + // Generic Case + this.setJsonRepresentation(toscaConverter.convertToscaToJsonSchemaObject( + this.getPolicyModel().getPolicyModelTosca(), + this.getPolicyModel().getPolicyModelType(), serviceModel)); + + } + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + OperationalPolicy other = (OperationalPolicy) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else { + if (!name.equals(other.name)) { + return false; + } + } + return true; + } + + @Override + public String createPolicyPayload() throws UnsupportedEncodingException { + return super.createPolicyPayload(); + + } +} diff --git a/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepository.java b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepository.java new file mode 100644 index 000000000..c0a6e12cd --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepository.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.policy.operational; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OperationalPolicyRepository extends JpaRepository<OperationalPolicy, String> { + void deleteByName(String policyName); +} diff --git a/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java new file mode 100644 index 000000000..0381f0a2a --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyRepresentationBuilder.java @@ -0,0 +1,352 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2020 Huawei Technologies Co., Ltd. + * ================================================================================ + * 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.onap.clamp.policy.operational; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import java.io.IOException; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.onap.clamp.clds.util.JsonUtils; +import org.onap.clamp.clds.util.ResourceFileUtils; +import org.onap.clamp.loop.service.Service; + +public class OperationalPolicyRepresentationBuilder { + + private static final EELFLogger logger = + EELFManager.getInstance().getLogger(OperationalPolicyRepresentationBuilder.class); + + public static final String PROPERTIES = "properties"; + public static final String ITEMS = "items"; + public static final String ANY_OF = "anyOf"; + public static final String TITLE = "title"; + public static final String RECIPE = "recipe"; + public static final String DEFAULT = "default"; + public static final String STRING = "string"; + public static final String TYPE = "type"; + public static final String TYPE_LIST = "list"; + public static final String TYPE_OBJECT = "object"; + public static final String TYPE_ARRAY = "array"; + + private OperationalPolicyRepresentationBuilder() { + throw new IllegalStateException("This is Utility class, not supposed to be initiated."); + } + + /** + * This method generates the operational policy json representation that will be + * used by ui for rendering. It uses the model (VF and VFModule) defined in the + * loop object to do so, so it's dynamic. It also uses the operational policy + * schema template defined in the resource folder. + * + * @param modelJson The loop model json + * @return The json representation + */ + public static JsonObject generateOperationalPolicySchema(Service modelJson) { + + JsonObject jsonSchema = null; + try { + jsonSchema = JsonUtils.GSON.fromJson( + ResourceFileUtils + .getResourceAsString("clds/json-schema/operational_policies/operational_policy.json"), + JsonObject.class); + jsonSchema.get(PROPERTIES).getAsJsonObject() + .get("operational_policy").getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("policies") + .getAsJsonObject().get(ITEMS).getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("target") + .getAsJsonObject().get(ANY_OF).getAsJsonArray().addAll(createAnyOfArray(modelJson, true)); + + // update CDS recipe and payload information to schema + JsonArray actors = jsonSchema.get(PROPERTIES).getAsJsonObject() + .get("operational_policy").getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("policies") + .getAsJsonObject().get(ITEMS).getAsJsonObject().get(PROPERTIES).getAsJsonObject().get("actor") + .getAsJsonObject().get(ANY_OF).getAsJsonArray(); + + for (JsonElement actor : actors) { + if ("CDS".equalsIgnoreCase(actor.getAsJsonObject().get(TITLE).getAsString())) { + actor.getAsJsonObject().get(PROPERTIES).getAsJsonObject().get(RECIPE).getAsJsonObject() + .get(ANY_OF).getAsJsonArray() + .addAll(createAnyOfArrayForCdsRecipe(modelJson)); + } + } + return jsonSchema; + } catch (IOException e) { + logger.error("Unable to generate the json schema because of an exception", e); + return new JsonObject(); + } + } + + private static JsonObject createSchemaProperty(String title, String type, String defaultValue, String readOnlyFlag, + String[] enumArray) { + JsonObject property = new JsonObject(); + property.addProperty(TITLE, title); + property.addProperty(TYPE, type); + property.addProperty(DEFAULT, defaultValue); + property.addProperty("readOnly", readOnlyFlag); + + if (enumArray != null) { + JsonArray jsonArray = new JsonArray(); + property.add("enum", jsonArray); + for (String val : enumArray) { + jsonArray.add(val); + } + } + return property; + } + + private static JsonArray createVnfSchema(Service modelService, boolean generateType) { + JsonArray vnfSchemaArray = new JsonArray(); + JsonObject modelVnfs = modelService.getResourceByType("VF"); + + for (Entry<String, JsonElement> entry : modelVnfs.entrySet()) { + JsonObject vnfOneOfSchema = new JsonObject(); + vnfOneOfSchema.addProperty(TITLE, "VNF" + "-" + entry.getKey()); + JsonObject properties = new JsonObject(); + if (generateType) { + properties.add(TYPE, createSchemaProperty("Type", STRING, "VNF", "True", null)); + } + properties.add("resourceID", createSchemaProperty("Resource ID", STRING, + modelVnfs.get(entry.getKey()).getAsJsonObject().get("invariantUUID").getAsString(), "True", null)); + + vnfOneOfSchema.add(PROPERTIES, properties); + vnfSchemaArray.add(vnfOneOfSchema); + } + return vnfSchemaArray; + } + + private static JsonArray createBlankEntry() { + JsonArray result = new JsonArray(); + JsonObject blankObject = new JsonObject(); + blankObject.addProperty("title", "User defined"); + blankObject.add("properties", new JsonObject()); + result.add(blankObject); + return result; + } + + private static JsonArray createVfModuleSchema(Service modelService, boolean generateType) { + JsonArray vfModuleOneOfSchemaArray = new JsonArray(); + JsonObject modelVfModules = modelService.getResourceByType("VFModule"); + + for (Entry<String, JsonElement> entry : modelVfModules.entrySet()) { + JsonObject vfModuleOneOfSchema = new JsonObject(); + vfModuleOneOfSchema.addProperty(TITLE, "VFMODULE" + "-" + entry.getKey()); + JsonObject properties = new JsonObject(); + if (generateType) { + properties.add(TYPE, createSchemaProperty("Type", STRING, "VFMODULE", "True", null)); + } + properties.add("resourceID", + createSchemaProperty("Resource ID", STRING, + modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelName").getAsString(), + "True", null)); + properties.add("modelInvariantId", + createSchemaProperty("Model Invariant Id (ModelInvariantUUID)", STRING, + modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelInvariantUUID") + .getAsString(), + "True", null)); + properties.add("modelVersionId", + createSchemaProperty("Model Version Id (ModelUUID)", STRING, + modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelUUID").getAsString(), + "True", null)); + properties.add("modelName", + createSchemaProperty("Model Name", STRING, + modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelName").getAsString(), + "True", null)); + properties.add("modelVersion", createSchemaProperty("Model Version", STRING, + modelVfModules.get(entry.getKey()).getAsJsonObject().get("vfModuleModelVersion").getAsString(), + "True", null)); + properties + .add("modelCustomizationId", + createSchemaProperty("Customization ID", STRING, + modelVfModules.get(entry.getKey()).getAsJsonObject() + .get("vfModuleModelCustomizationUUID").getAsString(), "True", + null)); + + vfModuleOneOfSchema.add(PROPERTIES, properties); + vfModuleOneOfSchemaArray.add(vfModuleOneOfSchema); + } + return vfModuleOneOfSchemaArray; + } + + /** + * Create an anyOf array of possible structure we may have for Target. + * + * @param modelJson The service object + * @return A JsonArray with everything inside + */ + public static JsonArray createAnyOfArray(Service modelJson, boolean generateType) { + JsonArray targetOneOfStructure = new JsonArray(); + // First entry must be user defined + targetOneOfStructure.addAll(createBlankEntry()); + targetOneOfStructure.addAll(createVnfSchema(modelJson, generateType)); + targetOneOfStructure.addAll(createVfModuleSchema(modelJson, generateType)); + return targetOneOfStructure; + } + + private static JsonArray createAnyOfArrayForCdsRecipe(Service modelJson) { + JsonArray anyOfStructure = new JsonArray(); + anyOfStructure.addAll(createAnyOfCdsRecipe(modelJson.getResourceDetails().getAsJsonObject("VF"))); + anyOfStructure.addAll(createAnyOfCdsRecipe(modelJson.getResourceDetails().getAsJsonObject("PNF"))); + return anyOfStructure; + } + + private static JsonArray createAnyOfCdsRecipe(JsonObject jsonObject) { + JsonArray schemaArray = new JsonArray(); + for (Entry<String, JsonElement> entry : jsonObject.entrySet()) { + JsonObject controllerProperties = entry.getValue().getAsJsonObject() + .getAsJsonObject("controllerProperties"); + + if (controllerProperties != null && controllerProperties.getAsJsonObject("workflows") != null) { + JsonObject workflows = controllerProperties.getAsJsonObject("workflows"); + for (Entry<String, JsonElement> workflowsEntry : workflows.entrySet()) { + JsonObject obj = new JsonObject(); + obj.addProperty(TITLE, workflowsEntry.getKey()); + obj.addProperty(TYPE, "object"); + obj.add(PROPERTIES, createPayloadProperty(workflowsEntry.getValue().getAsJsonObject(), + controllerProperties, workflowsEntry.getKey())); + schemaArray.add(obj); + } + + } + } + return schemaArray; + } + + private static JsonObject createPayloadProperty(JsonObject workFlow, + JsonObject controllerProperties, String workFlowName) { + JsonObject payload = new JsonObject(); + payload.addProperty(TITLE, "Payload"); + payload.addProperty(TYPE, "object"); + payload.add(PROPERTIES, createInputPropertiesForPayload(workFlow, controllerProperties, + workFlowName)); + JsonObject properties = new JsonObject(); + properties.add(RECIPE, createRecipeForCdsWorkflow(workFlowName)); + properties.add("payload", payload); + return properties; + } + + private static JsonObject createRecipeForCdsWorkflow(String workflow) { + JsonObject recipe = new JsonObject(); + recipe.addProperty(TITLE, RECIPE); + recipe.addProperty(TYPE, STRING); + recipe.addProperty(DEFAULT, workflow); + JsonObject options = new JsonObject(); + options.addProperty("hidden", true); + recipe.add("options", options); + return recipe; + } + + /** + * Returns the properties of payload based on the cds work flows. + * + * @param workFlow cds work flows to update payload + * @param controllerProperties cds properties to get blueprint name and + * version + * @param workFlowName work flow name + * @return returns the properties of payload + */ + public static JsonObject createInputPropertiesForPayload(JsonObject workFlow, + JsonObject controllerProperties, + String workFlowName) { + String artifactName = controllerProperties.get("sdnc_model_name").getAsString(); + String artifactVersion = controllerProperties.get("sdnc_model_version").getAsString(); + JsonObject inputs = workFlow.getAsJsonObject("inputs"); + JsonObject jsonObject = new JsonObject(); + jsonObject.add("artifact_name", createSchemaProperty( + "artifact name", STRING, artifactName, "True", null)); + jsonObject.add("artifact_version", createSchemaProperty( + "artifact version", STRING, artifactVersion, "True", null)); + jsonObject.add("mode", createCdsInputProperty( + "mode", STRING, "async" ,null)); + jsonObject.add("data", createDataProperty(inputs, workFlowName)); + return jsonObject; + } + + private static JsonObject createDataProperty(JsonObject inputs, String workflowName) { + JsonObject data = new JsonObject(); + data.addProperty(TITLE, "data"); + JsonObject dataObj = new JsonObject(); + addDataFields(inputs, dataObj, workflowName); + data.add(PROPERTIES, dataObj); + return data; + } + + private static void addDataFields(JsonObject inputs, + JsonObject dataObj, + String workFlowName) { + Set<Map.Entry<String, JsonElement>> entrySet = inputs.entrySet(); + for (Map.Entry<String, JsonElement> entry : entrySet) { + String key = entry.getKey(); + JsonObject inputProperty = inputs.getAsJsonObject(key); + if (key.equalsIgnoreCase(workFlowName + "-properties")) { + addDataFields(entry.getValue().getAsJsonObject().get("properties").getAsJsonObject(), + dataObj, workFlowName); + } else { + dataObj.add(entry.getKey(), + createCdsInputProperty(key, inputProperty.get(TYPE).getAsString(),null, + entry.getValue().getAsJsonObject())); + } + } + } + + private static JsonObject createCdsInputProperty(String title, + String type, + String defaultValue, + JsonObject cdsProperty) { + JsonObject property = new JsonObject(); + property.addProperty(TITLE, title); + + if (TYPE_LIST.equalsIgnoreCase(type)) { + property.addProperty(TYPE, TYPE_ARRAY); + if (cdsProperty != null && cdsProperty.get(PROPERTIES) != null) { + JsonObject listProperties = new JsonObject(); + listProperties.add(PROPERTIES, getProperties(cdsProperty.get(PROPERTIES).getAsJsonObject())); + property.add(ITEMS, listProperties); + } + } else if (TYPE_OBJECT.equalsIgnoreCase(type)) { + property.addProperty(TYPE, TYPE_OBJECT); + property.add(PROPERTIES, getProperties(cdsProperty.get(PROPERTIES).getAsJsonObject())); + } else { + property.addProperty(TYPE, type); + } + + if (defaultValue != null) { + property.addProperty(DEFAULT, defaultValue); + } + return property; + } + + private static JsonObject getProperties(JsonObject inputProperties) { + if (inputProperties == null) { + return null; + } + JsonObject dataObject = new JsonObject(); + addDataFields(inputProperties, dataObject, null); + return dataObject; + } +} diff --git a/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyService.java b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyService.java new file mode 100644 index 000000000..d5442e145 --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/operational/OperationalPolicyService.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 Nokia 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.onap.clamp.policy.operational; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.onap.clamp.clds.tosca.update.ToscaConverterWithDictionarySupport; +import org.onap.clamp.loop.Loop; +import org.onap.clamp.loop.template.PolicyModelsRepository; +import org.onap.clamp.policy.PolicyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class OperationalPolicyService implements PolicyService<OperationalPolicy> { + + private final OperationalPolicyRepository operationalPolicyRepository; + + private final PolicyModelsRepository policyModelsRepository; + + private static final EELFLogger logger = EELFManager.getInstance().getLogger(OperationalPolicyService.class); + + @Autowired + public OperationalPolicyService(OperationalPolicyRepository repository, + PolicyModelsRepository policyModelsRepository) { + this.operationalPolicyRepository = repository; + this.policyModelsRepository = policyModelsRepository; + } + + @Override + public Set<OperationalPolicy> updatePolicies(Loop loop, List<OperationalPolicy> operationalPolicies) { + return operationalPolicies + .parallelStream() + .map(policy -> + operationalPolicyRepository + .findById(policy.getName()) + .map(p -> setConfiguration(p, policy)) + .orElse(initializeMissingFields(loop, policy))) + .collect(Collectors.toSet()); + } + + @Override + public boolean isExisting(String policyName) { + return operationalPolicyRepository.existsById(policyName); + } + + private OperationalPolicy initializeMissingFields(Loop loop, OperationalPolicy policy) { + policy.setLoop(loop); + return policy; + } + + private OperationalPolicy setConfiguration(OperationalPolicy policy, OperationalPolicy newPolicy) { + policy.setConfigurationsJson(newPolicy.getConfigurationsJson()); + policy.setPdpGroup(newPolicy.getPdpGroup()); + policy.setPdpSubgroup(newPolicy.getPdpSubgroup()); + return policy; + } + + /** + * Api to refresh the Operational Policy UI window. + * + * @param operationalPolicy The operational policy object + * @param toscaConverter the tosca converter required to convert the tosca model to json schema + */ + public void refreshOperationalPolicyJsonRepresentation(OperationalPolicy operationalPolicy, + ToscaConverterWithDictionarySupport toscaConverter) { + operationalPolicy.updateJsonRepresentation(toscaConverter, operationalPolicy.getLoop().getModelService()); + this.operationalPolicyRepository.saveAndFlush(operationalPolicy); + } +} diff --git a/src/main/java/org/onap/clamp/policy/pdpgroup/PdpGroup.java b/src/main/java/org/onap/clamp/policy/pdpgroup/PdpGroup.java new file mode 100644 index 000000000..a3cf4e053 --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/pdpgroup/PdpGroup.java @@ -0,0 +1,93 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.policy.pdpgroup; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.annotations.Expose; + +import java.util.List; + +/** + * This class maps the get Pdp Group response to a nice pojo. + */ +public class PdpGroup { + + @Expose + private String name; + + @Expose + private String pdpGroupState; + + @Expose + private List<PdpSubgroup> pdpSubgroups; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPdpGroupState() { + return pdpGroupState; + } + + public void setPdpGroupState(String pdpGroupState) { + this.pdpGroupState = pdpGroupState; + } + + public List<PdpSubgroup> getPdpSubgroups() { + return pdpSubgroups; + } + + public void setPdpSubgroups(List<PdpSubgroup> pdpSubgroups) { + this.pdpSubgroups = pdpSubgroups; + } + + /** + * Get supported subGroups based on the defined policy type and version. + * @param policyType The policy type + * @param version The version + * @return The supported subGroup list in Json format + */ + public JsonObject getSupportedSubgroups(String policyType, String version) { + if (!pdpGroupState.equalsIgnoreCase("ACTIVE")) { + return null; + } + JsonArray supportedSubgroups = new JsonArray(); + for (PdpSubgroup subGroup : pdpSubgroups) { + if (subGroup.getSupportedPolicyTypes().contains(new PolicyModelKey(policyType, version))) { + supportedSubgroups.add(subGroup.getPdpType()); + } + } + if (supportedSubgroups.size() > 0) { + JsonObject supportedPdpGroup = new JsonObject(); + supportedPdpGroup.add(this.name, supportedSubgroups); + return supportedPdpGroup; + } + return null; + } +} diff --git a/src/main/java/org/onap/clamp/policy/pdpgroup/PdpSubgroup.java b/src/main/java/org/onap/clamp/policy/pdpgroup/PdpSubgroup.java new file mode 100644 index 000000000..28de79abf --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/pdpgroup/PdpSubgroup.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.policy.pdpgroup; + +import com.google.gson.annotations.Expose; +import java.util.List; + +/** + * This class maps the Policy get PDP Group response to a nice pojo. + */ +public class PdpSubgroup { + + @Expose + private String pdpType; + + @Expose + private List<PolicyModelKey> supportedPolicyTypes; + + public String getPdpType() { + return pdpType; + } + + public void setPdpType(String pdpType) { + this.pdpType = pdpType; + } + + public List<PolicyModelKey> getSupportedPolicyTypes() { + return supportedPolicyTypes; + } + + public void setSupportedPolicyTypes(List<PolicyModelKey> supportedPolicyTypes) { + this.supportedPolicyTypes = supportedPolicyTypes; + } + +} diff --git a/src/main/java/org/onap/clamp/policy/pdpgroup/PolicyModelKey.java b/src/main/java/org/onap/clamp/policy/pdpgroup/PolicyModelKey.java new file mode 100644 index 000000000..707b3bd2f --- /dev/null +++ b/src/main/java/org/onap/clamp/policy/pdpgroup/PolicyModelKey.java @@ -0,0 +1,126 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.policy.pdpgroup; + +import com.google.gson.annotations.Expose; + +import java.io.Serializable; + +public class PolicyModelKey implements Serializable { + + /** + * The serial version ID. + */ + private static final long serialVersionUID = 3307410842013230886L; + + @Expose + private String name; + + @Expose + private String version; + + /** + * Constructor. + */ + public PolicyModelKey(String name, String version) { + this.name = name; + this.version = version; + } + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * version getter. + * + * @return the version + */ + public String getVersion() { + return version; + } + + /** + * version setter. + * + * @param version the version to set + */ + public void setVersion(String version) { + this.version = version; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((version == null) ? 0 : version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + PolicyModelKey other = (PolicyModelKey) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + if (!name.matches(other.name)) { + return false; + } + } + if (version == null) { + if (other.version != null) { + return false; + } + } else if (!version.equals(other.version)) { + return false; + } + return true; + } +} diff --git a/src/main/java/org/onap/clamp/tosca/Dictionary.java b/src/main/java/org/onap/clamp/tosca/Dictionary.java new file mode 100644 index 000000000..cf514c4bd --- /dev/null +++ b/src/main/java/org/onap/clamp/tosca/Dictionary.java @@ -0,0 +1,219 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.tosca; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.onap.clamp.loop.common.AuditEntity; + +/** + * Represents Dictionary. + */ + +@Entity +@Table(name = "dictionary") +public class Dictionary extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388645L; + + @Id + @Expose + @Column(nullable = false, name = "name", unique = true) + private String name; + + @Expose + @Column(name = "dictionary_second_level") + private int secondLevelDictionary = 0; + + @Expose + @Column(name = "dictionary_type") + private String subDictionaryType; + + @Expose + @ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL}) + @JoinTable( + name = "dictionary_to_dictionaryelements", + joinColumns = @JoinColumn(name = "dictionary_name", referencedColumnName = "name"), + inverseJoinColumns = {@JoinColumn( + name = "dictionary_element_short_name", + referencedColumnName = "short_name")}) + private Set<DictionaryElement> dictionaryElements = new HashSet<>(); + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * secondLevelDictionary getter. + * + * @return the secondLevelDictionary + */ + public int getSecondLevelDictionary() { + return secondLevelDictionary; + } + + /** + * secondLevelDictionary setter. + * + * @param secondLevelDictionary the secondLevelDictionary to set + */ + public void setSecondLevelDictionary(int secondLevelDictionary) { + this.secondLevelDictionary = secondLevelDictionary; + } + + /** + * subDictionaryType getter. + * + * @return the subDictionaryType + */ + public String getSubDictionaryType() { + return subDictionaryType; + } + + /** + * subDictionaryType setter. + * + * @param subDictionaryType the subDictionaryType to set + */ + public void setSubDictionaryType(String subDictionaryType) { + this.subDictionaryType = subDictionaryType; + } + + /** + * dictionaryElements getter. + * + * @return the dictionaryElements List of dictionary element + */ + public Set<DictionaryElement> getDictionaryElements() { + return dictionaryElements; + } + + /** + * Method to add a new dictionaryElement to the list. + * + * @param dictionaryElement The dictionary element + */ + public void addDictionaryElements(DictionaryElement dictionaryElement) { + dictionaryElements.add(dictionaryElement); + dictionaryElement.getUsedByDictionaries().add(this); + } + + /** + * Method to set dictionaryElements. + * + * @param dictionaryElements The dictionary elements set + */ + public void setDictionaryElements(Set<DictionaryElement> dictionaryElements) { + this.dictionaryElements = dictionaryElements; + } + + /** + * Method to delete a dictionaryElement from the list. + * + * @param dictionaryElement The dictionary element + */ + public void removeDictionaryElement(DictionaryElement dictionaryElement) { + dictionaryElements.remove(dictionaryElement); + dictionaryElement.getUsedByDictionaries().remove(this); + } + + /** + * Default Constructor. + */ + public Dictionary() { + + } + + /** + * Constructor. + * + * @param name The Dictionary name + * @param secondLevelDictionary defines if dictionary is a secondary level + * @param subDictionaryType defines the type of secondary level dictionary + */ + public Dictionary(String name, int secondLevelDictionary, String subDictionaryType) { + this.name = name; + this.secondLevelDictionary = secondLevelDictionary; + this.subDictionaryType = subDictionaryType; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Dictionary other = (Dictionary) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + return true; + } + +} diff --git a/src/main/java/org/onap/clamp/tosca/DictionaryElement.java b/src/main/java/org/onap/clamp/tosca/DictionaryElement.java new file mode 100644 index 000000000..43a3106f5 --- /dev/null +++ b/src/main/java/org/onap/clamp/tosca/DictionaryElement.java @@ -0,0 +1,254 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.tosca; + +import com.google.gson.annotations.Expose; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.Table; +import org.onap.clamp.loop.common.AuditEntity; + +/** + * Represents a Dictionary Item. + */ +@Entity +@Table(name = "dictionary_elements") +public class DictionaryElement extends AuditEntity implements Serializable { + + /** + * The serial version id. + */ + private static final long serialVersionUID = -286522707701388644L; + + @Id + @Expose + @Column(nullable = false, name = "short_name") + private String shortName; + + @Expose + @Column(nullable = false, name = "name") + private String name; + + @Expose + @Column(nullable = false, name = "description") + private String description; + + @Expose + @Column(nullable = false, name = "type") + private String type; + + @Expose + @Column(nullable = true, name = "subdictionary_name") + private String subDictionary; + + @ManyToMany(mappedBy = "dictionaryElements", fetch = FetchType.EAGER) + private Set<Dictionary> usedByDictionaries = new HashSet<>(); + + /** + * name getter. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * name setter. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * shortName getter. + * + * @return the shortName + */ + public String getShortName() { + return shortName; + } + + /** + * shortName setter. + * + * @param shortName the shortName to set + */ + public void setShortName(String shortName) { + this.shortName = shortName; + } + + /** + * description getter. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * description setter. + * + * @param description the description to set + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * type getter. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * type setter. + * + * @param type the type to set + */ + public void setType(String type) { + this.type = type; + } + + /** + * subDictionary getter. + * + * @return the subDictionary + */ + public String getSubDictionary() { + return subDictionary; + } + + /** + * subDictionary setter. + * + * @param subDictionary the subDictionary to set + */ + public void setSubDictionary(String subDictionary) { + this.subDictionary = subDictionary; + } + + /** + * usedByDictionaries getter. + * + * @return the usedByDictionaries + */ + public Set<Dictionary> getUsedByDictionaries() { + return usedByDictionaries; + } + + /** + * usedByDictionaries setter. + * + * @param usedByDictionaries the usedByDictionaries to set + */ + public void setUsedByDictionaries(Set<Dictionary> usedByDictionaries) { + this.usedByDictionaries = usedByDictionaries; + } + + /** + * Default Constructor. + */ + public DictionaryElement() { + } + + /** + * Constructor. + * + * @param name The Dictionary element name + * @param shortName The short name + * @param description The description + * @param type The type of element + * @param subDictionary The sub type + */ + public DictionaryElement(String name, String shortName, String description, String type, + String subDictionary) { + this.name = name; + this.shortName = shortName; + this.description = description; + this.type = type; + this.subDictionary = subDictionary; + } + + /** + * Constructor. + * + * @param name The Dictionary element name + * @param shortName The short name + * @param description The description + * @param type The type of element + * @param subDictionary The sub type + */ + public DictionaryElement(String name, String shortName, String description, String type, + String subDictionary, Set<Dictionary> usedByDictionaries) { + this.name = name; + this.shortName = shortName; + this.description = description; + this.type = type; + this.subDictionary = subDictionary; + this.usedByDictionaries = usedByDictionaries; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((shortName == null) ? 0 : shortName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + DictionaryElement other = (DictionaryElement) obj; + if (shortName == null) { + if (other.shortName != null) { + return false; + } + } else if (!shortName.equals(other.shortName)) { + return false; + } + return true; + } +} diff --git a/src/main/java/org/onap/clamp/tosca/DictionaryElementsRepository.java b/src/main/java/org/onap/clamp/tosca/DictionaryElementsRepository.java new file mode 100644 index 000000000..43f6f1d40 --- /dev/null +++ b/src/main/java/org/onap/clamp/tosca/DictionaryElementsRepository.java @@ -0,0 +1,32 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.tosca; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DictionaryElementsRepository extends JpaRepository<DictionaryElement, String> { + +} diff --git a/src/main/java/org/onap/clamp/tosca/DictionaryRepository.java b/src/main/java/org/onap/clamp/tosca/DictionaryRepository.java new file mode 100644 index 000000000..ae8430d93 --- /dev/null +++ b/src/main/java/org/onap/clamp/tosca/DictionaryRepository.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.tosca; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface DictionaryRepository extends JpaRepository<Dictionary, String> { + + @Query("SELECT dict.name FROM Dictionary as dict") + List<String> getAllDictionaryNames(); + + @Query("SELECT dict.name FROM Dictionary as dict where dict.secondLevelDictionary = 1") + List<String> getAllSecondaryLevelDictionaryNames(); + +} diff --git a/src/main/java/org/onap/clamp/tosca/DictionaryService.java b/src/main/java/org/onap/clamp/tosca/DictionaryService.java new file mode 100644 index 000000000..6172641a7 --- /dev/null +++ b/src/main/java/org/onap/clamp/tosca/DictionaryService.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.tosca; + +import com.google.common.collect.Sets; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import javax.persistence.EntityNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class DictionaryService { + + private final DictionaryRepository dictionaryRepository; + private final DictionaryElementsRepository dictionaryElementsRepository; + + /** + * Constructor. + */ + @Autowired + public DictionaryService(DictionaryRepository dictionaryRepository, + DictionaryElementsRepository dictionaryElementsRepository) { + this.dictionaryRepository = dictionaryRepository; + this.dictionaryElementsRepository = dictionaryElementsRepository; + + } + + public Dictionary saveOrUpdateDictionary(Dictionary dictionary) { + return dictionaryRepository.saveAndFlush(dictionary); + } + + /** + * Creates or Updates Dictionary Element. + * + * @param dictionaryName The Dictionary name + * @param dictionary The Dictionary object with dictionary elements + * @return updated Dictionary object with all dictionary elements + */ + public Dictionary saveOrUpdateDictionaryElement(String dictionaryName, Dictionary dictionary) { + Dictionary dict = getDictionary(dictionaryName); + + Set<DictionaryElement> newDictionaryElements = dictionary.getDictionaryElements(); + + if (newDictionaryElements != null && !newDictionaryElements.isEmpty()) { + Set<DictionaryElement> updatedDictionaryElements = newDictionaryElements.stream() + .map(dictionaryElement -> getAndUpdateDictionaryElement(dict, dictionaryElement)) + .collect(Collectors.toSet()); + + dict.getDictionaryElements().forEach(dictElement -> { + if (!updatedDictionaryElements.contains(dictElement)) { + updatedDictionaryElements.add(dictElement); + } + }); + dict.setDictionaryElements(updatedDictionaryElements); + } + return dictionaryRepository.saveAndFlush(dict); + + } + + private DictionaryElement getAndUpdateDictionaryElement(Dictionary dictionary, + DictionaryElement element) { + return dictionaryElementsRepository + .save(dictionaryElementsRepository.findById(element.getShortName()) + .map(p -> updateDictionaryElement(p, element, dictionary)) + .orElse(new DictionaryElement(element.getName(), element.getShortName(), + element.getDescription(), element.getType(), element.getSubDictionary(), + Sets.newHashSet(dictionary)))); + } + + public void deleteDictionary(Dictionary dictionary) { + dictionaryRepository.delete(dictionary); + } + + public void deleteDictionary(String dictionaryName) { + dictionaryRepository.deleteById(dictionaryName); + } + + public List<Dictionary> getAllDictionaries() { + return dictionaryRepository.findAll(); + } + + public List<String> getAllSecondaryLevelDictionaryNames() { + return dictionaryRepository.getAllSecondaryLevelDictionaryNames(); + } + + public Dictionary getDictionary(String dictionaryName) { + return dictionaryRepository.findById(dictionaryName).orElseThrow( + () -> new EntityNotFoundException("Couldn't find Dictionary named: " + dictionaryName)); + } + + /** + * Deletes a dictionary element from Dictionary by shortName. + * + * @param dictionaryName The dictionary name + * @param dictionaryElementShortName the dictionary Element Short name + */ + public void deleteDictionaryElement(String dictionaryName, String dictionaryElementShortName) { + if (dictionaryRepository.existsById(dictionaryName)) { + DictionaryElement element = + dictionaryElementsRepository.findById(dictionaryElementShortName).orElse(null); + if (element != null) { + Dictionary dict = getDictionary(dictionaryName); + dict.removeDictionaryElement(element); + dictionaryRepository.saveAndFlush(dict); + } + } + } + + private DictionaryElement updateDictionaryElement(DictionaryElement oldDictionaryElement, + DictionaryElement newDictionaryElement, Dictionary dictionary) { + oldDictionaryElement.setName(newDictionaryElement.getName()); + oldDictionaryElement.setDescription(newDictionaryElement.getDescription()); + oldDictionaryElement.setType(newDictionaryElement.getType()); + oldDictionaryElement.setSubDictionary(newDictionaryElement.getSubDictionary()); + oldDictionaryElement.getUsedByDictionaries().add(dictionary); + return oldDictionaryElement; + } +} diff --git a/src/main/java/org/onap/clamp/util/PassDecoder.java b/src/main/java/org/onap/clamp/util/PassDecoder.java new file mode 100644 index 000000000..b2e4ca2c5 --- /dev/null +++ b/src/main/java/org/onap/clamp/util/PassDecoder.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2019 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.onap.clamp.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import org.onap.aaf.cadi.Symm; +import org.onap.clamp.clds.util.ResourceFileUtils; + +/** + * PassDecoder for decrypting the truststore and keystore password. + */ +public class PassDecoder { + /** + * Used to log PassDecoder class. + */ + private static final EELFLogger logger = EELFManager.getInstance().getLogger(PassDecoder.class); + + /** + * Decode the password. + * + * @param encryptedPass The encrypted password + * @param keyFileName The key file name in String + */ + public static String decode(String encryptedPass, String keyFileName) { + if (null == keyFileName) { + logger.debug("Key file is not defined, thus password will not be decrypted"); + return encryptedPass; + } + if (null == encryptedPass) { + logger.error("Encrypted password is not defined"); + return null; + } + try { + return Symm.obtain(ResourceFileUtils.getResourceAsStream(keyFileName)).depass(encryptedPass); + } catch (IOException e) { + logger.error("Exception occurred during the key decryption", e); + return null; + } + } +} diff --git a/src/main/java/org/onap/clamp/util/SemanticVersioning.java b/src/main/java/org/onap/clamp/util/SemanticVersioning.java new file mode 100644 index 000000000..8852e2a4f --- /dev/null +++ b/src/main/java/org/onap/clamp/util/SemanticVersioning.java @@ -0,0 +1,91 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP CLAMP + * ================================================================================ + * Copyright (C) 2020 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.onap.clamp.util; + +/** + * This class is the base class for object that requires semantic versioning. + * ... This class supports also a.b.c.d... etc ... as a version. + */ +public class SemanticVersioning { + public static final int BEFORE = -1; + public static final int EQUAL = 0; + public static final int AFTER = 1; + public static final String DEFAULT_VERSION = "1.0.0"; + + /** + * The compare method that compare arg0 to arg1. + * + * @param arg0 A version in string for semantic versioning (a.b.c.d...) + * @param arg1 A version in string for semantic versioning (a.b.c.d...) + * @return objects (arg0, arg1) given as parameters. It returns the value: 0: if + * (arg0==arg1) -1: if (arg0 < arg1) 1: if (arg0 > arg1) + */ + public static int compare(String arg0, String arg1) { + + if (arg0 == null && arg1 == null) { + return EQUAL; + } + if (arg0 == null) { + return BEFORE; + } + if (arg1 == null) { + return AFTER; + } + String[] arg0Array = arg0.split("\\."); + String[] arg1Array = arg1.split("\\."); + + int smalestStringLength = Math.min(arg0Array.length, arg1Array.length); + + for (int currentVersionIndex = + 0; currentVersionIndex < smalestStringLength; ++currentVersionIndex) { + if (Integer.parseInt(arg0Array[currentVersionIndex]) < Integer + .parseInt(arg1Array[currentVersionIndex])) { + return BEFORE; + } else if (Integer.parseInt(arg0Array[currentVersionIndex]) > Integer + .parseInt(arg1Array[currentVersionIndex])) { + return AFTER; + } + // equals, so do not return anything, continue + } + if (arg0Array.length == arg1Array.length) { + return EQUAL; + } else { + return Integer.compare(arg0Array.length, arg1Array.length); + } + } + + /** + * Method to increment a version from its current version. + * + * @param currentVersion The current Version + * @return the increment version string + */ + public static String incrementMajorVersion(String currentVersion) { + if (currentVersion == null || currentVersion.isEmpty()) { + return DEFAULT_VERSION; + } + String[] versionArray = currentVersion.split("\\."); + return String.valueOf(Integer.parseInt(versionArray[0]) + 1) + ".0.0"; + } +} |