From 7e69be504213aa92893fd3354a767128b3a583f1 Mon Sep 17 00:00:00 2001 From: Shwetank Dave Date: Tue, 22 Aug 2017 10:36:30 -0400 Subject: Using DbEdgeRules.json files from aai-core jar. Before we were aai_relationship_vxx.json files. Now using the edge rules directly from aai-core jar. Issue-ID: AAI-21 Change-Id: Id62494caabc75bc29e4f3558268ec78897946937 Signed-off-by: Shwetank Dave --- .../org/openecomp/schema/RelationshipSchema.java | 108 ++++----- .../openecomp/schema/RelationshipSchemaLoader.java | 243 ++++++++++++++------- .../schema/RelationshipSchemaValidator.java | 12 +- 3 files changed, 209 insertions(+), 154 deletions(-) (limited to 'src/main') diff --git a/src/main/java/org/openecomp/schema/RelationshipSchema.java b/src/main/java/org/openecomp/schema/RelationshipSchema.java index 5b28e28..a8d101d 100644 --- a/src/main/java/org/openecomp/schema/RelationshipSchema.java +++ b/src/main/java/org/openecomp/schema/RelationshipSchema.java @@ -25,95 +25,60 @@ 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.codehaus.jackson.map.ObjectMapper; import org.openecomp.crud.exception.CrudException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; 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"; + public static final String SCHEMA_SOURCE_NODE_TYPE = "from"; + public static final String SCHEMA_TARGET_NODE_TYPE = "to"; + public static final String SCHEMA_RELATIONSHIP_TYPE = "label"; + public static final String SCHEMA_RULES_ARRAY = "rules"; + + private Map>> relations = new HashMap<>(); /** - * key = source-node-type:target-node-type:relationship-type value = map of properties with name - * and type . Like propertyName:PropertyType - */ - private HashMap>> relations - = new HashMap>>(); - /** - * Hashmap of valid relationship types alongwith properrties. + * Hashmap of valid relationship types along with properties. */ - private HashMap>> relationTypes - = new HashMap>>(); - - - public RelationshipSchema(String json) throws CrudException { + private Map>> relationTypes = new HashMap<>(); - 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> props = new HashMap>(); - Set> entries = obj.get(SCHEMA_RELATIONSHIP_PROPERTIES) - .getAsJsonObject().entrySet(); - - for (Map.Entry entry : entries) { - props.put(entry.getKey(), resolveClass(entry.getValue().getAsString())); - - } - relationTypes.put(type, props); + public RelationshipSchema(List jsonStrings) throws CrudException, IOException { + String edgeRules = jsonStrings.get(0); + String props = jsonStrings.get(1); + HashMap>> rules = new ObjectMapper().readValue(edgeRules, HashMap.class); + HashMap properties = new ObjectMapper().readValue(props, HashMap.class); + Map> edgeProps = properties.entrySet().stream().collect(Collectors.toMap(p -> p.getKey(), p -> { + try { + return resolveClass(p.getValue()); + } catch (CrudException | ClassNotFoundException e) { + e.printStackTrace(); } + return null; + })); - 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); - } - + rules.get(SCHEMA_RULES_ARRAY).forEach(l -> { + relationTypes.put(l.get(SCHEMA_RELATIONSHIP_TYPE), edgeProps); + relations.put(buildRelation(l.get(SCHEMA_SOURCE_NODE_TYPE), l.get(SCHEMA_TARGET_NODE_TYPE), l.get(SCHEMA_RELATIONSHIP_TYPE)), edgeProps); + }); } - public HashMap> lookupRelation(String key) { + + public Map> lookupRelation(String key) { return this.relations.get(key); } - public HashMap> lookupRelationType(String type) { + public Map> lookupRelationType(String type) { return this.relationTypes.get(type); } @@ -121,6 +86,11 @@ public class RelationshipSchema { return relationTypes.containsKey(type); } + + private String buildRelation(String source, String target, String relation){ + return source + ":" + target + ":" + relation; + } + private Class resolveClass(String type) throws CrudException, ClassNotFoundException { Class clazz = Class.forName(type); validateClassTypes(clazz); @@ -129,10 +99,10 @@ public class RelationshipSchema { private void validateClassTypes(Class clazz) throws CrudException { if (!clazz.isAssignableFrom(Integer.class) && !clazz.isAssignableFrom(Double.class) - && !clazz.isAssignableFrom(Boolean.class) && !clazz.isAssignableFrom(String.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 index 51b33d0..7b68b35 100644 --- a/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java +++ b/src/main/java/org/openecomp/schema/RelationshipSchemaLoader.java @@ -24,135 +24,220 @@ package org.openecomp.schema; import org.apache.commons.io.IOUtils; +import org.openecomp.aai.dbmodel.DbEdgeRules; 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 org.springframework.core.io.UrlResource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; + +import java.io.*; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.concurrent.ConcurrentHashMap; import java.util.Date; -import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.SortedSet; +import java.util.stream.Collectors; 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 versionContextMap - = new ConcurrentHashMap(); + private static Map versionContextMap = new ConcurrentHashMap<>(); private static SortedSet versions = new TreeSet(); private static Map timers = new ConcurrentHashMap(); - - final static Pattern filePattern = Pattern.compile("aai_relationship_(.*).json"); + final static String edgePropsFiles = "edge_properties_"; + final static String fileExt = ".json"; + final static Pattern rulesFilePattern = Pattern.compile("DbEdgeRules(.*)" + fileExt); + final static Pattern propsFilePattern = Pattern.compile(edgePropsFiles + "(.*)" + fileExt); + final static Pattern versionPattern = Pattern.compile(".*(v\\d+)" + fileExt); private static org.openecomp.cl.api.Logger logger = LoggerFactory.getInstance() - .getLogger(RelationshipSchemaLoader.class.getName()); + .getLogger(RelationshipSchemaLoader.class.getName()); - public synchronized static void loadModels() { + public synchronized static void loadModels() throws CrudException { + load(rulesFilePattern, propsFilePattern); + } - File[] listOfFiles = new File(CrudServiceConstants.CRD_HOME_MODEL).listFiles(); + public synchronized static void loadModels(String version) throws CrudException { + String pattern = String.format(".*(%s)" + fileExt, version); + load(Pattern.compile(pattern), Pattern.compile(edgePropsFiles + version + fileExt)); + } - 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()); - } - } + public static RelationshipSchema getSchemaForVersion(String version) throws CrudException { + if (versionContextMap == null || versionContextMap.isEmpty()) { + loadModels(); + } else if (!versionContextMap.containsKey(version)) { + try { + loadModels(version); + } catch (Exception e) { + throw new CrudException("", Status.NOT_FOUND); + } + } + RelationshipSchema schema = versionContextMap.get(version); + if (schema == null) { + throw new CrudException("", Status.NOT_FOUND); + } else + return schema; + } - } + public static String getLatestSchemaVersion() throws CrudException { + return "v" + versions.last(); + } + + public static Map getVersionContextMap() { + return versionContextMap; + } + + public static void setVersionContextMap(Map versionContextMap) { + RelationshipSchemaLoader.versionContextMap = versionContextMap; + } + + public static void resetVersionContextMap() { + RelationshipSchemaLoader.versionContextMap = new ConcurrentHashMap<>(); + } + + + private static void load(Pattern rulesPattern, Pattern edgePropsPattern) throws CrudException { + ClassLoader cl = RelationshipSchemaLoader.class.getClassLoader(); + ResourcePatternResolver rulesResolver = new PathMatchingResourcePatternResolver(cl); + List rulesFiles; + String rulesDir = CrudServiceConstants.CRD_HOME_MODEL; + try { + + // getResources method returns objects of type "Resource" + // 1. We are getting all the objects from the classpath which has "DbEdgeRules" in the name. + // 2. We run them through a filter and return only the objects which match the supplied pattern "p" + // 3. We then collect the objects in a list. At this point we have a list of the kind of files we require. + rulesFiles = Arrays.stream(rulesResolver.getResources("classpath*:/dbedgerules/DbEdgeRules*" + fileExt)) + .filter(r -> !myMatcher(rulesPattern, r.getFilename()).isEmpty()) + .collect(Collectors.toList()); + + // This gets all the objects of type "File" from external directory (not on the classpath) + // 1. From an external directory (one not on the classpath) we get all the objects of type "File" + // 2. We only return the files whose names matched the supplied pattern "p2". + // 3. We then collect all the objects in a list and add the contents of this list + // to the previous collection (rulesFiles) + rulesFiles.addAll(Arrays.stream(new File(rulesDir).listFiles((d, name) -> + edgePropsPattern.matcher(name).matches())).collect(Collectors.toList())); + + if (rulesFiles.isEmpty()) { + logger.error(CrudServiceMsgs.INVALID_OXM_DIR, rulesDir); + throw new FileNotFoundException("DbEdgeRules and edge_properties files were not found."); + } + + // Sort and then group the files with their versions, convert them to the schema, and add them to versionContextMap + // 1. Sort the files. We need the DbEdgeRules files to be before the edgeProperties files. + // 2. Group the files with their versions. ie. v11 -> ["DbEdgeRule_v11.json", "edgeProperties_v11.json"]. + // The "group method" returns a HashMap whose key is the version and the value is a list of objects. + // 3. Go through each version and map the files into one schema using the "jsonFilesLoader" method. + // Also update the "versionContextMap" with the version and it's schema. + rulesFiles.stream().sorted(Comparator.comparing(RelationshipSchemaLoader::filename)) + .collect(Collectors.groupingBy(f -> myMatcher(versionPattern, filename(f)))) + .forEach((version, resourceAndFile) -> versionContextMap.put(version, jsonFilesLoader(version, resourceAndFile))); + + logger.info(CrudServiceMsgs.LOADED_OXM_FILE, "Relationship Schema and Properties files: " + rulesFiles.stream().map(f -> filename(f)).collect(Collectors.toList())); + } catch (IOException e) { + logger.error(CrudServiceMsgs.INVALID_OXM_DIR, rulesDir); + throw new CrudException("DbEdgeRules or edge_properties files were not found.", new FileNotFoundException()); + } + } + + private static String filename (Object k) throws ClassCastException { + if (k instanceof UrlResource){ + return ((UrlResource) k).getFilename(); + } else if (k instanceof File) { + return ((File) k).getName(); + } else { + throw new ClassCastException(); + } + } + + private static RelationshipSchema jsonFilesLoader (String version, List files) { + List fileContents = new ArrayList<>(); + RelationshipSchema rsSchema = null; + if (files.size() == 2) { + for (Object file : files) { + fileContents.add(jsonToRelationSchema(version, file)); + versions.add(Integer.parseInt(version.substring(1))); } + + try { + rsSchema = new RelationshipSchema(fileContents); + } catch (CrudException | IOException e) { + e.printStackTrace(); + logger.error(CrudServiceMsgs.INVALID_OXM_FILE, + files.stream().map(f -> filename(f)).collect(Collectors.toList()).toString(), e.getMessage()); + } + return rsSchema; } else { - logger.error(CrudServiceMsgs.INVALID_OXM_DIR, CrudServiceConstants.CRD_HOME_MODEL); + logger.debug(CrudServiceMsgs.INVALID_OXM_FILE, "Expecting a rules file and a properties file but found: " + + files.stream().map(f-> filename(f)).collect(Collectors.toList()).toString()); } + return rsSchema; + } + private synchronized static void updateVersionContext(String version, RelationshipSchema rs){ + versionContextMap.put(version, rs); + } + private synchronized static String jsonToRelationSchema (String version, Object file) { + InputStream inputStream = null; + String content = null; + + try { + if (file instanceof UrlResource) { + inputStream = ((UrlResource) file).getInputStream(); + } else { + inputStream = new FileInputStream((File) file); + addtimer(version, file); + } + content = IOUtils.toString(inputStream, "UTF-8"); + } catch (IOException e) { + e.printStackTrace(); + } + return content; } - private static void addtimer(String version, File file) { + private static void addtimer(String version, Object file) { TimerTask task = null; task = new FileWatcher( - file) { + (File) file) { protected void onChange(File file) { // here we implement the onChange logger.info(CrudServiceMsgs.OXM_FILE_CHANGED, file.getName()); try { - RelationshipSchemaLoader.loadModel(version, file); + // Cannot use the file object here because we also have to get the edge properties associated with that version. + // The properties are stored in a different file. + RelationshipSchemaLoader.loadModels(version); } catch (Exception e) { e.printStackTrace(); } - } }; if (!timers.containsKey(version)) { - Timer timer = new Timer("aai_relationship_" + version); + Timer timer = new Timer("db_edge_rules_" + 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))); + private static String myMatcher (Pattern p, String s) { + Matcher m = p.matcher(s); + return m.matches() ? m.group(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 getVersionContextMap() { - return versionContextMap; - } - - public static void setVersionContextMap(HashMap 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 index 552b60a..af20699 100644 --- a/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java +++ b/src/main/java/org/openecomp/schema/RelationshipSchemaValidator.java @@ -56,7 +56,7 @@ public class RelationshipSchemaValidator { throw new CrudException("", Status.NOT_FOUND); } - HashMap> props = schema.lookupRelationType(type); + Map> props = schema.lookupRelationType(type); Map result = new HashMap(); for (String key : filter.keySet()) { @@ -128,7 +128,7 @@ public class RelationshipSchemaValidator { String key = sourceNodeType + ":" + targetNodeType + ":" + type; // find the validate the key from the schema - HashMap> schemaObject = schema.lookupRelation(key); + Map> schemaObject = schema.lookupRelation(key); if (schemaObject == null) { throw new CrudException("Invalid source/target/relationship type: " + key, @@ -185,7 +185,7 @@ public class RelationshipSchemaValidator { + ":" + edge.getType(); // find the validate the key from the schema - HashMap> schemaObject = schema.lookupRelation(key); + Map> schemaObject = schema.lookupRelation(key); if (schemaObject == null) { Logger.warn("key :" + key @@ -267,7 +267,7 @@ public class RelationshipSchemaValidator { + ":" + edge.getType(); // find the validate the key from the schema - HashMap> schemaObject = schema.lookupRelation(key); + Map> schemaObject = schema.lookupRelation(key); if (schemaObject == null) { Logger.warn("key :" + key @@ -295,7 +295,7 @@ public class RelationshipSchemaValidator { private static void validateEdgeProps(Edge.Builder builder, JsonElement props, - HashMap> schemaObject) + Map> schemaObject) throws CrudException { Set> entries = props.getAsJsonObject().entrySet(); @@ -323,7 +323,7 @@ public class RelationshipSchemaValidator { String key = edge.getSource().getType() + ":" + edge.getTarget().getType() + ":" + edge.getType(); - HashMap> schemaObject = schema.lookupRelation(key); + Map> schemaObject = schema.lookupRelation(key); if (schemaObject == null || schemaObject.isEmpty()) { return edge; -- cgit 1.2.3-korg