/*
* ============LICENSE_START=======================================================
* 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.
*
* SPDX-License-Identifier: Apache-2.0
* ============LICENSE_END=========================================================
*/
package org.onap.policy.drools.policies;
import com.worldturner.medeia.api.ValidationFailedException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.onap.policy.common.utils.coder.CoderException;
import org.onap.policy.common.utils.coder.StandardCoder;
import org.onap.policy.common.utils.coder.StandardValCoder;
import org.onap.policy.common.utils.resources.ResourceUtils;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Converts Tosca Policies into Domain policies.
*
*
* A Domain Policy is a specialized version of the Tosca Policy that
* conform with a particular domain specification in json schema format.
* A ToscaPolicy is a generic data structure where domain data is contained
* in a Map[String, Object]. This class contains that generic information
* into a concrete domain specific data model for the ToscaPolicy.
*
*/
@NoArgsConstructor
public class DomainMaker {
private static final Logger logger = LoggerFactory.getLogger(DomainMaker.class);
/**
* policy-type -> schema validator map.
*/
private final Map validators = new ConcurrentHashMap<>();
/**
* non-validation serialization coder.
*/
private final StandardCoder nonValCoder = new StandardCoder();
/**
* Does this json conform to a registered policy type schema?.
*/
public boolean isConformant(@NonNull ToscaPolicyTypeIdentifier policyType, @NonNull String json) {
if (!isRegistered(policyType)) {
return false;
}
return validators.get(policyType).isConformant(json);
}
/**
* Does this policy conform to its domain specification?.
*/
public boolean isConformant(@NonNull ToscaPolicy policy) {
String rawPolicy = serialize(policy);
if (StringUtils.isBlank(rawPolicy)) {
return false;
}
return isConformant(policy.getTypeIdentifier(), rawPolicy);
}
/**
* Does this domain policy conforms to its schema definition?.
*/
public boolean isDomainConformant(@NonNull ToscaPolicyTypeIdentifier policyType, @NonNull T domainPolicy) {
if (!isRegistered(policyType)) {
return false;
}
try {
return validators.get(policyType).encode(domainPolicy) != null;
} catch (CoderException e) {
logger.info("policy {}:{} is not conformant", policyType, domainPolicy.getClass().getName(), e);
return false;
}
}
/**
* Check policy conformance to its specification providing a list of errors
* in a ValidationFailedException.
*/
public boolean conformance(@NonNull ToscaPolicy policy) {
if (!isRegistered(policy.getTypeIdentifier())) {
return false;
}
String rawPolicy = serialize(policy);
if (StringUtils.isBlank(rawPolicy)) {
return false;
}
try {
validators.get(policy.getTypeIdentifier()).conformance(rawPolicy);
} catch (CoderException e) {
logger.info("policy {}:{}:{} is not conformant",
policy.getTypeIdentifier(), policy.getName(), policy.getVersion(), e);
if (e.getCause() instanceof ValidationFailedException) {
throw (ValidationFailedException) e.getCause();
}
return false;
}
return true;
}
/**
* Checks a domain policy conformance to its specification providing a list of errors
* in a ValidationFailedException.
*/
public boolean conformance(@NonNull ToscaPolicyTypeIdentifier policyType, T domainPolicy) {
if (!isRegistered(policyType)) {
return false;
}
try {
validators.get(policyType).encode(domainPolicy);
} catch (CoderException e) {
logger.info("policy {}:{} is not conformant", policyType, domainPolicy.getClass().getName(), e);
if (e.getCause() instanceof ValidationFailedException) {
throw (ValidationFailedException) e.getCause();
}
return false;
}
return true;
}
/**
* Registers a known schema resource for validation.
*/
public boolean registerValidator(@NonNull ToscaPolicyTypeIdentifier policyType) {
//
// A known schema is one that embedded in a .jar in the classpath as a resource
// matching the following syntax: -.schema.json.
//
String schema =
ResourceUtils
.getResourceAsString("schemas/"
+ policyType.getName() + "-" + policyType.getVersion() + ".schema.json");
if (schema == null) {
return false;
}
return registerValidator(policyType, schema);
}
/**
* Registers/Overrides a new/known schema for a policy type.
*/
public boolean registerValidator(@NonNull ToscaPolicyTypeIdentifier policyType, @NonNull String schema) {
try {
validators.put(policyType, new StandardValCoder(schema, policyType.toString()));
} catch (RuntimeException r) {
logger.info("schema for {} is not valid", policyType, r);
return false;
}
return true;
}
/**
* Converts a ToscaPolicy into a Domain Policy.
*/
public T convertTo(@NonNull ToscaPolicy toscaPolicy, @NonNull Class clazz) throws CoderException {
return convertTo(toscaPolicy.getTypeIdentifier(), nonValCoder.encode(toscaPolicy), clazz);
}
/**
* Converts a JSON policy into a Domain Policy.
*/
public T convertTo(@NonNull ToscaPolicyTypeIdentifier policyType, @NonNull String json, @NonNull Class clazz)
throws CoderException {
if (isRegistered(policyType)) {
return validators.get(policyType).decode(json, clazz);
} else {
return nonValCoder.decode(json, clazz);
}
}
/**
* Converts a Tosca Policy Type specification to a domain-specific json specification.
*/
public String convertToSchema(@NonNull ToscaPolicyType policyType) {
//
// TODO:
// 1. Convert Tosca Policy Type definition schema to suitable json schema.
// 2. Call registerValidator to register
throw new UnsupportedOperationException("schema generation from policy type is not supported");
}
public boolean isRegistered(@NonNull ToscaPolicyTypeIdentifier policyType) {
return validators.containsKey(policyType) || registerValidator(policyType);
}
private String serialize(@NonNull ToscaPolicy policy) {
String rawPolicy = null;
try {
rawPolicy = nonValCoder.encode(policy);
} catch (CoderException e) {
logger.debug("policy {}:{} is invalid json", policy.getTypeIdentifier(), policy.getIdentifier(), e);
}
return rawPolicy;
}
}