Skip to content

Commit 961043e

Browse files
committed
Add missing plan builder plugins
1 parent 1ec4dfe commit 961043e

File tree

3 files changed

+634
-12
lines changed

3 files changed

+634
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
package org.opentosca.planbuilder.core.bpel.typebasedplanbuilder;
2+
3+
import java.io.IOException;
4+
import java.net.URLEncoder;
5+
import java.util.ArrayList;
6+
import java.util.HashMap;
7+
import java.util.List;
8+
import java.util.Map;
9+
import java.util.Objects;
10+
11+
import javax.xml.namespace.QName;
12+
import javax.xml.parsers.ParserConfigurationException;
13+
14+
import org.opentosca.container.core.tosca.convention.Interfaces;
15+
import org.opentosca.planbuilder.AbstractManagementFeaturePlanBuilder;
16+
import org.opentosca.planbuilder.core.bpel.context.BPELPlanContext;
17+
import org.opentosca.planbuilder.core.bpel.fragments.BPELProcessFragments;
18+
import org.opentosca.planbuilder.core.bpel.handlers.BPELFinalizer;
19+
import org.opentosca.planbuilder.core.bpel.handlers.BPELPlanHandler;
20+
import org.opentosca.planbuilder.core.bpel.handlers.CorrelationIDInitializer;
21+
import org.opentosca.planbuilder.core.bpel.tosca.handlers.NodeRelationInstanceVariablesHandler;
22+
import org.opentosca.planbuilder.core.bpel.tosca.handlers.PropertyVariableHandler;
23+
import org.opentosca.planbuilder.core.bpel.tosca.handlers.SimplePlanBuilderServiceInstanceHandler;
24+
import org.opentosca.planbuilder.model.plan.AbstractPlan;
25+
import org.opentosca.planbuilder.model.plan.AbstractPlan.PlanType;
26+
import org.opentosca.planbuilder.model.plan.ActivityType;
27+
import org.opentosca.planbuilder.model.plan.bpel.BPELPlan;
28+
import org.opentosca.planbuilder.model.plan.bpel.BPELScope;
29+
import org.opentosca.planbuilder.model.tosca.AbstractDefinitions;
30+
import org.opentosca.planbuilder.model.tosca.AbstractNodeTemplate;
31+
import org.opentosca.planbuilder.model.tosca.AbstractOperation;
32+
import org.opentosca.planbuilder.model.tosca.AbstractParameter;
33+
import org.opentosca.planbuilder.model.tosca.AbstractServiceTemplate;
34+
import org.opentosca.planbuilder.model.utils.ModelUtils;
35+
import org.opentosca.planbuilder.plugins.context.Property2VariableMapping;
36+
import org.opentosca.planbuilder.plugins.context.Variable;
37+
import org.slf4j.Logger;
38+
import org.slf4j.LoggerFactory;
39+
import org.w3c.dom.Node;
40+
import org.xml.sax.SAXException;
41+
42+
/**
43+
* <p>
44+
* This process builder creates a backup management plan if one of the NodeTemplates in the topology
45+
* is of a type that defines the freeze interface.
46+
* </p>
47+
*
48+
* Copyright 2019 IAAS University of Stuttgart <br>
49+
* <br>
50+
*/
51+
public class BPELBackupManagementProcessBuilder extends AbstractManagementFeaturePlanBuilder {
52+
53+
private final static Logger LOG = LoggerFactory.getLogger(BPELBackupManagementProcessBuilder.class);
54+
55+
// handler for abstract buildplan operations
56+
public BPELPlanHandler planHandler;
57+
58+
// class for initializing properties inside the build plan
59+
private final PropertyVariableHandler propertyInitializer;
60+
61+
// adds serviceInstance Variable and instanceDataAPIUrl to buildPlans
62+
private SimplePlanBuilderServiceInstanceHandler serviceInstanceVarsHandler;
63+
64+
// adds nodeInstanceIDs to each templatePlan
65+
private NodeRelationInstanceVariablesHandler instanceVarsHandler;
66+
67+
// class for finalizing build plans (e.g when some template didn't receive
68+
// some provisioning logic and they must be filled with empty elements)
69+
private final BPELFinalizer finalizer;
70+
71+
private BPELProcessFragments bpelFragments;
72+
73+
private CorrelationIDInitializer correlationHandler;
74+
75+
/**
76+
* <p>
77+
* Default Constructor
78+
* </p>
79+
*/
80+
public BPELBackupManagementProcessBuilder() {
81+
try {
82+
this.planHandler = new BPELPlanHandler();
83+
this.serviceInstanceVarsHandler = new SimplePlanBuilderServiceInstanceHandler();
84+
this.instanceVarsHandler = new NodeRelationInstanceVariablesHandler(this.planHandler);
85+
this.bpelFragments = new BPELProcessFragments();
86+
this.correlationHandler = new CorrelationIDInitializer();
87+
}
88+
catch (final ParserConfigurationException e) {
89+
LOG.error("Error while initializing BuildPlanHandler", e);
90+
}
91+
this.propertyInitializer = new PropertyVariableHandler(this.planHandler);
92+
this.finalizer = new BPELFinalizer();
93+
}
94+
95+
/*
96+
* (non-Javadoc)
97+
*
98+
* @see org.opentosca.planbuilder.IPlanBuilder#buildPlan(java.lang.String,
99+
* org.opentosca.planbuilder.model.tosca.AbstractDefinitions, javax.xml.namespace.QName)
100+
*/
101+
@Override
102+
public BPELPlan buildPlan(final String csarName, final AbstractDefinitions definitions,
103+
final AbstractServiceTemplate serviceTemplate) {
104+
LOG.debug("Creating Backup Management Plan...");
105+
106+
if (Objects.isNull(serviceTemplate)) {
107+
LOG.error("Unable to generate Backup Plan with ServiceTempolate equal to null.");
108+
return null;
109+
}
110+
111+
final String processName = ModelUtils.makeValidNCName(serviceTemplate.getId() + "_backupManagementPlan");
112+
final String processNamespace = serviceTemplate.getTargetNamespace() + "_backupManagementPlan";
113+
114+
final AbstractPlan abstractBackupPlan =
115+
generateMOG(new QName(processNamespace, processName).toString(), definitions, serviceTemplate,
116+
Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE, ActivityType.BACKUP, true);
117+
118+
LOG.debug("Generated the following abstract backup plan: ");
119+
LOG.debug(abstractBackupPlan.toString());
120+
121+
abstractBackupPlan.setType(PlanType.MANAGE);
122+
final BPELPlan newBackupPlan =
123+
this.planHandler.createEmptyBPELPlan(processNamespace, processName, abstractBackupPlan, "backup");
124+
125+
this.planHandler.initializeBPELSkeleton(newBackupPlan, csarName);
126+
127+
newBackupPlan.setTOSCAInterfaceName("OpenTOSCA-Management-Feature-Interface");
128+
newBackupPlan.setTOSCAOperationname("backup");
129+
130+
this.instanceVarsHandler.addInstanceURLVarToTemplatePlans(newBackupPlan, serviceTemplate);
131+
this.instanceVarsHandler.addInstanceIDVarToTemplatePlans(newBackupPlan, serviceTemplate);
132+
133+
final Property2VariableMapping propMap =
134+
this.propertyInitializer.initializePropertiesAsVariables(newBackupPlan, serviceTemplate);
135+
136+
// initialize instanceData handling
137+
this.planHandler.registerExtension("http://www.apache.org/ode/bpel/extensions/bpel4restlight", true,
138+
newBackupPlan);
139+
this.serviceInstanceVarsHandler.addServiceInstanceHandlingFromInput(newBackupPlan);
140+
final String serviceTemplateURLVarName =
141+
this.serviceInstanceVarsHandler.getServiceTemplateURLVariableName(newBackupPlan);
142+
this.serviceInstanceVarsHandler.appendInitPropertyVariablesFromServiceInstanceData(newBackupPlan, propMap,
143+
serviceTemplateURLVarName,
144+
serviceTemplate, null);
145+
146+
// fetch all node instances that are running
147+
this.instanceVarsHandler.addNodeInstanceFindLogic(newBackupPlan,
148+
"?state=STARTED&amp;state=CREATED&amp;state=CONFIGURED",
149+
serviceTemplate);
150+
this.instanceVarsHandler.addPropertyVariableUpdateBasedOnNodeInstanceID(newBackupPlan, propMap,
151+
serviceTemplate);
152+
153+
try {
154+
appendGenerateStatefulServiceTemplateLogic(newBackupPlan);
155+
}
156+
catch (final IOException e) {
157+
e.printStackTrace();
158+
}
159+
catch (final SAXException e) {
160+
e.printStackTrace();
161+
}
162+
163+
runPlugins(newBackupPlan, propMap, csarName);
164+
165+
this.correlationHandler.addCorrellationID(newBackupPlan);
166+
this.finalizer.finalize(newBackupPlan);
167+
168+
LOG.debug("Created Plan:");
169+
LOG.debug(ModelUtils.getStringFromDoc(newBackupPlan.getBpelDocument()));
170+
171+
return newBackupPlan;
172+
}
173+
174+
private void runPlugins(final BPELPlan plan, final Property2VariableMapping propMap, final String csarName) {
175+
176+
final String statefulServiceTemplateUrlVarName = findStatefulServiceTemplateUrlVar(plan);
177+
178+
final String serviceInstanceUrl = this.serviceInstanceVarsHandler.findServiceInstanceUrlVariableName(plan);
179+
final String serviceInstanceId = this.serviceInstanceVarsHandler.findServiceInstanceIdVarName(plan);
180+
final String serviceTemplateUrl = this.serviceInstanceVarsHandler.findServiceTemplateUrlVariableName(plan);
181+
182+
183+
for (final BPELScope templatePlan : plan.getTemplateBuildPlans()) {
184+
final BPELPlanContext context = new BPELPlanContext(plan, templatePlan, propMap, plan.getServiceTemplate(),
185+
serviceInstanceUrl, serviceInstanceId, serviceTemplateUrl, csarName);
186+
187+
// only handle NodeTemplates of type with save state interface
188+
final AbstractNodeTemplate nodeTemplate = templatePlan.getNodeTemplate();
189+
if (Objects.nonNull(nodeTemplate)
190+
&& Objects.nonNull(ModelUtils.getInterfaceOfNode(nodeTemplate,
191+
Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE))) {
192+
LOG.debug("Adding backup logic for NodeTemplate {}", nodeTemplate.getName());
193+
194+
final String saveStateUrlVarName =
195+
this.planHandler.addGlobalStringVariable("nodeTemplateStateSaveURL", plan);
196+
197+
final String xpathQuery = "concat($" + statefulServiceTemplateUrlVarName
198+
+ ",'/topologytemplate/nodetemplates/" + nodeTemplate.getId() + "/state')";
199+
try {
200+
Node assignSaveStateURL =
201+
this.bpelFragments.createAssignVarToVarWithXpathQueryAsNode("assignNodeTemplate"
202+
+ nodeTemplate.getId() + "state" + System.currentTimeMillis(),
203+
statefulServiceTemplateUrlVarName,
204+
saveStateUrlVarName, xpathQuery);
205+
assignSaveStateURL = context.importNode(assignSaveStateURL);
206+
context.getPrePhaseElement().appendChild(assignSaveStateURL);
207+
}
208+
catch (final IOException e) {
209+
e.printStackTrace();
210+
}
211+
catch (final SAXException e) {
212+
e.printStackTrace();
213+
}
214+
215+
final AbstractOperation freezeOp =
216+
ModelUtils.getOperationOfNode(nodeTemplate, Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE,
217+
Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE_FREEZE);
218+
if (Objects.nonNull(freezeOp)) {
219+
final Variable saveStateUrlVar = BPELPlanContext.getVariable(saveStateUrlVarName);
220+
221+
final Map<AbstractParameter, Variable> inputs = new HashMap<>();
222+
223+
// retrieve input parameters from all nodes which are downwards in the same topology stack
224+
final List<AbstractNodeTemplate> nodesForMatching = new ArrayList<>();
225+
ModelUtils.getNodesFromNodeToSink(nodeTemplate, nodesForMatching);
226+
227+
LOG.debug("Backup on NodeTemplate {} needs the following input parameters:",
228+
nodeTemplate.getName());
229+
for (final AbstractParameter param : freezeOp.getInputParameters()) {
230+
LOG.debug("Input param: {}", param.getName());
231+
found: for (final AbstractNodeTemplate nodeForMatching : nodesForMatching) {
232+
for (final String propName : ModelUtils.getPropertyNames(nodeForMatching)) {
233+
if (param.getName().equals(propName)) {
234+
inputs.put(param, context.getPropertyVariable(nodeForMatching, propName));
235+
break found;
236+
}
237+
}
238+
}
239+
}
240+
241+
// add special parameter with winery URL
242+
inputs.put(getSaveStateParameter(freezeOp), saveStateUrlVar);
243+
244+
LOG.debug("Found {} of {} input parameters.", inputs.size(), freezeOp.getInputParameters().size());
245+
246+
context.executeOperation(nodeTemplate, Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE,
247+
Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE_FREEZE, inputs);
248+
}
249+
}
250+
}
251+
}
252+
253+
@Override
254+
public List<AbstractPlan> buildPlans(final String csarName, final AbstractDefinitions definitions) {
255+
LOG.info("Building the Backup Management Plans");
256+
final List<AbstractPlan> plans = new ArrayList<>();
257+
for (final AbstractServiceTemplate serviceTemplate : definitions.getServiceTemplates()) {
258+
259+
if (containsManagementInterface(serviceTemplate, Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE)) {
260+
LOG.debug("ServiceTemplate {} contains NodeTypes with defined backup interface.",
261+
serviceTemplate.getName());
262+
final BPELPlan newBuildPlan = buildPlan(csarName, definitions, serviceTemplate);
263+
if (Objects.nonNull(newBuildPlan)) {
264+
LOG.debug("Created Backup Management Plan "
265+
+ newBuildPlan.getBpelProcessElement().getAttribute("name"));
266+
plans.add(newBuildPlan);
267+
}
268+
} else {
269+
LOG.debug("No backup interface defined in ServiceTemplate {}", serviceTemplate.getName());
270+
}
271+
}
272+
return plans;
273+
}
274+
275+
private void appendGenerateStatefulServiceTemplateLogic(final BPELPlan plan) throws IOException, SAXException {
276+
final QName serviceTemplateId = plan.getServiceTemplate().getQName();
277+
278+
this.planHandler.addStringElementToPlanRequest(Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE_FREEZE_MANDATORY_PARAM_ENDPOINT,
279+
plan);
280+
281+
// var to save serviceTemplate url on storage service
282+
final String statefulServiceTemplateVarName =
283+
this.planHandler.addGlobalStringVariable("statefulServiceTemplateUrl" + System.currentTimeMillis(), plan);
284+
final String responseVarName = this.planHandler.createAnyTypeVar(plan);
285+
286+
// assign variable with the original service template url
287+
Node assignStatefuleServiceTemplateStorageVar =
288+
this.bpelFragments.createAssignVarToVarWithXpathQueryAsNode("assignServiceTemplateStorageUrl"
289+
+ System.currentTimeMillis(), "input", statefulServiceTemplateVarName,
290+
"concat(//*[local-name()='"
291+
+ Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE_FREEZE_MANDATORY_PARAM_ENDPOINT
292+
+ "']/text(),'/servicetemplates/"
293+
+ URLEncoder.encode(URLEncoder.encode(serviceTemplateId.getNamespaceURI(),
294+
"UTF-8"),
295+
"UTF-8")
296+
+ "','/" + serviceTemplateId.getLocalPart()
297+
+ "','/createnewstatefulversion')");
298+
assignStatefuleServiceTemplateStorageVar =
299+
plan.getBpelDocument().importNode(assignStatefuleServiceTemplateStorageVar, true);
300+
plan.getBpelMainSequenceElement().insertBefore(assignStatefuleServiceTemplateStorageVar,
301+
plan.getBpelMainSequencePropertyAssignElement());
302+
303+
// create append POST for creating a stateful service template version
304+
Node createStatefulServiceTemplatePOST =
305+
this.bpelFragments.createHTTPPOST(statefulServiceTemplateVarName, responseVarName);
306+
307+
createStatefulServiceTemplatePOST = plan.getBpelDocument().importNode(createStatefulServiceTemplatePOST, true);
308+
309+
plan.getBpelMainSequenceElement().insertBefore(createStatefulServiceTemplatePOST,
310+
plan.getBpelMainSequencePropertyAssignElement());
311+
312+
// read response and assign url of created stateful service template query the localname from the
313+
// response
314+
final String xpathQuery1 =
315+
"concat(substring-before($" + statefulServiceTemplateVarName + ",'" + serviceTemplateId.getLocalPart()
316+
+ "'),encode-for-uri(encode-for-uri(//*[local-name()='QName']/*[local-name()='localname']/text())))";
317+
318+
// query original service template url without the last path fragment(/service template localname)
319+
final String xpathQuery2 = "string($" + statefulServiceTemplateVarName + ")";
320+
Node assignCreatedStatefulServiceTemplate =
321+
this.bpelFragments.createAssignVarToVarWithXpathQueriesAsNode("assignCreatedStatefuleServiceTemplateUrl",
322+
responseVarName, null,
323+
statefulServiceTemplateVarName, null,
324+
xpathQuery1, xpathQuery2,
325+
"change the url from original service template to stateful",
326+
null);
327+
328+
assignCreatedStatefulServiceTemplate =
329+
plan.getBpelDocument().importNode(assignCreatedStatefulServiceTemplate, true);
330+
plan.getBpelMainSequenceElement().insertBefore(assignCreatedStatefulServiceTemplate,
331+
plan.getBpelMainSequencePropertyAssignElement());
332+
}
333+
334+
private String findStatefulServiceTemplateUrlVar(final BPELPlan plan) {
335+
return this.planHandler.getMainVariableNames(plan).stream()
336+
.filter(varName -> varName.contains("statefulServiceTemplateUrl")).findFirst()
337+
.orElse(null);
338+
}
339+
340+
private AbstractParameter getSaveStateParameter(final AbstractOperation op) {
341+
return op.getInputParameters().stream()
342+
.filter(param -> param.getName()
343+
.equals(Interfaces.OPENTOSCA_DECLARATIVE_INTERFACE_STATE_FREEZE_MANDATORY_PARAM_ENDPOINT))
344+
.findFirst().orElse(null);
345+
}
346+
}

0 commit comments

Comments
 (0)