diff options
author | Shwetank Dave <shwetank.dave@amdocs.com> | 2017-08-02 17:10:38 -0400 |
---|---|---|
committer | Shwetank Dave <shwetank.dave@amdocs.com> | 2017-08-03 11:28:39 -0400 |
commit | e9c94429a8ada3e55854515060df817945b73d87 (patch) | |
tree | 3c5a9ac766d99570d542c1996f1321c99e5498e5 /src/main/java/org/openecomp/schema | |
parent | 27ff75c77611a8bdae37c7c0092787938c63a786 (diff) |
[AAI-26] Adding gizmo data to the repository.
Change-Id: I183f837d45acbfe3c673fde1acf8768d5e3fd37b
Signed-off-by: Shwetank Dave <shwetank.dave@amdocs.com>
Diffstat (limited to 'src/main/java/org/openecomp/schema')
5 files changed, 1130 insertions, 0 deletions
diff --git a/src/main/java/org/openecomp/schema/OxmModelLoader.java b/src/main/java/org/openecomp/schema/OxmModelLoader.java new file mode 100644 index 0000000..4ef77a2 --- /dev/null +++ b/src/main/java/org/openecomp/schema/OxmModelLoader.java @@ -0,0 +1,168 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * 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========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.openecomp.schema; + +import org.eclipse.persistence.jaxb.JAXBContextProperties; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory; +import org.openecomp.cl.eelf.LoggerFactory; +import org.openecomp.crud.exception.CrudException; +import org.openecomp.crud.logging.CrudServiceMsgs; +import org.openecomp.crud.util.CrudServiceConstants; +import org.openecomp.crud.util.FileWatcher; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.ws.rs.core.Response.Status; +import javax.xml.bind.JAXBException; + + +public class OxmModelLoader { + + private static Map<String, DynamicJAXBContext> versionContextMap + = new ConcurrentHashMap<String, DynamicJAXBContext>(); + private static Map<String, Timer> timers = new ConcurrentHashMap<String, Timer>(); + + final static Pattern p = Pattern.compile("aai_oxm_(.*).xml"); + + private static org.openecomp.cl.api.Logger logger = LoggerFactory.getInstance() + .getLogger(OxmModelLoader.class.getName()); + + public synchronized static void loadModels() throws CrudException { + ClassLoader cl = OxmModelLoader.class.getClassLoader(); + ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl); + Resource[] resources; + try { + resources = resolver.getResources("classpath*:/oxm/aai_oxm*.xml"); + } catch (IOException ex) { + logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, ex.getMessage()); + throw new CrudException("", Status.NOT_FOUND); + } + + if (resources.length == 0) { + logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, "No OXM schema files found on classpath"); + throw new CrudException("Failed to load schema", Status.NOT_FOUND); + } + + for (Resource resource : resources) { + Matcher matcher = p.matcher(resource.getFilename()); + + if (matcher.matches()) { + try { + OxmModelLoader.loadModel(matcher.group(1), resource); + } catch (Exception e) { + logger.error(CrudServiceMsgs.OXM_LOAD_ERROR, "Failed to load " + resource.getFilename() + + ": " + e.getMessage()); + throw new CrudException("Failed to load schema", Status.NOT_FOUND); + } + } + } + } + + private static void addtimer(String version, File file) { + TimerTask task = null; + task = new FileWatcher( + file) { + protected void onChange(File file) { + // here we implement the onChange + logger.info(CrudServiceMsgs.OXM_FILE_CHANGED, file.getName()); + + try { + OxmModelLoader.loadModel(version, file); + } catch (Exception e) { + e.printStackTrace(); + } + + } + }; + + if (!timers.containsKey(version)) { + Timer timer = new Timer("oxm-" + version); + timer.schedule(task, new Date(), 10000); + timers.put(version, timer); + + } + } + + private synchronized static void loadModel(String version, File file) + throws JAXBException, IOException { + InputStream inputStream = new FileInputStream(file); + loadModel(version, file.getName(), inputStream); + addtimer(version, file); + } + + private synchronized static void loadModel(String version, Resource resource) + throws JAXBException, IOException { + InputStream inputStream = resource.getInputStream(); + loadModel(version, resource.getFilename(), inputStream); + } + + private synchronized static void loadModel(String version, String resourceName, + InputStream inputStream) + throws JAXBException, IOException { + Map<String, Object> properties = new HashMap<String, Object>(); + properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, inputStream); + final DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory + .createContextFromOXM(Thread.currentThread().getContextClassLoader(), properties); + versionContextMap.put(version, jaxbContext); + logger.info(CrudServiceMsgs.LOADED_OXM_FILE, resourceName); + } + + public static DynamicJAXBContext getContextForVersion(String version) throws CrudException { + if (versionContextMap == null || versionContextMap.isEmpty()) { + loadModels(); + } else if (!versionContextMap.containsKey(version)) { + try { + loadModel(version, new File(CrudServiceConstants.CRD_HOME_MODEL + "aai_oxm_" + + version + ".xml")); + } catch (Exception e) { + throw new CrudException("", Status.NOT_FOUND); + } + } + + return versionContextMap.get(version); + } + + public static Map<String, DynamicJAXBContext> getVersionContextMap() { + return versionContextMap; + } + + public static void setVersionContextMap(Map<String, DynamicJAXBContext> versionContextMap) { + OxmModelLoader.versionContextMap = versionContextMap; + } + +} diff --git a/src/main/java/org/openecomp/schema/OxmModelValidator.java b/src/main/java/org/openecomp/schema/OxmModelValidator.java new file mode 100644 index 0000000..45a2597 --- /dev/null +++ b/src/main/java/org/openecomp/schema/OxmModelValidator.java @@ -0,0 +1,325 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * 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========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.openecomp.schema; + +import com.google.common.base.CaseFormat; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; + +import org.eclipse.persistence.dynamic.DynamicType; +import org.eclipse.persistence.internal.helper.DatabaseField; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.eclipse.persistence.mappings.DatabaseMapping; +import org.eclipse.persistence.oxm.XMLField; +import org.openecomp.crud.entity.Vertex; +import org.openecomp.crud.exception.CrudException; +import org.openecomp.crud.util.CrudServiceUtil; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.ws.rs.core.Response.Status; + +public class OxmModelValidator { + public enum Metadata { + NODE_TYPE("aai-node-type"), + URI("aai-uri"), + CREATED_TS("aai-created-ts"), + SOT("source-of-truth"), + LAST_MOD_SOT("last-mod-source-of-truth"); + + private final String propName; + + Metadata(String propName) { + this.propName = propName; + } + + public String propertyName() { + return propName; + } + + public static boolean isProperty(String property) { + for (Metadata meta : Metadata.values()) { + if (meta.propName.equals(property)) { + return true; + } + } + return false; + } + } + + + public static Map<String, Object> resolveCollectionfilter(String version, String type, + Map<String, String> filter) + throws CrudException { + + DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); + + Map<String, Object> result = new HashMap<String, Object>(); + if (jaxbContext == null) { + throw new CrudException("", Status.NOT_FOUND); + } + final DynamicType modelObjectType = jaxbContext.getDynamicType(CaseFormat.LOWER_CAMEL + .to(CaseFormat.UPPER_CAMEL, + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type))); + + for (String key : filter.keySet()) { + String keyJavaName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, key); + if (modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName) != null) { + try { + DatabaseMapping mapping = modelObjectType.getDescriptor() + .getMappingForAttributeName(keyJavaName); + Object value = CrudServiceUtil.validateFieldType(filter.get(key), + mapping.getField().getType()); + result.put(key, value); + } catch (Exception ex) { + // Skip any exceptions thrown while validating the filter + // key value + continue; + } + } + } + + return result; + + } + + public static String resolveCollectionType(String version, String type) throws CrudException { + + DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); + + if (jaxbContext == null) { + throw new CrudException("", Status.NOT_FOUND); + } + // Determine if the Object part is a collection type in the model + // definition + final DynamicType modelObjectType = jaxbContext.getDynamicType(CaseFormat.LOWER_CAMEL + .to(CaseFormat.UPPER_CAMEL, + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type))); + + if (modelObjectType == null) { + throw new CrudException("", Status.NOT_FOUND); + } + + if (modelObjectType.getDescriptor().getMappings().size() == 1 + && modelObjectType.getDescriptor().getMappings().get(0).isCollectionMapping()) { + String childJavaObjectName = modelObjectType.getDescriptor().getMappings() + .get(0).getAttributeName(); + childJavaObjectName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, childJavaObjectName); + final DynamicType childObjectType = jaxbContext.getDynamicType(childJavaObjectName); + if (childObjectType == null) { + // Should not happen as child object is defined in oxm model + // itself + throw new CrudException("", Status.NOT_FOUND); + } + return childObjectType.getDescriptor().getTableName(); + } else { + return modelObjectType.getDescriptor().getTableName(); + } + + } + + + public static Vertex validateIncomingUpsertPayload(String id, String version, String type, + JsonElement properties) + throws CrudException { + + try { + type = resolveCollectionType(version, type); + DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); + String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type)); + + final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass); + + Set<Map.Entry<String, JsonElement>> payloadEntriesSet = properties.getAsJsonObject() + .entrySet(); + + //loop through input to validate against schema + for (Map.Entry<String, JsonElement> entry : payloadEntriesSet) { + String keyJavaName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, entry.getKey()); + + // check for valid field + if (modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName) == null) { + throw new CrudException("Invalid field: " + entry.getKey(), Status.BAD_REQUEST); + } + + } + + Map<String, JsonElement> entriesMap = new HashMap<String, JsonElement>(); + for (Map.Entry<String, JsonElement> entry : payloadEntriesSet) { + entriesMap.put(entry.getKey(), entry.getValue()); + } + + Vertex.Builder modelVertexBuilder = new Vertex.Builder(type); + if (id != null) { + modelVertexBuilder.id(id); + } + for (DatabaseMapping mapping : modelObjectType.getDescriptor().getMappings()) { + if (mapping.isAbstractDirectMapping()) { + DatabaseField field = mapping.getField(); + String defaultValue = mapping.getProperties().get("defaultValue") == null ? "" + : mapping.getProperties().get("defaultValue").toString(); + + String keyName = field.getName().substring(0, field.getName().indexOf("/")); + + if (((XMLField) field).isRequired() && !entriesMap.containsKey(keyName) + && !defaultValue.isEmpty()) { + modelVertexBuilder.property(keyName, + CrudServiceUtil.validateFieldType(defaultValue, field.getType())); + } + // if schema field is required and not set then reject + if (((XMLField) field).isRequired() && !entriesMap.containsKey(keyName) + && defaultValue.isEmpty()) { + throw new CrudException("Missing required field: " + keyName, Status.BAD_REQUEST); + } + // If invalid field then reject + if (entriesMap.containsKey(keyName)) { + Object value = CrudServiceUtil.validateFieldType(entriesMap.get(keyName) + .getAsString(), field.getType()); + modelVertexBuilder.property(keyName, value); + } + + // Set defaults + if (!defaultValue.isEmpty() && !entriesMap.containsKey(keyName)) { + modelVertexBuilder.property(keyName, + CrudServiceUtil.validateFieldType(defaultValue, field.getType())); + } + } + } + + return modelVertexBuilder.build(); + } catch (Exception e) { + throw new CrudException(e.getMessage(), Status.BAD_REQUEST); + } + } + + public static Vertex validateIncomingPatchPayload(String id, String version, String type, + JsonElement properties, Vertex existingVertex) + throws CrudException { + + try { + type = resolveCollectionType(version, type); + DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); + String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, type)); + + final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass); + + Set<Map.Entry<String, JsonElement>> payloadEntriesSet = properties.getAsJsonObject() + .entrySet(); + + // Loop through the payload properties and merge with existing + // vertex props + for (Map.Entry<String, JsonElement> entry : payloadEntriesSet) { + + String keyJavaName = CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, entry.getKey()); + + // check for valid field + if (modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName) == null) { + throw new CrudException("Invalid field: " + entry.getKey(), Status.BAD_REQUEST); + } + + DatabaseField field = modelObjectType.getDescriptor() + .getMappingForAttributeName(keyJavaName).getField(); + String defaultValue = modelObjectType.getDescriptor() + .getMappingForAttributeName(keyJavaName) + .getProperties().get("defaultValue") == null ? "" + : modelObjectType.getDescriptor().getMappingForAttributeName(keyJavaName) + .getProperties().get("defaultValue").toString(); + + // check if mandatory field is not set to null + if (((XMLField) field).isRequired() && entry.getValue() instanceof JsonNull + && !defaultValue.isEmpty()) { + existingVertex.getProperties().put(entry.getKey(), + CrudServiceUtil.validateFieldType(defaultValue, field.getType())); + } else if (((XMLField) field).isRequired() && entry.getValue() instanceof JsonNull + && defaultValue.isEmpty()) { + throw new CrudException("Mandatory field: " + entry.getKey() + + " can't be set to null", + Status.BAD_REQUEST); + } else if (!((XMLField) field).isRequired() && entry.getValue() instanceof JsonNull + && existingVertex.getProperties().containsKey(entry.getKey())) { + existingVertex.getProperties().remove(entry.getKey()); + } else if (!(entry.getValue() instanceof JsonNull)) { + // add/update the value if found in existing vertex + Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(), + field.getType()); + existingVertex.getProperties().put(entry.getKey(), value); + } + + } + + return existingVertex; + } catch (Exception e) { + throw new CrudException(e.getMessage(), Status.BAD_REQUEST); + } + + } + + private static DatabaseField getDatabaseField(String fieldName, DynamicType modelObjectType) { + for (DatabaseField field : modelObjectType.getDescriptor().getAllFields()) { + int ix = field.getName().indexOf("/"); + if (ix <= 0) { + ix = field.getName().length(); + } + + String keyName = field.getName().substring(0, ix); + if (fieldName.equals(keyName)) { + return field; + } + } + return null; + } + + public static Vertex validateOutgoingPayload(String version, Vertex vertex) { + + Vertex.Builder modelVertexBuilder = new Vertex.Builder(vertex.getType()) + .id(vertex.getId().get()); + + try { + DynamicJAXBContext jaxbContext = OxmModelLoader.getContextForVersion(version); + String modelObjectClass = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, + vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()) != null + ? vertex.getProperties().get(Metadata.NODE_TYPE.propertyName()).toString() : vertex.getType())); + final DynamicType modelObjectType = jaxbContext.getDynamicType(modelObjectClass); + + for (String key : vertex.getProperties().keySet()) { + DatabaseField field = getDatabaseField(key, modelObjectType); + if (field != null) { + if (!Metadata.isProperty(key)) { + modelVertexBuilder.property(key, vertex.getProperties().get(key)); + } + } + } + return modelVertexBuilder.build(); + } catch (Exception ex) { + return vertex; + } + + } + + +} diff --git a/src/main/java/org/openecomp/schema/RelationshipSchema.java b/src/main/java/org/openecomp/schema/RelationshipSchema.java new file mode 100644 index 0000000..5b28e28 --- /dev/null +++ b/src/main/java/org/openecomp/schema/RelationshipSchema.java @@ -0,0 +1,138 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * 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========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.openecomp.schema; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.openecomp.crud.exception.CrudException; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.ws.rs.core.Response.Status; + +public class RelationshipSchema { + private static final Gson gson = new GsonBuilder().create(); + + public static final String SCHEMA_SOURCE_NODE_TYPE = "source-node-type"; + public static final String SCHEMA_TARGET_NODE_TYPE = "target-node-type"; + public static final String SCHEMA_RELATIONSHIP_TYPE = "relationship-type"; + public static final String SCHEMA_RELATIONSHIP_TYPES_ARRAY = "relationship-types"; + public static final String SCHEMA_RELATIONSHIP_PROPERTIES = "properties"; + public static final String SCHEMA_RELATIONS_ARRAY = "relations"; + + /** + * key = source-node-type:target-node-type:relationship-type value = map of properties with name + * and type . Like propertyName:PropertyType + */ + private HashMap<String, HashMap<String, Class<?>>> relations + = new HashMap<String, HashMap<String, Class<?>>>(); + /** + * Hashmap of valid relationship types alongwith properrties. + */ + private HashMap<String, HashMap<String, Class<?>>> relationTypes + = new HashMap<String, HashMap<String, Class<?>>>(); + + + public RelationshipSchema(String json) throws CrudException { + + JsonParser parser = new JsonParser(); + try { + JsonObject root = parser.parse(json).getAsJsonObject(); + JsonArray relationshipTypesArray = root.getAsJsonArray(SCHEMA_RELATIONSHIP_TYPES_ARRAY); + JsonArray relationsArray = root.getAsJsonArray(SCHEMA_RELATIONS_ARRAY); + + //First load all the relationship-types + for (JsonElement item : relationshipTypesArray) { + JsonObject obj = item.getAsJsonObject(); + String type = obj.get(SCHEMA_RELATIONSHIP_TYPE).getAsString(); + + + HashMap<String, Class<?>> props = new HashMap<String, Class<?>>(); + Set<Map.Entry<String, JsonElement>> entries = obj.get(SCHEMA_RELATIONSHIP_PROPERTIES) + .getAsJsonObject().entrySet(); + + for (Map.Entry<String, JsonElement> entry : entries) { + props.put(entry.getKey(), resolveClass(entry.getValue().getAsString())); + + } + relationTypes.put(type, props); + + } + + for (JsonElement item : relationsArray) { + JsonObject obj = item.getAsJsonObject(); + // Parse the Source/Taget nodeTypes + + String relationType = obj.get(SCHEMA_RELATIONSHIP_TYPE).getAsString(); + String key = obj.get(SCHEMA_SOURCE_NODE_TYPE).getAsString() + ":" + + obj.get(SCHEMA_TARGET_NODE_TYPE).getAsString() + ":" + relationType; + + + if (!relationTypes.containsKey(relationType)) { + throw new CrudException(SCHEMA_RELATIONSHIP_TYPE + ": " + relationType + " not found", + Status.BAD_REQUEST); + } + + relations.put(key, relationTypes.get(relationType)); + } + } catch (Exception e) { + throw new CrudException(e.getMessage(), Status.BAD_REQUEST); + } + + } + + + public HashMap<String, Class<?>> lookupRelation(String key) { + return this.relations.get(key); + } + + public HashMap<String, Class<?>> lookupRelationType(String type) { + return this.relationTypes.get(type); + } + + public boolean isValidType(String type) { + return relationTypes.containsKey(type); + } + + private Class<?> resolveClass(String type) throws CrudException, ClassNotFoundException { + Class<?> clazz = Class.forName(type); + validateClassTypes(clazz); + return clazz; + } + + private void validateClassTypes(Class<?> clazz) throws CrudException { + if (!clazz.isAssignableFrom(Integer.class) && !clazz.isAssignableFrom(Double.class) + && !clazz.isAssignableFrom(Boolean.class) && !clazz.isAssignableFrom(String.class)) { + throw new CrudException("", Status.BAD_REQUEST); + } + } + + +} diff --git a/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java b/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java new file mode 100644 index 0000000..51b33d0 --- /dev/null +++ b/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java @@ -0,0 +1,158 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * 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========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.openecomp.schema; + +import org.apache.commons.io.IOUtils; +import org.openecomp.cl.eelf.LoggerFactory; +import org.openecomp.crud.exception.CrudException; +import org.openecomp.crud.logging.CrudServiceMsgs; +import org.openecomp.crud.util.CrudServiceConstants; +import org.openecomp.crud.util.FileWatcher; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; +import java.util.Timer; +import java.util.TimerTask; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.ws.rs.core.Response.Status; +import javax.xml.bind.JAXBException; + + +public class RelationshipSchemaLoader { + + private static Map<String, RelationshipSchema> versionContextMap + = new ConcurrentHashMap<String, RelationshipSchema>(); + private static SortedSet<Integer> versions = new TreeSet<Integer>(); + private static Map<String, Timer> timers = new ConcurrentHashMap<String, Timer>(); + + final static Pattern filePattern = Pattern.compile("aai_relationship_(.*).json"); + + + private static org.openecomp.cl.api.Logger logger = LoggerFactory.getInstance() + .getLogger(RelationshipSchemaLoader.class.getName()); + + public synchronized static void loadModels() { + + File[] listOfFiles = new File(CrudServiceConstants.CRD_HOME_MODEL).listFiles(); + + if (listOfFiles != null) { + for (File file : listOfFiles) { + if (file.isFile()) { + Matcher matcher = filePattern.matcher(file.getName()); + if (matcher.matches()) { + try { + RelationshipSchemaLoader.loadModel(matcher.group(1), file); + } catch (Exception e) { + logger.error(CrudServiceMsgs.INVALID_OXM_FILE, file.getName(), e.getMessage()); + } + } + + } + } + } else { + logger.error(CrudServiceMsgs.INVALID_OXM_DIR, CrudServiceConstants.CRD_HOME_MODEL); + } + + + } + + private static void addtimer(String version, File file) { + TimerTask task = null; + task = new FileWatcher( + file) { + protected void onChange(File file) { + // here we implement the onChange + logger.info(CrudServiceMsgs.OXM_FILE_CHANGED, file.getName()); + + try { + RelationshipSchemaLoader.loadModel(version, file); + } catch (Exception e) { + e.printStackTrace(); + } + + } + }; + + if (!timers.containsKey(version)) { + Timer timer = new Timer("aai_relationship_" + version); + timer.schedule(task, new Date(), 10000); + timers.put(version, timer); + + } + } + + private synchronized static void loadModel(String version, File file) + throws JAXBException, IOException, CrudException { + + InputStream inputStream = new FileInputStream(file); + String content = IOUtils.toString(inputStream, "UTF-8"); + versionContextMap.put(version, new RelationshipSchema(content)); + addtimer(version, file); + versions.add(Integer.parseInt(version.substring(1))); + } + + public static RelationshipSchema getSchemaForVersion(String version) throws CrudException { + if (versionContextMap == null || versionContextMap.isEmpty()) { + loadModels(); + } else if (!versionContextMap.containsKey(version)) { + try { + loadModel(version, new File(CrudServiceConstants.CRD_HOME_MODEL + "aai_relationship_" + + version + ".json")); + } catch (Exception e) { + throw new CrudException("", Status.NOT_FOUND); + } + } + + return versionContextMap.get(version); + } + + public static String getLatestSchemaVersion() throws CrudException { + return "v" + versions.last(); + } + + public static Map<String, RelationshipSchema> getVersionContextMap() { + return versionContextMap; + } + + public static void setVersionContextMap(HashMap<String, RelationshipSchema> versionContextMap) { + RelationshipSchemaLoader.versionContextMap = versionContextMap; + } + + public static void main(String[] args) throws FileNotFoundException, Exception { + File initialFile = new File("C:\\Software\\gizmo\\src\\main\\java\\org\\openecomp\\schema\\vio.json"); + + loadModel("v8", initialFile); + } + +} diff --git a/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java b/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java new file mode 100644 index 0000000..552b60a --- /dev/null +++ b/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java @@ -0,0 +1,341 @@ +/** + * ============LICENSE_START======================================================= + * Gizmo + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. + * Copyright © 2017 Amdocs + * 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========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.openecomp.schema; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; + +import org.openecomp.crud.entity.Edge; +import org.openecomp.crud.entity.Vertex; +import org.openecomp.crud.exception.CrudException; +import org.openecomp.crud.service.EdgePayload; +import org.openecomp.crud.util.CrudServiceUtil; +import org.radeox.util.logging.Logger; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.ws.rs.core.Response.Status; + +public class RelationshipSchemaValidator { + + public static final String SOURCE_NODE = "source"; + public static final String TARGET_NODE = "target"; + + final static Pattern urlPattern = Pattern.compile("services/inventory/(.*)/(.*)/(.*)"); + + public static Map<String, Object> resolveCollectionfilter(String version, String type, + Map<String, String> filter) + throws CrudException { + + RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version); + if (schema == null) { + throw new CrudException("", Status.NOT_FOUND); + } + + HashMap<String, Class<?>> props = schema.lookupRelationType(type); + Map<String, Object> result = new HashMap<String, Object>(); + + for (String key : filter.keySet()) { + + if (props.containsKey(key)) { + try { + Object value = CrudServiceUtil.validateFieldType(filter.get(key), props.get(key)); + result.put(key, value); + } catch (Exception ex) { + // Skip any exceptions thrown while validating the filter + // key value + continue; + } + } + } + + return result; + + } + + public static void validateType(String version, String type) throws CrudException { + + RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version); + if (!schema.isValidType(type)) { + throw new CrudException("Invalid " + RelationshipSchema.SCHEMA_RELATIONSHIP_TYPE + + ": " + type, + Status.BAD_REQUEST); + } + + } + + public static Edge validateIncomingAddPayload(String version, String type, Vertex sourceNode, + Vertex targetNode, JsonElement properties) + throws CrudException { + EdgePayload payload = new EdgePayload(); + payload.setSource("services/inventory/" + version + "/" + sourceNode.getType() + + "/" + sourceNode.getId().get()); + payload.setTarget("services/inventory/" + version + "/" + targetNode.getType() + + "/" + targetNode.getId().get()); + payload.setType(type); + payload.setProperties(properties); + return validateIncomingAddPayload(version, type, payload); + } + + public static Edge validateIncomingAddPayload(String version, String type, EdgePayload payload) + throws CrudException { + RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version); + + try { + + if (payload.getSource() == null || payload.getTarget() == null) { + throw new CrudException("Source/Target not specified", Status.BAD_REQUEST); + } + + Matcher sourceMatcher = urlPattern.matcher(payload.getSource()); + Matcher targetMatcher = urlPattern.matcher(payload.getTarget()); + + if (!sourceMatcher.matches() || !targetMatcher.matches()) { + throw new CrudException("Invalid Source/Target Urls", Status.BAD_REQUEST); + } + + // create key based on source:target:relationshipType + String sourceNodeType = sourceMatcher.group(2); + String targetNodeType = targetMatcher.group(2); + + String sourceNodeId = sourceMatcher.group(3); + String targetNodeId = targetMatcher.group(3); + + String key = sourceNodeType + ":" + targetNodeType + ":" + type; + + // find the validate the key from the schema + HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key); + + if (schemaObject == null) { + throw new CrudException("Invalid source/target/relationship type: " + key, + Status.BAD_REQUEST); + } + + Edge.Builder modelEdgeBuilder = new Edge.Builder(type); + + modelEdgeBuilder.source(new Vertex.Builder(sourceNodeType).id(sourceNodeId).build()); + modelEdgeBuilder.target(new Vertex.Builder(targetNodeType).id(targetNodeId).build()); + + // validate it properties + validateEdgeProps(modelEdgeBuilder, payload.getProperties(), schemaObject); + + return modelEdgeBuilder.build(); + } catch (Exception ex) { + + throw new CrudException(ex.getMessage(), Status.BAD_REQUEST); + } + + } + + public static Edge validateIncomingPatchPayload(Edge edge, String version, EdgePayload payload) + throws CrudException { + RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version); + + try { + if (payload.getSource() != null) { + Matcher sourceMatcher = urlPattern.matcher(payload.getSource()); + + if (!sourceMatcher.matches()) { + throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST); + } + String sourceNodeId = sourceMatcher.group(3); + if (!sourceNodeId.equals(edge.getSource().getId().get())) { + throw new CrudException("Source can't be updated", Status.BAD_REQUEST); + } + } + + if (payload.getTarget() != null) { + Matcher targetMatcher = urlPattern.matcher(payload.getTarget()); + + if (!targetMatcher.matches()) { + throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST); + } + String sourceNodeId = targetMatcher.group(3); + if (!sourceNodeId.equals(edge.getTarget().getId().get())) { + throw new CrudException("Target can't be updated", Status.BAD_REQUEST); + } + } + // create key based on source:target:relationshipType + + String key = edge.getSource().getType() + ":" + edge.getTarget().getType() + + ":" + edge.getType(); + + // find the validate the key from the schema + HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key); + + if (schemaObject == null) { + Logger.warn("key :" + key + + " not found in relationship schema . Skipping the schema validation"); + return edge; + } + + Set<Map.Entry<String, JsonElement>> entries = payload.getProperties() + .getAsJsonObject().entrySet(); + + for (Map.Entry<String, JsonElement> entry : entries) { + + if (!schemaObject.containsKey(entry.getKey())) { + throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST); + } else if (entry.getValue() instanceof JsonNull && edge.getProperties() + .containsKey(entry.getKey())) { + edge.getProperties().remove(entry.getKey()); + } else if (!(entry.getValue() instanceof JsonNull)) { + Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(), + schemaObject.get(entry.getKey())); + edge.getProperties().put(entry.getKey(), value); + } + + } + + return edge; + + } catch (Exception ex) { + + throw new CrudException(ex.getMessage(), Status.BAD_REQUEST); + } + } + + public static Edge validateIncomingUpdatePayload(Edge edge, String version, Vertex sourceNode, + Vertex targetNode, JsonElement properties) + throws CrudException { + EdgePayload payload = new EdgePayload(); + payload.setSource("services/inventory/" + version + "/" + sourceNode.getType() + + "/" + sourceNode.getId().get()); + payload.setTarget("services/inventory/" + version + "/" + targetNode.getType() + + "/" + targetNode.getId().get()); + payload.setType(edge.getType()); + payload.setProperties(properties); + return validateIncomingUpdatePayload(edge, version, payload); + } + + public static Edge validateIncomingUpdatePayload(Edge edge, String version, EdgePayload payload) + throws CrudException { + RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version); + + try { + + if (payload.getSource() != null) { + Matcher sourceMatcher = urlPattern.matcher(payload.getSource()); + + if (!sourceMatcher.matches()) { + throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST); + } + String sourceNodeId = sourceMatcher.group(3); + if (!sourceNodeId.equals(edge.getSource().getId().get())) { + throw new CrudException("Source can't be updated", Status.BAD_REQUEST); + } + } + + if (payload.getTarget() != null) { + Matcher targetMatcher = urlPattern.matcher(payload.getTarget()); + + if (!targetMatcher.matches()) { + throw new CrudException("Invalid Target Urls", Status.BAD_REQUEST); + } + String sourceNodeId = targetMatcher.group(3); + if (!sourceNodeId.equals(edge.getTarget().getId().get())) { + throw new CrudException("Target can't be updated", Status.BAD_REQUEST); + } + } + // create key based on source:target:relationshipType + + String key = edge.getSource().getType() + ":" + edge.getTarget().getType() + + ":" + edge.getType(); + + // find the validate the key from the schema + HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key); + + if (schemaObject == null) { + Logger.warn("key :" + key + + " not found in relationship schema . Skipping the schema validation"); + return edge; + } + + Edge.Builder updatedEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId().get()); + + updatedEdgeBuilder + .source(new Vertex.Builder(edge.getSource().getType()).id(edge.getSource().getId() + .get()).build()); + updatedEdgeBuilder + .target(new Vertex.Builder(edge.getTarget().getType()).id(edge.getTarget().getId() + .get()).build()); + + validateEdgeProps(updatedEdgeBuilder, payload.getProperties(), schemaObject); + + return updatedEdgeBuilder.build(); + } catch (Exception ex) { + + throw new CrudException(ex.getMessage(), Status.BAD_REQUEST); + } + } + + + private static void validateEdgeProps(Edge.Builder builder, JsonElement props, + HashMap<String, Class<?>> schemaObject) + throws CrudException { + Set<Map.Entry<String, JsonElement>> entries = props.getAsJsonObject().entrySet(); + + for (Map.Entry<String, JsonElement> entry : entries) { + + if (!schemaObject.containsKey(entry.getKey())) { + throw new CrudException("Invalid property: " + entry.getKey(), Status.BAD_REQUEST); + } else { + Object value = CrudServiceUtil.validateFieldType(entry.getValue().getAsString(), + schemaObject.get(entry.getKey())); + builder.property(entry.getKey(), value); + } + + } + + } + + public static Edge validateOutgoingPayload(String version, Edge edge) throws CrudException { + + Edge.Builder modelEdgeBuilder = new Edge.Builder(edge.getType()).id(edge.getId() + .get()).source(edge.getSource()) + .target(edge.getTarget()); + + RelationshipSchema schema = RelationshipSchemaLoader.getSchemaForVersion(version); + + String key = edge.getSource().getType() + ":" + edge.getTarget().getType() + + ":" + edge.getType(); + HashMap<String, Class<?>> schemaObject = schema.lookupRelation(key); + + if (schemaObject == null || schemaObject.isEmpty()) { + return edge; + } + + for (String prop : edge.getProperties().keySet()) { + if (schemaObject.containsKey(prop)) { + modelEdgeBuilder.property(prop, edge.getProperties().get(prop)); + } + + } + return modelEdgeBuilder.build(); + } + +} |