2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.sdnc.sliapi;
24 import java.util.Enumeration;
25 import java.util.LinkedList;
26 import java.util.Properties;
27 import java.util.concurrent.Future;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.binding.impl.AbstractForwardedDataBroker;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
37 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
38 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
39 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
40 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphInput;
41 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphInput.Mode;
42 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphInputBuilder;
43 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphOutput;
44 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.ExecuteGraphOutputBuilder;
45 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.HealthcheckOutput;
46 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.HealthcheckOutputBuilder;
47 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.SLIAPIService;
48 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.TestResults;
49 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.execute.graph.input.SliParameter;
50 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.test.results.TestResult;
51 import org.opendaylight.yang.gen.v1.org.openecomp.sdnc.sliapi.rev161110.test.results.TestResultBuilder;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.opendaylight.yangtools.yang.common.QName;
54 import org.opendaylight.yangtools.yang.common.RpcResult;
55 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
56 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
57 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
58 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
59 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
60 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
61 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
62 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
63 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
64 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
65 import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
66 import org.openecomp.sdnc.sli.provider.SvcLogicService;
67 import org.osgi.framework.BundleContext;
68 import org.osgi.framework.FrameworkUtil;
69 import org.osgi.framework.ServiceReference;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
73 import com.google.common.util.concurrent.Futures;
77 * Defines a base implementation for your provider. This class extends from a helper class
78 * which provides storage for the most commonly used components of the MD-SAL. Additionally the
79 * base class provides some basic logging and initialization / clean up methods.
81 * To use this, copy and paste (overwrite) the following method into the TestApplicationProviderModule
82 * class which is auto generated under src/main/java in this project
83 * (created only once during first compilation):
88 public java.lang.AutoCloseable createInstance() {
90 final sliapiProvider provider = new sliapiProvider();
91 provider.setDataBroker( getDataBrokerDependency() );
92 provider.setNotificationService( getNotificationServiceDependency() );
93 provider.setRpcRegistry( getRpcRegistryDependency() );
94 provider.initialize();
95 return new AutoCloseable() {
98 public void close() throws Exception {
99 //TODO: CLOSE ANY REGISTRATION OBJECTS CREATED USING ABOVE BROKER/NOTIFICATION
100 //SERVIE/RPC REGISTRY
109 public class sliapiProvider implements AutoCloseable, SLIAPIService{
111 private final Logger LOG = LoggerFactory.getLogger( sliapiProvider.class );
112 private final String appName = "slitester";
114 protected DataBroker dataBroker;
115 protected DOMDataBroker domDataBroker;
116 protected NotificationProviderService notificationService;
117 protected RpcProviderRegistry rpcRegistry;
119 protected BindingAwareBroker.RpcRegistration<SLIAPIService> rpcRegistration;
121 private static String SLIAPI_NAMESPACE = "org:openecomp:sdnc:sliapi";
122 private static String SLIAPI_REVISION = "2016-11-10";
124 private static QName TEST_RESULTS_QNAME = null;
125 private static QName TEST_RESULT_QNAME = null;
126 private static QName TEST_ID_QNAME = null;
127 private static QName RESULTS_QNAME = null;
131 TEST_RESULTS_QNAME = QName.create(SLIAPI_NAMESPACE, SLIAPI_REVISION, "test-results");
132 TEST_RESULT_QNAME = QName.create(TEST_RESULTS_QNAME, "test-result");
133 TEST_ID_QNAME = QName.create(TEST_RESULT_QNAME, "test-identifier");
134 RESULTS_QNAME = QName.create(TEST_RESULT_QNAME, "results");
138 public sliapiProvider() {
139 this.LOG.info( "Creating provider for " + appName );
142 public void initialize(){
143 LOG.info( "Initializing provider for " + appName );
144 //initialization code goes here.
146 rpcRegistration = rpcRegistry.addRpcImplementation(SLIAPIService.class, this);
147 LOG.info( "Initialization complete for " + appName );
150 protected void initializeChild() {
151 //Override if you have custom initialization intelligence
155 public void close() throws Exception {
156 LOG.info( "Closing provider for " + appName );
157 //closing code goes here
159 rpcRegistration.close();
160 LOG.info( "Successfully closed provider for " + appName );
163 public void setDataBroker(DataBroker dataBroker) {
164 this.dataBroker = dataBroker;
165 if (dataBroker instanceof AbstractForwardedDataBroker) {
166 domDataBroker = ((AbstractForwardedDataBroker) dataBroker).getDelegate();
168 if( LOG.isDebugEnabled() ){
169 LOG.debug( "DataBroker set to " + (dataBroker==null?"null":"non-null") + "." );
173 public void setNotificationService(
174 NotificationProviderService notificationService) {
175 this.notificationService = notificationService;
176 if( LOG.isDebugEnabled() ){
177 LOG.debug( "Notification Service set to " + (notificationService==null?"null":"non-null") + "." );
181 public void setRpcRegistry(RpcProviderRegistry rpcRegistry) {
182 this.rpcRegistry = rpcRegistry;
183 if( LOG.isDebugEnabled() ){
184 LOG.debug( "RpcRegistry set to " + (rpcRegistry==null?"null":"non-null") + "." );
189 public Future<RpcResult<ExecuteGraphOutput>> executeGraph(ExecuteGraphInput input) {
190 RpcResult<ExecuteGraphOutput> rpcResult = null;
192 SvcLogicService svcLogic = getSvcLogicService();
193 ExecuteGraphOutputBuilder respBuilder = new ExecuteGraphOutputBuilder();
195 String calledModule = input.getModuleName();
196 String calledRpc = input.getRpcName();
197 Mode calledMode = input.getMode();
198 String modeStr = "sync";
200 if (calledMode == Mode.Async) {
204 if (svcLogic == null) {
205 respBuilder.setResponseCode("500");
206 respBuilder.setResponseMessage("Could not locate OSGi SvcLogicService service");
207 respBuilder.setAckFinalIndicator("Y");
209 rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build();
210 return(Futures.immediateFuture(rpcResult));
215 if (!svcLogic.hasGraph(calledModule, calledRpc, null, modeStr)) {
216 respBuilder.setResponseCode("404");
217 respBuilder.setResponseMessage("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found");
218 respBuilder.setAckFinalIndicator("Y");
220 rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build();
221 return(Futures.immediateFuture(rpcResult));
223 } catch (Exception e) {
224 LOG.error("Caught exception looking for directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr, e);
226 respBuilder.setResponseCode("500");
227 respBuilder.setResponseMessage("Internal error : could not determine if target graph exists");
228 respBuilder.setAckFinalIndicator("Y");
230 rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true).withResult(respBuilder.build()).build();
231 return(Futures.immediateFuture(rpcResult));
235 Properties parms = new Properties();
237 // Pass properties using names from sli-parameters
238 for (SliParameter sliParm : input.getSliParameter()) {
240 String propValue = "";
242 Boolean boolval = sliParm.isBooleanValue();
244 if (boolval != null) {
245 propValue = boolval.toString();
247 Integer intval = sliParm.getIntValue();
248 if (intval != null) {
249 propValue = intval.toString();
251 propValue = sliParm.getStringValue();
252 if (propValue == null) {
257 parms.setProperty(sliParm.getParameterName(), propValue);
260 // Also, pass "meta" properties (i.e. pass SliParameter objects themselves)
261 ExecuteGraphInputBuilder inputBuilder = new ExecuteGraphInputBuilder(input);
263 SliapiHelper.toProperties(parms, "input", inputBuilder);
266 LOG.info("Calling directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr);
268 if (LOG.isTraceEnabled()) {
269 StringBuffer argList = new StringBuffer();
270 argList.append("Parameters : {");
271 Enumeration e = parms.propertyNames();
272 while (e.hasMoreElements()) {
273 String propName = (String) e.nextElement();
274 argList.append(" ("+propName+","+parms.getProperty(propName)+") ");
277 LOG.trace(argList.toString());
283 Properties respProps = svcLogic.execute(calledModule, calledRpc,
284 null, modeStr, parms, domDataBroker);
286 StringBuilder sb = new StringBuilder("{");
288 for (Object key : respProps.keySet()) {
289 String keyValue = (String) key;
290 if (keyValue != null && !"".equals(keyValue) && !keyValue.contains("input.sli-parameter")) {
291 sb.append("\"").append(keyValue).append("\": \"").append(respProps.getProperty(keyValue)).append("\",");
295 sb.setLength(sb.length() - 1);
298 respBuilder.setResponseCode(respProps.getProperty("error-code", "0"));
299 respBuilder.setResponseMessage(respProps.getProperty("error-message", ""));// TODO change response-text to response-message to match other BVC APIs
300 respBuilder.setAckFinalIndicator(respProps.getProperty("ack-final", "Y"));
301 respBuilder.setContextMemoryJson(sb.toString());
303 TestResultBuilder testResultBuilder = new TestResultBuilder();
305 SliapiHelper.toBuilder(respProps, testResultBuilder);
307 String testIdentifier = testResultBuilder.getTestIdentifier();
309 if ((testIdentifier != null) && (testIdentifier.length() > 0)) {
311 // Add test results to config tree
312 LOG.debug("Saving test results for test id "+testIdentifier);
314 DomSaveTestResult(testResultBuilder.build(), true, LogicalDatastoreType.CONFIGURATION);
318 } catch (Exception e) {
319 LOG.error("Caught exception executing directed graph for"
320 + calledModule + ":" + calledRpc + "," + modeStr + ">", e);
322 respBuilder.setResponseCode("500");
324 .setResponseMessage("Internal error : caught exception executing directed graph "
330 respBuilder.setAckFinalIndicator("Y");
334 rpcResult = RpcResultBuilder.<ExecuteGraphOutput> status(true)
335 .withResult(respBuilder.build()).build();
336 return (Futures.immediateFuture(rpcResult));
340 private SvcLogicService getSvcLogicService() {
341 BundleContext bctx = FrameworkUtil.getBundle(SvcLogicService.class).getBundleContext();
343 SvcLogicService svcLogic = null;
345 // Get SvcLogicService reference
346 ServiceReference sref = bctx.getServiceReference(SvcLogicService.NAME);
349 svcLogic = (SvcLogicService) bctx.getService(sref);
354 LOG.warn("Cannot find service reference for "+SvcLogicService.NAME);
362 public Future<RpcResult<HealthcheckOutput>> healthcheck() {
364 RpcResult<HealthcheckOutput> rpcResult = null;
365 SvcLogicService svcLogic = getSvcLogicService();
367 HealthcheckOutputBuilder respBuilder = new HealthcheckOutputBuilder();
369 String calledModule = "sli";
370 String calledRpc = "healthcheck";
371 String modeStr = "sync";
373 if (svcLogic == null) {
374 respBuilder.setResponseCode("500");
375 respBuilder.setResponseMessage("Could not locate OSGi SvcLogicService service");
376 respBuilder.setAckFinalIndicator("Y");
378 rpcResult = RpcResultBuilder.<HealthcheckOutput> failed().withResult(respBuilder.build()).build();
379 return(Futures.immediateFuture(rpcResult));
383 if (!svcLogic.hasGraph(calledModule, calledRpc, null, modeStr)) {
384 respBuilder.setResponseCode("404");
385 respBuilder.setResponseMessage("Directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr+" not found");
387 respBuilder.setAckFinalIndicator("Y");
389 rpcResult = RpcResultBuilder.<HealthcheckOutput> status(true).withResult(respBuilder.build()).build();
390 return(Futures.immediateFuture(rpcResult));
392 } catch (Exception e) {
393 LOG.error("Caught exception looking for directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr, e);
395 respBuilder.setResponseCode("500");
396 respBuilder.setResponseMessage("Internal error : could not determine if target graph exists");
397 respBuilder.setAckFinalIndicator("Y");
399 rpcResult = RpcResultBuilder.<HealthcheckOutput> failed().withResult(respBuilder.build()).build();
400 return(Futures.immediateFuture(rpcResult));
404 LOG.info("Calling directed graph for "+calledModule+"/"+calledRpc+"/"+modeStr);
406 Properties parms = new Properties();
408 Properties respProps = svcLogic.execute(calledModule, calledRpc,
409 null, modeStr, parms);
411 respBuilder.setResponseCode(respProps.getProperty("error-code", "0"));
412 respBuilder.setResponseMessage(respProps.getProperty("error-message", ""));
413 respBuilder.setAckFinalIndicator(respProps.getProperty("ack-final", "Y"));
415 } catch (Exception e) {
416 LOG.error("Caught exception executing directed graph for"
417 + calledModule + ":" + calledRpc + "," + modeStr + ">", e);
419 respBuilder.setResponseCode("500");
421 .setResponseMessage("Internal error : caught exception executing directed graph "
427 respBuilder.setAckFinalIndicator("Y");
431 rpcResult = RpcResultBuilder.<HealthcheckOutput> status(true)
432 .withResult(respBuilder.build()).build();
433 return (Futures.immediateFuture(rpcResult));
436 private void DomSaveTestResult(final TestResult entry, boolean merge, LogicalDatastoreType storeType) {
439 if (domDataBroker == null) {
440 LOG.error("domDataBroker unset - cannot save test result using DOMDataBroker");
444 MapEntryNode resultNode = null;
447 resultNode = toMapEntryNode(entry);
448 } catch (Exception e) {
449 LOG.error("Caught exception trying to create map entry node", e);
452 if (resultNode == null) {
453 LOG.error("Could not convert entry to MapEntryNode");
458 YangInstanceIdentifier testResultsPid = YangInstanceIdentifier.builder().node(TEST_RESULTS_QNAME).node(QName.create(TEST_RESULTS_QNAME, "test-result")).build();
459 YangInstanceIdentifier testResultPid = testResultsPid.node(new NodeIdentifierWithPredicates(TEST_RESULT_QNAME, resultNode.getIdentifier().getKeyValues()));
466 DOMDataWriteTransaction wtx = domDataBroker.newWriteOnlyTransaction();
468 LOG.info("Merging test identifier "+entry.getTestIdentifier());
469 wtx.merge(storeType, testResultPid, resultNode);
471 LOG.info("Putting test identifier "+entry.getTestIdentifier());
472 wtx.put(storeType, testResultPid, resultNode);
474 wtx.submit().checkedGet();
475 LOG.trace("Update DataStore succeeded");
477 } catch (final TransactionCommitFailedException e) {
478 if(e instanceof OptimisticLockFailedException) {
480 LOG.trace("Got OptimisticLockFailedException on last try - failing ");
481 throw new IllegalStateException(e);
483 LOG.trace("Got OptimisticLockFailedException - trying again ");
485 LOG.trace("Update DataStore failed");
486 throw new IllegalStateException(e);
493 private void SaveTestResult(final TestResult entry, boolean merge, LogicalDatastoreType storeType) throws IllegalStateException
495 // Each entry will be identifiable by a unique key, we have to create that identifier
496 InstanceIdentifier.InstanceIdentifierBuilder<TestResult> testResultIdBuilder =
497 InstanceIdentifier.<TestResults>builder(TestResults.class)
498 .child(TestResult.class, entry.getKey());
499 InstanceIdentifier<TestResult> path = testResultIdBuilder.toInstance();
503 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
505 tx.merge(storeType, path, entry);
507 tx.put(storeType, path, entry);
509 tx.submit().checkedGet();
510 LOG.trace("Update DataStore succeeded");
512 } catch (final TransactionCommitFailedException e) {
513 if(e instanceof OptimisticLockFailedException) {
515 LOG.trace("Got OptimisticLockFailedException on last try - failing ");
516 throw new IllegalStateException(e);
518 LOG.trace("Got OptimisticLockFailedException - trying again ");
520 LOG.trace("Update DataStore failed");
521 throw new IllegalStateException(e);
527 private MapEntryNode toMapEntryNode(TestResult testResult) {
530 YangInstanceIdentifier testResultId = YangInstanceIdentifier.builder().node(TEST_RESULTS_QNAME).node(TEST_RESULT_QNAME).build();
532 // Construct results list
533 LinkedList<LeafSetEntryNode<Object>> entryList = new LinkedList<LeafSetEntryNode<Object>>();
534 for (String result : testResult.getResults()) {
535 LeafSetEntryNode<Object> leafSetEntryNode = ImmutableLeafSetEntryNodeBuilder.create()
536 .withNodeIdentifier(new NodeWithValue(RESULTS_QNAME, result))
539 entryList.add(leafSetEntryNode);
541 // Construct results LeafSetNode
542 LeafSetNode<?> resultsNode = ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(new NodeIdentifier(RESULTS_QNAME)).withValue(entryList).build();
546 // Construct test result ContainerNode with 2 children - test-identifier leaf and results leaf-set
547 MapEntryNode testResultNode = ImmutableNodes.mapEntryBuilder()
548 .withNodeIdentifier(new NodeIdentifierWithPredicates(TEST_RESULT_QNAME, TEST_ID_QNAME, testResult.getTestIdentifier()))
549 .withChild(ImmutableNodes.leafNode(TEST_ID_QNAME, testResult.getTestIdentifier()))
550 .withChild(resultsNode)
553 return(testResultNode);