diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java index 65d20f0..4083dce 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JavaPrototypeGenerateAction.java @@ -18,6 +18,7 @@ import generators.JavaCodeGenerator; import generators.JavaMethodBodyGenerator; import generators.JavaSpecific; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; @@ -47,8 +48,8 @@ if (fileName == null) fileName = "Main"; String mainTypeName = fileName.split("\\.")[0]; boolean exist = false; - for (ResourcePath id: model.getResourcePaths()) { - String resourceName = id.getResourceName().substring(0, 1).toUpperCase() + id.getResourceName().substring(1); + for (ResourceHierarchy res: model.getResourceHierarchies()) { + String resourceName = res.getResourceName().substring(0, 1).toUpperCase() + res.getResourceName().substring(1); if (mainTypeName.equals(resourceName)) { exist = true; } diff --git a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java index 766c384..dbf75fd 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java +++ b/AlgebraicDataflowArchitectureModel/src/application/actions/JerseyPrototypeGenerateAction.java @@ -17,6 +17,7 @@ import generators.JerseyCodeGenerator; import generators.JerseyMethodBodyGenerator; import models.algebra.Type; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.ModelExtension; @@ -46,8 +47,8 @@ if (fileName == null) fileName = "Main"; String mainTypeName = fileName.split("\\.")[0]; boolean exist = false; - for (ResourcePath id: model.getResourcePaths()) { - String resourceName = id.getResourceName().substring(0, 1).toUpperCase() + id.getResourceName().substring(1); + for (ResourceHierarchy res: model.getResourceHierarchies()) { + String resourceName = res.getResourceName().substring(0, 1).toUpperCase() + res.getResourceName().substring(1); if (mainTypeName.equals(resourceName)) { exist = true; } diff --git a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java index cce92fa..cb7692b 100644 --- a/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java +++ b/AlgebraicDataflowArchitectureModel/src/application/editor/Editor.java @@ -113,6 +113,7 @@ public DataFlowGraph getDataFlowGraph() { if (dataFlowGraph == null) { analyzeDataTransferModel(getModel()); + updateEdgeAttiributes(dataFlowGraph); } return dataFlowGraph; } @@ -120,7 +121,6 @@ public DataFlowGraph analyzeDataTransferModel(DataTransferModel model) { DataFlowGraph flowGraph = DataTransferModelAnalyzer.createDataFlowGraphWithStateStoringAttribute(model); dataFlowGraph = DataTransferModelAnalyzer.annotateWithSelectableDataTransferAttiribute(flowGraph); - updateEdgeAttiributes(dataFlowGraph); return dataFlowGraph; } @@ -183,13 +183,20 @@ } else { ParserDTRAM parserDTRAM = new ParserDTRAM(new BufferedReader(new FileReader(file))); try { + // Parse the .dtram file. model = parserDTRAM.doParseModel(); - graph = constructGraph(model); + + // Analyze the model. + if (!Validation.checkUpdateConflict(model)) return null; + DataFlowGraph dataFlowGraph = analyzeDataTransferModel(model); + + // Visualize the model. + graph = constructGraph(model, dataFlowGraph); parserDTRAM.doParseGeometry(graph); + updateEdgeAttiributes(dataFlowGraph); + curFilePath = file.getAbsolutePath(); curFileName = file.getName(); - if (!Validation.checkUpdateConflict(model)) return null; - analyzeDataTransferModel(model); return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression @@ -215,16 +222,19 @@ // Parse the .model file. model = parser.doParse(); - curFilePath = file.getAbsolutePath(); - curFileName = file.getName(); - // Analyze the model. if (!Validation.checkUpdateConflict(model)) return null; - graph = constructGraph(model); - analyzeDataTransferModel(model); + DataFlowGraph dataFlowGraph = analyzeDataTransferModel(model); + + // Visualize the model. + graph = constructGraph(model, dataFlowGraph); + updateEdgeAttiributes(dataFlowGraph); // Set DAG layout. setDAGLayout(); + + curFilePath = file.getAbsolutePath(); + curFileName = file.getName(); return model; } catch (ExpectedChannel | ExpectedChannelName | ExpectedLeftCurlyBracket | ExpectedInOrOutOrRefOrSubKeyword | ExpectedStateTransition | ExpectedEquals | ExpectedRHSExpression | WrongLHSExpression @@ -332,10 +342,10 @@ /** * Construct a mxGraph from DataFlowModel and DataFlowModel * @param model - * @param dataFlowGraph + * @param dataFlowGraph * @return constructed mxGraph */ - public mxGraph constructGraph(DataTransferModel model) { + public mxGraph constructGraph(DataTransferModel model, DataFlowGraph dataFlowGraph) { bReflectingArchitectureModel = true; ((mxGraphModel) graph.getModel()).clear(); Object parent = graph.getDefaultParent(); @@ -354,23 +364,36 @@ Map resources = new HashMap<>(); // create channel vertices - for (Channel c: model.getChannels()) { - DataTransferChannel channel = (DataTransferChannel) c; - if (channelsIn.get(channel) == null || channelsOut.get(channel) == null) { - Object chCell = graph.insertVertex(parent, null, channel.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex - mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); - port_in.setVertex(true); - graph.addCell(port_in, chCell); // insert the input port of a channel - mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); - port_out.setVertex(true); - graph.addCell(port_out, chCell); // insert the output port of a channel - channelsIn.put(channel, port_in); - channelsOut.put(channel, port_out); + for (ChannelNode c: dataFlowGraph.getRootChannelNodes()) { + DataTransferChannel channel = (DataTransferChannel) c.getChannel(); + if (channel.getInputResources().size() > 0) { + // Normal channel + if (channelsIn.get(channel) == null || channelsOut.get(channel) == null) { + Object chCell = graph.insertVertex(parent, null, channel.getChannelName(), 150, 20, 30, 30); // insert a channel as a vertex + mxCell port_in = new mxCell(null, geo1, "shape=ellipse;perimter=ellipsePerimeter"); + port_in.setVertex(true); + graph.addCell(port_in, chCell); // insert the input port of a channel + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelsIn.put(channel, port_in); + channelsOut.put(channel, port_out); + } + } else { + // I/O channel + if (channelsOut.get(channel) == null) { + Object chCell = graph.insertVertex(parent, null, channel.getChannelName(), 150, 20, 30, 30); // insert an I/O channel as a vertex + mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); + port_out.setVertex(true); + graph.addCell(port_out, chCell); // insert the output port of a channel + channelsOut.put((DataTransferChannel) channel, port_out); + } } } // create resource vertices - for (ResourcePath res: model.getResourcePaths()) { + for (ResourceNode resNode: dataFlowGraph.getRootResourceNodes()) { + ResourcePath res = resNode.getOutSideResource(); Object resource = graph.insertVertex(parent, null, res.getResourceName(), 20, 20, 80, 30, "shape=ellipse;perimeter=ellipsePerimeter"); // insert a resource as a vertex @@ -378,34 +401,28 @@ } // add input, output and reference edges - for (Channel ch: model.getChannels()) { - DataTransferChannel channel = (DataTransferChannel) ch; - // input edge - for (ResourcePath srcRes: channel.getInputResources()) { + for (Edge edge: dataFlowGraph.getEdges()) { + DataFlowEdge dfEdge = (DataFlowEdge) edge; + if (dfEdge.isChannelToResource()) { + // output edge + DataTransferChannel channel = ((ChannelNode) dfEdge.getSource()).getChannel(); + ResourcePath dstRes = ((ResourceNode) dfEdge.getDestination()).getOutSideResource(); + graph.insertEdge(parent, null, new SrcDstAttribute(channel, dstRes), channelsOut.get(channel), resources.get(dstRes), "movable=false"); + } else { + // input edge + ResourcePath srcRes = ((ResourceNode) dfEdge.getSource()).getOutSideResource(); + DataTransferChannel channel = ((ChannelNode) dfEdge.getDestination()).getChannel(); graph.insertEdge(parent, null, new SrcDstAttribute(srcRes, channel), resources.get(srcRes), channelsIn.get(channel), "movable=false"); } - // output edge - for (ResourcePath dstRes: channel.getOutputResources()) { - graph.insertEdge(parent, null, new SrcDstAttribute(channel, dstRes), channelsOut.get(channel), resources.get(dstRes), "movable=false"); - } + } + + for (Channel ch: model.getChannels()) { // reference edges + DataTransferChannel channel = (DataTransferChannel) ch; for (ResourcePath refRes: channel.getReferenceResources()) { graph.insertEdge(parent, null, null, resources.get(refRes), channelsIn.get(channel), "dashed=true;movable=false"); } } - - for (Channel ioChannel: model.getIOChannels()) { - if (channelsOut.get(ioChannel) == null) { - Object channel = graph.insertVertex(parent, null, ioChannel.getChannelName(), 150, 20, 30, 30); // insert an I/O channel as a vertex - mxCell port_out = new mxCell(null, geo2, "shape=ellipse;perimter=ellipsePerimeter"); - port_out.setVertex(true); - graph.addCell(port_out, channel); // insert the output port of a channel - channelsOut.put((DataTransferChannel) ioChannel, port_out); - for (ResourcePath outRes: ((DataTransferChannel) ioChannel).getOutputResources()) { - graph.insertEdge(parent, null, null, port_out, resources.get(outRes), "movable=false"); - } - } - } } finally { graph.getModel().endUpdate(); } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java index 9a21a20..37bdd37 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGenerator.java @@ -168,9 +168,9 @@ } // Add a statement to instantiate each object to the main constructor. List parameters = new ArrayList<>(); - for (ResourcePath id: depends) { + for (ResourcePath res: depends) { // For the callee objects (the destination resource of push transfer or the source resource of pull transfer). - parameters.add(id.getResourceName()); + parameters.add(res.getResourceName()); } // For the refs. if (resNode != null) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java index c766ccb..080d7f7 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/CodeGeneratorFromDataFlowGraph.java @@ -56,13 +56,20 @@ CompilationUnit cu = langSpec.newCompilationUnit(component); codes.add(cu); + // Declare the constructor and the fields to refer to other resources. + MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, depends, langSpec); + // Update the main component for this component. updateMainComponent(model, mainComponent, mainConstructor, componentNode, depends, langSpec); + + // Declare the fields to refer to reference resources. + declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); + + if (constructor.getParameters() == null) { + component.removeMethod(constructor); + } } - // Declare the constructor and the fields to refer to other resources. - MethodDeclaration constructor = declareConstructorAndFieldsToReferToResources(resourceNode, component, depends, langSpec); - ResourcePath res = resourceNode.getOutSideResource(); Type resStateType = res.getResourceStateType(); @@ -77,19 +84,11 @@ // Declare the accessor method in the main component to call the getter method. declareAccessorInMainComponent(mainComponent, res, getter, langSpec); - - // Declare the fields to refer to reference resources. - declareFieldsToReferenceResources(model, resourceNode, component, constructor, depends, langSpec); - // Declare cache fields and update methods in this resource. List updates = declareCacheFieldsAndUpdateMethods(resourceNode, component, langSpec); // Declare input methods in this component and the main component. List inputs = declareInputMethodsInThisAndMainComponents(resourceNode, component, mainComponent, model, langSpec); - - if (constructor.getParameters() == null) { - component.removeMethod(constructor); - } } } @@ -268,7 +267,7 @@ } // Declare the field to cache the state of the source resource in the type of the destination resource. - if (resourceNode.getIndegree() > 1) { + if (resToCh.getDestination().getIndegree() > 1) { // If incoming edges are multiple if (langSpec.declareField()) { // Declare the cache field. diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java index abc6a98..771e43a 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaCodeGenerator.java @@ -122,11 +122,11 @@ fieldInitializer += resName.toLowerCase() + ","; f = true; } else { - if (rn.getIndegree() > 1) { + if (re.getDestination().getIndegree() > 1) { // Declare a field to cash the state of the source resource in the type of the destination resource. - ResourcePath cashResId = ((ResourceNode) re.getSource()).getOutSideResource(); + ResourcePath cashRes = ((ResourceNode) re.getSource()).getOutSideResource(); type.addField(new FieldDeclaration( - cashResId.getResourceStateType(), ((ResourceNode) re.getSource()).getOutSideResource().getResourceName(), getInitializer(cashResId))); + cashRes.getResourceStateType(), ((ResourceNode) re.getSource()).getOutSideResource().getResourceName(), getInitializer(cashRes))); } } } diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java index 3e132e4..177b87e 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JavaMethodBodyGenerator.java @@ -25,6 +25,7 @@ import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataConstraintModel.Selector; import models.dataFlowModel.DataTransferModel; @@ -83,7 +84,7 @@ update.addFirstStatement(updateStatement); } } - if (dst.getIndegree() > 1) { + if (resToCh.getDestination().getIndegree() > 1) { // update a cash of src side resource (when incoming edges are multiple) String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { @@ -210,13 +211,13 @@ // for source nodes String mainTypeName = JavaCodeGenerator.mainTypeName.substring(0,1).toLowerCase() + JavaCodeGenerator.mainTypeName.substring(1); TypeDeclaration mainType = typeMap.get(mainTypeName); - for (Node n: graph.getResourceNodes()) { - ResourceNode resource = (ResourceNode) n; + for (ResourceHierarchy resource: model.getResourceHierarchies()) { +// ResourceNode resource = (ResourceNode) n; String resourceName = resource.getResourceName(); TypeDeclaration type = typeMap.get(resourceName); if (type != null) { // getter method - if (resource.getNumberOfParameters() == 0) { + if (resource.getTotalNumParameters() == 0) { MethodDeclaration getter = getGetterMethod(type, null); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { Type resourceType = resource.getResourceStateType(); @@ -246,7 +247,7 @@ MethodDeclaration input = getInputMethod(type, out); if (input != null) { // In the resource - if (resource.getNumberOfParameters() == 0) { + if (resource.getTotalNumParameters() == 0) { String[] sideEffects = new String[] {""}; Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JavaCodeGenerator.pushAccessor); String newState = updateExp.toImplementation(sideEffects); @@ -332,13 +333,13 @@ return null; } - private static Map> getIOChannelsAndMembers(ResourceNode resource, DataTransferModel model) { + private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { Map> ioChannelsAndMembers = new HashMap<>(); for (Channel c: model.getIOChannels()) { DataTransferChannel ch = (DataTransferChannel) c; // I/O channel for (ChannelMember out: ch.getOutputChannelMembers()) { - if (resource.getInSideResources().contains(out.getResource())) { + if (resource.equals(out.getResource().getResourceHierarchy())) { if (out.getStateTransition().getMessageExpression() instanceof Term || out.getStateTransition().getMessageExpression() instanceof Variable) { Set channelMembers = ioChannelsAndMembers.get(ch); if (channelMembers == null) { diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java index f982fc7..7618a14 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyCodeGenerator.java @@ -145,7 +145,7 @@ } } } - if (rn.getInEdges().size() > 1) { + if (re.getDestination().getIndegree() > 1) { // For each source resource, a child resource is defined in the destination resource so that its state can be updated separately. update.addAnnotation(new Annotation("Path", "\"/" + srcName + "\"")); // Declare a field to cash the state of the source resource in the type of the destination resource. diff --git a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java index 2fec5d8..c919fc1 100644 --- a/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java +++ b/AlgebraicDataflowArchitectureModel/src/generators/JerseyMethodBodyGenerator.java @@ -27,6 +27,7 @@ import models.dataConstraintModel.Channel; import models.dataConstraintModel.ChannelMember; import models.dataConstraintModel.DataConstraintModel; +import models.dataConstraintModel.ResourceHierarchy; import models.dataConstraintModel.ResourcePath; import models.dataFlowModel.DataTransferModel; import models.dataFlowModel.DataTransferChannel; @@ -104,7 +105,7 @@ update.addFirstStatement(updateStatement); } } - if (dst.getIndegree() > 1) { + if (resToCh.getDestination().getIndegree() > 1) { // update a cash of src side resource (when incoming edges are multiple) String cashStatement = "this." + srcResourceName + " = " + srcResourceName + ";"; if (update.getBody() == null || !update.getBody().getStatements().contains(cashStatement)) { @@ -304,13 +305,12 @@ } } // for source nodes - for (Node n: graph.getResourceNodes()) { - ResourceNode resource = (ResourceNode) n; + for (ResourceHierarchy resource: model.getResourceHierarchies()) { String resourceName = resource.getResourceName(); TypeDeclaration type = typeMap.get(resourceName); if (type != null) { // getter method - if (resource.getNumberOfParameters() == 0) { + if (resource.getTotalNumParameters() == 0) { MethodDeclaration getter = getGetterMethod(type, null); if (getter.getBody() == null || getter.getBody().getStatements().size() == 0) { getter.addStatement("return value;"); @@ -323,7 +323,7 @@ for (ChannelMember out: outs) { MethodDeclaration input = getInputMethod(type, out); if (input != null) { - if (resource.getNumberOfParameters() == 0) { + if (resource.getTotalNumParameters() == 0) { Expression updateExp = entry.getKey().deriveUpdateExpressionOf(out, JerseyCodeGenerator.pushAccessor); String[] sideEffects = new String[] {""}; String newState = updateExp.toImplementation(sideEffects); @@ -567,13 +567,13 @@ return null; } - private static Map> getIOChannelsAndMembers(ResourceNode resource, DataTransferModel model) { + private static Map> getIOChannelsAndMembers(ResourceHierarchy resource, DataTransferModel model) { Map> ioChannelsAndMembers = new HashMap<>(); for (Channel c: model.getIOChannels()) { DataTransferChannel ch = (DataTransferChannel) c; // I/O channel for (ChannelMember out: ch.getOutputChannelMembers()) { - if (resource.getInSideResources().contains(out.getResource())) { + if (resource.equals(out.getResource().getResourceHierarchy())) { if (out.getStateTransition().getMessageExpression() instanceof Term || out.getStateTransition().getMessageExpression() instanceof Variable) { Set channelMembers = ioChannelsAndMembers.get(ch); if (channelMembers == null) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java index b5068fa..b083477 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/DataConstraintModel.java @@ -301,14 +301,17 @@ } public void addResourcePath(ResourcePath resourcePath) { + resourcePaths.add(resourcePath); ResourceHierarchy hierarchy = resourcePath.getResourceHierarchy(); do { if (resourceHierarchies.get(hierarchy.toString()) == null) { resourceHierarchies.put(hierarchy.toString(), hierarchy); + } else { + resourcePath.setResourceHierarchy(resourceHierarchies.get(hierarchy.toString())); } + resourcePath = resourcePath.getParent(); hierarchy = hierarchy.getParent(); } while (hierarchy != null); - resourcePaths.add(resourcePath); } public void setResourcePaths(List resourcePaths) { diff --git a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java index f3a19c6..390f80e 100644 --- a/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java +++ b/AlgebraicDataflowArchitectureModel/src/models/dataConstraintModel/ResourcePath.java @@ -17,6 +17,7 @@ public ResourcePath(String resourceName) { super(resourceName); + this.parent = null; this.resourceHierarchy = new ResourceHierarchy(null, resourceName); this.pathParams = new ArrayList<>(); } @@ -38,6 +39,7 @@ public ResourcePath(ResourcePath parent, List pathParams) { super(parent.toString() + ".{" + pathParams.toString() + "}"); + this.parent = parent; this.resourceHierarchy = new ResourceHierarchy(parent.getResourceHierarchy(), pathParams.size()); this.pathParams = new ArrayList<>(parent.getPathParams()); this.pathParams.addAll(pathParams); @@ -48,6 +50,10 @@ return resourceHierarchy; } + public void setResourceHierarchy(ResourceHierarchy resourceHierarchy) { + this.resourceHierarchy = resourceHierarchy; + } + public String getResourceName() { return resourceHierarchy.getResourceName(); }