BUG-6858: adapt to ise api, change lookup from ise
[groupbasedpolicy.git] / sxp-integration / sxp-ise-adapter / src / main / java / org / opendaylight / groupbasedpolicy / sxp_ise_adapter / impl / GbpIseConfigListenerImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.sxp_ise_adapter.impl;
10
11 import com.google.common.util.concurrent.CheckedFuture;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.ThreadFactoryBuilder;
16 import java.text.SimpleDateFormat;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.LinkedBlockingQueue;
22 import java.util.concurrent.ThreadPoolExecutor;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import javax.annotation.Nonnull;
26 import javax.annotation.Nullable;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
29 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.GbpSxpIseAdapter;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.gbp.sxp.ise.adapter.IseHarvestStatus;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.gbp.sxp.ise.adapter.IseHarvestStatusBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ise.adapter.model.rev160630.gbp.sxp.ise.adapter.IseSourceConfig;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * Purpose: listen for harvest configuration and trigger harvesting
43  */
44 public class GbpIseConfigListenerImpl implements GbpIseConfigListener {
45
46     private static final Logger LOG = LoggerFactory.getLogger(GbpIseConfigListenerImpl.class);
47
48     private static final String DATE_AND_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
49
50     private final DataBroker dataBroker;
51     private final GbpIseSgtHarvester gbpIseSgtHarvester;
52     @Nonnull private final EPPolicyTemplateProviderFacade templateProviderFacade;
53     private final ThreadPoolExecutor pool;
54
55     public GbpIseConfigListenerImpl(@Nonnull final DataBroker dataBroker, @Nonnull final GbpIseSgtHarvester gbpIseSgtHarvester,
56                                     @Nonnull final EPPolicyTemplateProviderFacade templateProviderFacade) {
57         this.dataBroker = dataBroker;
58         this.gbpIseSgtHarvester = gbpIseSgtHarvester;
59         this.templateProviderFacade = templateProviderFacade;
60         pool = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10),
61                 new ThreadFactoryBuilder().setNameFormat("ise-sgt-harverster-%d").build()) {
62             @Override
63             protected void afterExecute(final Runnable r, final Throwable t) {
64                 super.afterExecute(r, t);
65                 if (t != null) {
66                     LOG.warn("ise harvest task failed", t);
67                 }
68             }
69         };
70     }
71
72     @Override
73     public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<IseSourceConfig>> collection) {
74         for (DataTreeModification<IseSourceConfig> modification : collection) {
75             final IseSourceConfig iseSourceConfig = modification.getRootNode().getDataAfter();
76             //TODO: separate template provider from harvesting
77             final IseContext iseContext = new IseContext(iseSourceConfig);
78             templateProviderFacade.assignIseContext(iseContext);
79             if (iseSourceConfig != null) {
80                 pool.submit(() -> {
81                     final ListenableFuture<Collection<SgtInfo>> harvestResult = gbpIseSgtHarvester.harvestAll(iseContext);
82                     Futures.addCallback(harvestResult, new FutureCallback<Collection<SgtInfo>>() {
83                         @Override
84                         public void onSuccess(@Nullable final Collection<SgtInfo> result) {
85                             LOG.debug("ise harvest finished, outcome: {}", result);
86                             storeOutcome(true, Optional.ofNullable(result).map(Collection::size).orElse(0), null);
87                         }
88
89                         @Override
90                         public void onFailure(final Throwable t) {
91                             LOG.debug("ise harvest failed", t);
92                             storeOutcome(false, 0, t.getMessage());
93                         }
94                     });
95
96                     try {
97                         harvestResult.get(30, TimeUnit.SECONDS);
98                     } catch (InterruptedException | ExecutionException | TimeoutException e) {
99                         LOG.debug("failed to finish ise-sgt-harvest task properly on time", e);
100                     }
101                 });
102             }
103         }
104     }
105
106     private CheckedFuture<Void, TransactionCommitFailedException> storeOutcome(final boolean succeeded, final int counter, final String reason) {
107         final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
108         final InstanceIdentifier<IseHarvestStatus> harvestStatusPath = InstanceIdentifier.create(GbpSxpIseAdapter.class)
109                 .child(IseHarvestStatus.class);
110         final IseHarvestStatus harvestStatus = new IseHarvestStatusBuilder()
111                 .setReason(reason)
112                 .setSuccess(succeeded)
113                 .setTemplatesWritten(counter)
114                 .setTimestamp(createDateTime(new Date()))
115                 .build();
116         wTx.put(LogicalDatastoreType.OPERATIONAL, harvestStatusPath, harvestStatus, true);
117         return wTx.submit();
118     }
119
120     private static DateAndTime createDateTime(Date when) {
121         final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_AND_TIME_FORMAT);
122         return new DateAndTime(simpleDateFormat.format(when));
123     }
124
125     @Override
126     public void close() throws Exception {
127         if (!pool.isTerminated()) {
128             pool.shutdown();
129             final boolean terminated = pool.awaitTermination(10, TimeUnit.SECONDS);
130             if (! terminated) {
131                 pool.shutdownNow();
132             }
133         }
134     }
135 }