+ }
+ public void toRelations() {
+ logger.debug("{“comment”: “Valid TO Relations that can be added”},");
+ logger.debug("apiPath: "+apiPath+"\nopId="+opId+"\nobjectName="+objectName);
+ Collection<EdgeDescription> toEdges = GenerateXsd.getEdgeRulesTO(objectName);
+
+ if(toEdges.size() > 0) {
+ relations.add("{\"comment\": \"Valid TO Relations that can be added\"}\n");
+ }
+ for (EdgeDescription ed : toEdges) {
+ logger.debug(ed.getRuleKey()+"Type="+ed.type);
+ String obj = ed.getRuleKey().replace(objectName,"").replace("|","");
+ String selectedRelation = "";
+ if(ed.type == LineageType.UNRELATED) {
+ String selectObj = getUnrelatedObjectPaths(obj, apiPath);
+ logger.debug("SelectedObj:"+selectObj);
+ selectedRelation = formatObjectRelationSet(obj,selectObj);
+ logger.trace("ObjectRelationSet"+selectedRelation);
+ } else {
+ String selectObj = getKinObjectPath(obj, apiPath);
+ logger.debug("SelectedObj:"+selectObj);
+ selectedRelation = formatObjectRelation(obj,selectObj);
+ logger.trace("ObjectRelationSet"+selectedRelation);
+ }
+ relations.add(selectedRelation);
+ logger.trace(selectedRelation);
+ }
+ }
+
+ public void fromRelations() {
+ logger.debug("“comment”: “Valid FROM Relations that can be added”");
+ Collection<EdgeDescription> fromEdges = getEdgeRulesFROM(objectName);
+ if(fromEdges.size() > 0) {
+ relations.add("{\"comment\": \"Valid FROM Relations that can be added\"}\n");
+ }
+ for (EdgeDescription ed : fromEdges) {
+ logger.debug(ed.getRuleKey()+"Type="+ed.type);
+ String obj = ed.getRuleKey().replace(objectName,"").replace("|","");
+ String selectedRelation = "";
+ if(ed.type == LineageType.UNRELATED) {
+ String selectObj = getUnrelatedObjectPaths(obj, apiPath);
+ logger.debug("SelectedObj"+selectObj);
+ selectedRelation = formatObjectRelationSet(obj,selectObj);
+ logger.trace("ObjectRelationSet"+selectedRelation);
+ } else {
+ String selectObj = getKinObjectPath(obj, apiPath);
+ logger.debug("SelectedObj"+selectObj);
+ selectedRelation = formatObjectRelation(obj,selectObj);
+ logger.trace("ObjectRelationSet"+selectedRelation);
+ }
+ relations.add(selectedRelation);
+ logger.trace(selectedRelation);
+ }
+ }
+ public void writeRelationsFile() {
+ File examplefilePath = new File(yaml_dir + "/relations/" + currentAPIVersion+"/"+opId.replace("RelationshipListRelationship", "") + ".json");
+
+ logger.debug(String.join("exampleFilePath: ", examplefilePath.toString()));
+ FileOutputStream fop = null;
+ try {
+ if (!examplefilePath.exists()) {
+ examplefilePath.getParentFile().mkdirs();
+ examplefilePath.createNewFile();
+ }
+ fop = new FileOutputStream(examplefilePath);
+ } catch(Exception e) {
+ e.printStackTrace();
+ return;
+ }
+ try {
+ if(relations.size() > 0) {fop.write("[\n".getBytes());}
+ fop.write(String.join(",\n", relations).getBytes());
+ if(relations.size() > 0) {fop.write("\n]\n".getBytes());}
+ fop.flush();
+ fop.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return;
+ }
+ logger.debug(String.join(",\n", relations));
+ return;
+ }
+
+ private static String formatObjectRelationSet(String obj, String selectObj) {
+ StringBuffer pathSb = new StringBuffer();
+ String[] paths = selectObj.split("[|]");
+ for (String s: paths) {
+ logger.trace("SelectOBJ"+s);
+ pathSb.append(formatObjectRelation(obj, s)+",\n");
+ }
+ pathSb.deleteCharAt(pathSb.length()-2);
+ return pathSb.toString();
+ }
+
+ private static String formatObjectRelation(String obj, String selectObj) {
+ StringBuffer pathSb = new StringBuffer();
+ pathSb.append("{\n");
+ pathSb.append("\"related-to\" : \""+obj+"\",\n");
+ pathSb.append("\"related-link\" : \""+selectObj+"\"\n");
+ pathSb.append("}");
+ return pathSb.toString();
+ }
+
+ private static String getKinObjectPath(String obj, String apiPath) {
+ LevenshteinDistance proximity = new LevenshteinDistance();
+ String targetPath = "";
+ int targetScore = Integer.MAX_VALUE;
+ int targetMaxScore = 0;
+ for (Map.Entry<String, String> p : deletePaths.entrySet()) {
+ if(p.getValue().equals(obj)) {
+ targetScore = (targetScore >= proximity.apply(apiPath, p.getKey())) ? proximity.apply(apiPath, p.getKey()) : targetScore;
+ targetPath = (targetScore >= proximity.apply(apiPath, p.getKey())) ? p.getKey() : targetPath;
+ targetMaxScore = (targetMaxScore <= proximity.apply(apiPath, p.getKey())) ? proximity.apply(apiPath, p.getKey()) : targetScore;
+ logger.trace(proximity.apply(apiPath, p.getKey())+":"+p.getKey());
+ logger.trace(proximity.apply(apiPath, p.getKey())+":"+apiPath);
+ }
+ }
+ return targetPath;
+ }
+
+ private static String getUnrelatedObjectPaths(String obj, String apiPath) {
+ String targetPath = "";
+ logger.trace("Obj:"+obj +"\n" + apiPath);
+ for (Map.Entry<String, String> p : deletePaths.entrySet()) {
+ if(p.getValue().equals(obj)) {
+ logger.trace("p.getvalue:"+p.getValue()+"p.getkey:"+p.getKey());
+ targetPath += ((targetPath.length() == 0 ? "" : "|") + p.getKey());
+ logger.trace("Match:"+apiPath +"\n" + targetPath);
+ }
+ }
+ return targetPath;
+ }
+ }
+
+ private static class PatchOperation {
+ String useOpId;
+ String xmlRootElementName;
+ String tag;
+ String path;
+ String pathParams;
+
+ public PatchOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
+ super();
+ this.useOpId = useOpId;
+ this.xmlRootElementName = xmlRootElementName;
+ this.tag = tag;
+ this.path = path;
+ this.pathParams = pathParams;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer pathSb = new StringBuffer();
+ pathSb.append(" patch:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+
+ pathSb.append(" summary: update an existing " + xmlRootElementName + "\n");
+ pathSb.append(" description: update an existing " + xmlRootElementName + "\n");
+ pathSb.append(" operationId: Update" + useOpId + "\n");
+ pathSb.append(" consumes:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+
+ pathSb.append(" parameters:\n");
+ pathSb.append(pathParams); // for nesting
+ pathSb.append(" - name: body\n");
+ pathSb.append(" in: body\n");
+ pathSb.append(" description: " + xmlRootElementName + " object that needs to be created or updated\n");
+ pathSb.append(" required: true\n");
+ pathSb.append(" schema:\n");
+ pathSb.append(" $ref: \"patchSchema.yaml#/definitions/" + xmlRootElementName + "\"\n");
+
+ return pathSb.toString();
+ }
+ public String toString1() {
+ StringBuffer pathSb = new StringBuffer();
+ StringBuffer relationshipExamplesSb = new StringBuffer();
+ if ( path.endsWith("/relationship") ) {
+ pathSb.append(" " + path + ":\n" );
+ }
+ pathSb.append(" patch:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+
+ if ( path.endsWith("/relationship") ) {
+ pathSb.append(" summary: see node definition for valid relationships\n");
+ relationshipExamplesSb.append("[See Examples](apidocs/relations/"+GenerateXsd.apiVersion+"/"+useOpId+".json)");
+ } else {
+ pathSb.append(" summary: update an existing " + xmlRootElementName + "\n");
+ pathSb.append(" description: |\n");
+ pathSb.append(" Update an existing " + xmlRootElementName + "\n");
+ pathSb.append(" #\n");
+ pathSb.append(" Note: Endpoints that are not devoted to object relationships support both PUT and PATCH operations.\n");
+ pathSb.append(" The PUT operation will entirely replace an existing object.\n");
+ pathSb.append(" The PATCH operation sends a \"description of changes\" for an existing object. The entire set of changes must be applied. An error result means no change occurs.\n");
+ pathSb.append(" #\n");
+ pathSb.append(" Other differences between PUT and PATCH are:\n");
+ pathSb.append(" #\n");
+ pathSb.append(" - For PATCH, you can send any of the values shown in sample REQUEST body. There are no required values.\n");
+ pathSb.append(" - For PATCH, resource-id which is a required REQUEST body element for PUT, must not be sent.\n");
+ pathSb.append(" - PATCH cannot be used to update relationship elements; there are dedicated PUT operations for this.\n");
+ }
+ pathSb.append(" operationId: Update" + useOpId + "\n");
+ pathSb.append(" consumes:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+ pathSb.append(" parameters:\n");
+ pathSb.append(pathParams); // for nesting
+ pathSb.append(" - name: body\n");
+ pathSb.append(" in: body\n");
+ pathSb.append(" description: " + xmlRootElementName + " object that needs to be created or updated. "+relationshipExamplesSb.toString()+"\n");
+ pathSb.append(" required: true\n");
+ pathSb.append(" schema:\n");
+ pathSb.append(" $ref: \"#/patchDefinitions/" + xmlRootElementName + "\"\n");
+ return pathSb.toString();
+ }
+ }
+ private static class PutOperation {
+ String useOpId;
+ String xmlRootElementName;
+ String tag;
+ String path;
+ String pathParams;
+
+ public PutOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
+ super();
+ this.useOpId = useOpId;
+ this.xmlRootElementName = xmlRootElementName;
+ this.tag = tag;
+ this.path = path;
+ this.pathParams = pathParams;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer pathSb = new StringBuffer();
+ StringBuffer relationshipExamplesSb = new StringBuffer();
+ if ( path.endsWith("/relationship") ) {
+ pathSb.append(" " + path + ":\n" );
+ }
+ pathSb.append(" put:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+
+ if ( path.endsWith("/relationship") ) {
+ pathSb.append(" summary: see node definition for valid relationships\n");
+ } else {
+ pathSb.append(" summary: create or update an existing " + xmlRootElementName + "\n");
+ pathSb.append(" description: |\n Create or update an existing " + xmlRootElementName + ".\n #\n Note! This PUT method has a corresponding PATCH method that can be used to update just a few of the fields of an existing object, rather than a full object replacement. An example can be found in the [PATCH section] below\n");
+ }
+ relationshipExamplesSb.append("[Valid relationship examples shown here](apidocs/relations/"+GenerateXsd.apiVersion+"/"+useOpId.replace("RelationshipListRelationship", "")+".json)");
+ pathSb.append(" operationId: createOrUpdate" + useOpId + "\n");
+ pathSb.append(" consumes:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+
+ pathSb.append(" parameters:\n");
+ pathSb.append(pathParams); // for nesting
+ pathSb.append(" - name: body\n");
+ pathSb.append(" in: body\n");
+ pathSb.append(" description: " + xmlRootElementName + " object that needs to be created or updated. "+relationshipExamplesSb.toString()+"\n");
+ pathSb.append(" required: true\n");
+ pathSb.append(" schema:\n");
+ pathSb.append(" $ref: \"#/definitions/" + xmlRootElementName + "\"\n");
+ return pathSb.toString();
+ }
+ public String tagRelationshipPathMapEntry() {
+ if ( path.endsWith("/relationship") ) {
+ putRelationPaths.put(useOpId, path);
+ }
+ return "";
+ }
+
+ }
+
+ private static class GetOperation {
+ String useOpId;
+ String xmlRootElementName;
+ String tag;
+ String path;
+ @SuppressWarnings("unused")
+ String pathParams;
+ public GetOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
+ super();
+ this.useOpId = useOpId;
+ this.xmlRootElementName = xmlRootElementName;
+ this.tag = tag;
+ this.path = path;
+ this.pathParams = pathParams;
+ }
+ @Override
+ public String toString() {
+ StringBuffer pathSb = new StringBuffer();
+ pathSb.append(" " + path + ":\n" );
+ pathSb.append(" get:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+ pathSb.append(" summary: returns " + xmlRootElementName + "\n");
+
+ pathSb.append(" description: returns " + xmlRootElementName + "\n");
+ pathSb.append(" operationId: get" + useOpId + "\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"200\":\n");
+ pathSb.append(" description: successful operation\n");
+ pathSb.append(" schema:\n");
+ pathSb.append(" $ref: \"#/getDefinitions/" + xmlRootElementName + "\"\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+
+ return pathSb.toString();
+ }
+
+ }
+ private static class DeleteOperation {
+ String useOpId;
+ String xmlRootElementName;
+ String tag;
+ String path;
+ String pathParams;
+ public DeleteOperation(String useOpId, String xmlRootElementName, String tag, String path, String pathParams) {
+ super();
+ this.useOpId = useOpId;
+ this.xmlRootElementName = xmlRootElementName;
+ this.tag = tag;
+ this.path = path;
+ this.pathParams = pathParams;
+ }
+ @Override
+ public String toString() {
+ StringBuffer pathSb = new StringBuffer();
+ pathSb.append(" delete:\n");
+ pathSb.append(" tags:\n");
+ pathSb.append(" - " + tag + "\n");
+ pathSb.append(" summary: delete an existing " + xmlRootElementName + "\n");
+
+ pathSb.append(" description: delete an existing " + xmlRootElementName + "\n");
+
+ pathSb.append(" operationId: delete" + useOpId + "\n");
+ pathSb.append(" consumes:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" produces:\n");
+ pathSb.append(" - application/json\n");
+ pathSb.append(" - application/xml\n");
+ pathSb.append(" responses:\n");
+ pathSb.append(" \"default\":\n");
+ pathSb.append(" " + responsesUrl);
+ pathSb.append(" parameters:\n");
+
+ pathSb.append(pathParams); // for nesting
+ if ( !path.endsWith("/relationship") ) {
+ pathSb.append(" - name: resource-version\n");
+
+ pathSb.append(" in: query\n");
+ pathSb.append(" description: resource-version for concurrency\n");
+ pathSb.append(" required: true\n");
+ pathSb.append(" type: string\n");
+ }
+ return pathSb.toString();
+ }
+ public String objectPathMapEntry() {
+ if (! path.endsWith("/relationship") ) {
+ deletePaths.put(path, xmlRootElementName);
+ }
+ return (xmlRootElementName+":"+path);
+ }
+