Fix NPE when trying to download restconf provided yang files
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / RestConnectorProvider.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.restconf.nb.rfc8040;
10
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.ImmutableSet;
13 import com.google.common.collect.ImmutableSet.Builder;
14 import java.util.Set;
15 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
17 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
18 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
19 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
20 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
21 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
22 import org.opendaylight.controller.sal.core.api.model.SchemaService;
23 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
24 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
25 import org.opendaylight.restconf.nb.rfc8040.handlers.DOMDataBrokerHandler;
26 import org.opendaylight.restconf.nb.rfc8040.handlers.DOMMountPointServiceHandler;
27 import org.opendaylight.restconf.nb.rfc8040.handlers.NotificationServiceHandler;
28 import org.opendaylight.restconf.nb.rfc8040.handlers.RpcServiceHandler;
29 import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
30 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
31 import org.opendaylight.restconf.nb.rfc8040.services.wrapper.ServiceWrapper;
32 import org.opendaylight.yangtools.concepts.ListenerRegistration;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Provider for restconf draft18.
39  *
40  */
41 public class RestConnectorProvider<T extends ServiceWrapper> implements RestconfConnector, AutoCloseable {
42
43     private static final Logger LOG = LoggerFactory.getLogger(RestConnectorProvider.class);
44
45     public static final TransactionChainListener TRANSACTION_CHAIN_LISTENER = new TransactionChainListener() {
46         @Override
47         public void onTransactionChainFailed(final TransactionChain<?, ?> chain,
48                 final AsyncTransaction<?, ?> transaction, final Throwable cause) {
49             LOG.warn("TransactionChain({}) {} FAILED!", chain, transaction.getIdentifier(), cause);
50             resetTransactionChainForAdapaters(chain);
51             throw new RestconfDocumentedException("TransactionChain(" + chain + ") not committed correctly", cause);
52         }
53
54         @Override
55         public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
56             LOG.trace("TransactionChain({}) {} SUCCESSFUL", chain);
57         }
58     };
59
60     private static TransactionChainHandler transactionChainHandler;
61     private static DOMDataBroker dataBroker;
62     private static DOMMountPointServiceHandler mountPointServiceHandler;
63
64     private final SchemaService schemaService;
65     private final DOMRpcService rpcService;
66     private final DOMNotificationService notificationService;
67     private final DOMMountPointService mountPointService;
68     private final DOMSchemaService domSchemaService;
69     private final Builder<Object> servicesProperties;
70
71     private ListenerRegistration<SchemaContextListener> listenerRegistration;
72     private SchemaContextHandler schemaCtxHandler;
73     private T wrapperServices;
74
75     // FIXME: refactor this class and its users to interact via builder pattern, where individual
76     // services are injected and then the provider is created
77     public RestConnectorProvider(final DOMDataBroker domDataBroker,
78              final SchemaService schemaService, final DOMRpcService rpcService,
79              final DOMNotificationService notificationService, final DOMMountPointService mountPointService,
80              final DOMSchemaService domSchemaService) {
81         this(domDataBroker, schemaService, rpcService, notificationService, mountPointService, domSchemaService, null);
82
83     }
84
85     public RestConnectorProvider(final DOMDataBroker domDataBroker, final SchemaService schemaService,
86                                  final DOMRpcService rpcService,
87                                  final DOMNotificationService notificationService,
88                                  final DOMMountPointService mountPointService,
89                                  final DOMSchemaService domSchemaService, final T wrapperServices) {
90         this.servicesProperties = ImmutableSet.<Object>builder();
91         this.wrapperServices = wrapperServices;
92         this.schemaService = Preconditions.checkNotNull(schemaService);
93         this.rpcService = Preconditions.checkNotNull(rpcService);
94         this.notificationService = Preconditions.checkNotNull(notificationService);
95         this.mountPointService = Preconditions.checkNotNull(mountPointService);
96         this.domSchemaService = Preconditions.checkNotNull(domSchemaService);
97
98         RestConnectorProvider.dataBroker = Preconditions.checkNotNull(domDataBroker);
99     }
100
101     public synchronized void start() {
102         mountPointServiceHandler = new DOMMountPointServiceHandler(mountPointService);
103         servicesProperties.add(mountPointServiceHandler);
104
105         final DOMDataBrokerHandler brokerHandler = new DOMDataBrokerHandler(dataBroker);
106         servicesProperties.add(brokerHandler);
107
108         RestConnectorProvider.transactionChainHandler = new TransactionChainHandler(dataBroker
109                 .createTransactionChain(RestConnectorProvider.TRANSACTION_CHAIN_LISTENER));
110         servicesProperties.add(transactionChainHandler);
111
112         this.schemaCtxHandler = new SchemaContextHandler(transactionChainHandler);
113         servicesProperties.add(schemaCtxHandler);
114         this.listenerRegistration = schemaService.registerSchemaContextListener(this.schemaCtxHandler);
115
116         final RpcServiceHandler rpcServiceHandler = new RpcServiceHandler(rpcService);
117         servicesProperties.add(rpcServiceHandler);
118
119         final NotificationServiceHandler notificationServiceHandler =
120                 new NotificationServiceHandler(notificationService);
121         servicesProperties.add(notificationServiceHandler);
122
123         if (wrapperServices != null) {
124             wrapperServices.setHandlers(this.schemaCtxHandler, RestConnectorProvider.mountPointServiceHandler,
125                     RestConnectorProvider.transactionChainHandler, brokerHandler, rpcServiceHandler,
126                     notificationServiceHandler, domSchemaService);
127         }
128     }
129
130     public DOMMountPointServiceHandler getMountPointServiceHandler() {
131         return mountPointServiceHandler;
132     }
133
134     /**
135      * After {@link TransactionChain} failed, this updates {@link TransactionChainHandler} with new transaction chain.
136      *
137      * @param chain
138      *             old {@link TransactionChain}
139      */
140     public static void resetTransactionChainForAdapaters(final TransactionChain<?, ?> chain) {
141         LOG.trace("Resetting TransactionChain({})", chain);
142         chain.close();
143         RestConnectorProvider.transactionChainHandler.update(
144                 Preconditions.checkNotNull(dataBroker).createTransactionChain(
145                         RestConnectorProvider.TRANSACTION_CHAIN_LISTENER)
146         );
147     }
148
149     /**
150      * Get current {@link DOMMountPointService} from {@link DOMMountPointServiceHandler}.
151      * @return {@link DOMMountPointService}
152      */
153     public static DOMMountPointService getMountPointService() {
154         return mountPointServiceHandler.get();
155     }
156
157     @Override
158     public void close() throws Exception {
159         // close registration
160         if (this.listenerRegistration != null) {
161             this.listenerRegistration.close();
162         }
163
164         // close transaction chain
165         if (transactionChainHandler != null && transactionChainHandler.get() != null) {
166             transactionChainHandler.get().close();
167         }
168
169         transactionChainHandler = null;
170         mountPointServiceHandler = null;
171         dataBroker = null;
172     }
173
174     public final synchronized Set<Object> getServicesProperties() {
175         return servicesProperties.build();
176     }
177 }