BUG-1120: fix race window in unregistration
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / impl / MountPointManagerImpl.java
1 /*
2  * Copyright (c) 2014 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 package org.opendaylight.controller.sal.binding.impl;
9
10 import java.util.concurrent.ConcurrentHashMap;
11 import java.util.concurrent.ConcurrentMap;
12
13 import org.opendaylight.controller.md.sal.binding.util.AbstractBindingSalProviderInstance;
14 import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance;
15 import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
16 import org.opendaylight.yangtools.concepts.ListenerRegistration;
17 import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
18 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 import com.google.common.util.concurrent.ListeningExecutorService;
23
24 public class MountPointManagerImpl implements MountProviderService {
25
26     public final Logger LOG = LoggerFactory.getLogger(MountPointManagerImpl.class);
27
28     private final ConcurrentMap<InstanceIdentifier<?>, BindingMountPointImpl> mountPoints;
29     private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
30
31     private ListeningExecutorService notificationExecutor;
32     private ListeningExecutorService dataCommitExecutor;
33
34     public MountPointManagerImpl() {
35         mountPoints = new ConcurrentHashMap<>();
36     }
37
38     public ListeningExecutorService getNotificationExecutor() {
39         return notificationExecutor;
40     }
41
42     public void setNotificationExecutor(final ListeningExecutorService notificationExecutor) {
43         this.notificationExecutor = notificationExecutor;
44     }
45
46     public ListeningExecutorService getDataCommitExecutor() {
47         return dataCommitExecutor;
48     }
49
50     public void setDataCommitExecutor(final ListeningExecutorService dataCommitExecutor) {
51         this.dataCommitExecutor = dataCommitExecutor;
52     }
53
54     @Override
55     public synchronized BindingMountPointImpl createMountPoint(final InstanceIdentifier<?> path) {
56         BindingMountPointImpl potential = mountPoints.get(path);
57         if (potential != null) {
58             throw new IllegalStateException("Mount point already exists.");
59         }
60         return createOrGetMountPointImpl(path);
61     }
62
63     @Override
64     public BindingMountPointImpl createOrGetMountPoint(final InstanceIdentifier<?> path) {
65         BindingMountPointImpl potential = getMountPoint(path);
66         if (potential != null) {
67             return potential;
68         }
69         return createOrGetMountPointImpl(path);
70     }
71
72     @Override
73     public BindingMountPointImpl getMountPoint(final InstanceIdentifier<?> path) {
74         return mountPoints.get(path);
75     }
76
77     private synchronized BindingMountPointImpl createOrGetMountPointImpl(final InstanceIdentifier<?> path) {
78         BindingMountPointImpl potential = getMountPoint(path);
79         if (potential != null) {
80             return potential;
81         }
82         RpcProviderRegistryImpl rpcRegistry = new RpcProviderRegistryImpl("mount");
83         NotificationBrokerImpl notificationBroker = new NotificationBrokerImpl(getNotificationExecutor());
84         DataBrokerImpl dataBroker = new DataBrokerImpl();
85         dataBroker.setExecutor(getDataCommitExecutor());
86         BindingMountPointImpl mountInstance = new BindingMountPointImpl(path, rpcRegistry, notificationBroker,
87                 dataBroker);
88         mountPoints.putIfAbsent(path, mountInstance);
89         notifyMountPointCreated(path);
90         return mountInstance;
91     }
92
93     private void notifyMountPointCreated(final InstanceIdentifier<?> path) {
94         for (ListenerRegistration<MountProvisionListener> listener : listeners) {
95             try {
96                 listener.getInstance().onMountPointCreated(path);
97             } catch (Exception e) {
98                 LOG.error("Unhandled exception during invoking listener.", e);
99             }
100         }
101     }
102
103     @Override
104     public ListenerRegistration<MountProvisionListener> registerProvisionListener(final MountProvisionListener listener) {
105         return listeners.register(listener);
106     }
107
108     public class BindingMountPointImpl extends
109     AbstractBindingSalProviderInstance<DataBrokerImpl, NotificationBrokerImpl, RpcProviderRegistryImpl>
110     implements MountProviderInstance {
111
112         private final InstanceIdentifier<?> identifier;
113
114         public BindingMountPointImpl(final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> identifier,
115                 final RpcProviderRegistryImpl rpcRegistry, final NotificationBrokerImpl notificationBroker,
116                 final DataBrokerImpl dataBroker) {
117             super(rpcRegistry, notificationBroker, dataBroker);
118             this.identifier = identifier;
119         }
120
121         // Needed only for BI Connector
122         public DataBrokerImpl getDataBrokerImpl() {
123             return getDataBroker();
124         }
125
126         @Override
127         public InstanceIdentifier<?> getIdentifier() {
128             return this.identifier;
129         }
130     }
131 }