Fix findbugs violations in resourcemanager-impl
[genius.git] / resourcemanager / resourcemanager-impl / src / main / java / org / opendaylight / genius / resourcemanager / ResourceManager.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.genius.resourcemanager;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.Futures;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Objects;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20 import javax.annotation.PreDestroy;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeInputBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.AllocateResourceInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.AllocateResourceOutput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.AllocateResourceOutputBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.GetAvailableResourcesInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.GetAvailableResourcesOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.GetAvailableResourcesOutputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.GetResourcePoolInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.GetResourcePoolOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.GetResourcePoolOutputBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.ReleaseResourceInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.ResourceManagerService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.ResourceTypeBase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.ResourceTypeGroupIds;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.ResourceTypeMeterIds;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.ResourceTypeTableIds;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.getresourcepool.output.AvailableIds;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.getresourcepool.output.AvailableIdsBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.released.resource.ids.DelayedResourceEntries;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.resourcemanager.rev160622.released.resource.ids.DelayedResourceEntriesBuilder;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.common.RpcError;
57 import org.opendaylight.yangtools.yang.common.RpcResult;
58 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 @Singleton
63 public class ResourceManager implements ResourceManagerService, AutoCloseable {
64     // Property names
65     private static final String RESOURCE_TABLES_NAME_PROPERTY = "resource.tables.name";
66     private static final String RESOURCE_GROUPS_NAME_PROPERTY = "resource.groups.name";
67     private static final String RESOURCE_METERS_NAME_PROPERTY = "resource.meters.name";
68
69     private static final String RESOURCE_TABLES_START_ID_PROPERTY = "resource.tables.startId";
70     private static final String RESOURCE_TABLES_END_ID_PROPERTY = "resource.tables.endId";
71     private static final String RESOURCE_GROUPS_START_ID_PROPERTY = "resource.groups.startId";
72     private static final String RESOURCE_GROUPS_END_ID_PROPERTY = "resource.groups.endId";
73     private static final String RESOURCE_METERS_START_ID_PROPERTY = "resource.meters.startId";
74     private static final String RESOURCE_METERS_END_ID_PROPERTY = "resource.meters.endId";
75
76     // Cache default values
77     private static final String RESOURCE_TABLES_DEFAULT_NAME = "tables";
78     private static final String RESOURCE_GROUPS_DEFAULT_NAME = "groups";
79     private static final String RESOURCE_METERS_DEFAULT_NAME = "meters";
80
81     // Default ranges of IDs
82     private static final String DEFAULT_LOW_RANGE = "0";
83     private static final String DEFAULT_HIGH_RANGE = "254";
84
85     // Messages
86     private static final String RESOURCE_TYPE_CANNOT_BE_NULL = "Resource type cannot be null";
87     private static final String RESOURCE_TYPE_NOT_FOUND = "Resource type not found";
88     private static final String RESOURCE_ID_CANNOT_BE_NULL = "Id key cannot be null";
89     private static final String RESOURCE_SIZE_CANNOT_BE_NULL = "Resource size cannot be null";
90
91     // Other services
92     private final DataBroker dataBroker;
93     private final IdManagerService idManager;
94
95     // Cache of resources
96     private final ConcurrentMap<Class<? extends ResourceTypeBase>, String> resourcesCache;
97
98     private static final Logger LOG = LoggerFactory.getLogger(ResourceManager.class);
99
100     @Inject
101     public ResourceManager(final DataBroker dataBroker, final IdManagerService idManager) {
102         this.dataBroker = dataBroker;
103         this.idManager = idManager;
104         this.resourcesCache = loadCache();
105         createIdpools();
106     }
107
108     private ConcurrentMap<Class<? extends ResourceTypeBase>, String> loadCache() {
109         ConcurrentMap<Class<? extends ResourceTypeBase>, String> cache = new ConcurrentHashMap<>();
110         cache.put(ResourceTypeTableIds.class,
111                 System.getProperty(RESOURCE_TABLES_NAME_PROPERTY, RESOURCE_TABLES_DEFAULT_NAME));
112         cache.put(ResourceTypeGroupIds.class,
113                 System.getProperty(RESOURCE_GROUPS_NAME_PROPERTY, RESOURCE_GROUPS_DEFAULT_NAME));
114         cache.put(ResourceTypeMeterIds.class,
115                 System.getProperty(RESOURCE_METERS_NAME_PROPERTY, RESOURCE_METERS_DEFAULT_NAME));
116         return cache;
117     }
118
119     @Override
120     public Future<RpcResult<AllocateResourceOutput>> allocateResource(AllocateResourceInput input) {
121         Objects.requireNonNull(input.getResourceType(), RESOURCE_TYPE_CANNOT_BE_NULL);
122         Objects.requireNonNull(input.getIdKey(), RESOURCE_ID_CANNOT_BE_NULL);
123         Objects.requireNonNull(input.getSize(), RESOURCE_SIZE_CANNOT_BE_NULL);
124
125         Objects.requireNonNull(resourcesCache.get(input.getResourceType()), RESOURCE_TYPE_NOT_FOUND);
126
127         AllocateIdRangeInputBuilder allocateIdRangeBuilder = new AllocateIdRangeInputBuilder();
128         allocateIdRangeBuilder.setIdKey(input.getIdKey()).setPoolName(resourcesCache.get(input.getResourceType()))
129                 .setSize(input.getSize());
130         Future<RpcResult<AllocateIdRangeOutput>> output = idManager.allocateIdRange(allocateIdRangeBuilder.build());
131         AllocateResourceOutputBuilder allocateResourceOutputBuilder = new AllocateResourceOutputBuilder();
132         RpcResultBuilder<AllocateResourceOutput> allocateResourceOutputRpcBuilder = null;
133         try {
134             if (output.get().isSuccessful()) {
135                 AllocateIdRangeOutput allocateIdRangeOutput = output.get().getResult();
136                 List<Long> idValues = allocateIdRangeOutput.getIdValues();
137                 allocateResourceOutputBuilder.setIdValues(idValues);
138                 allocateResourceOutputRpcBuilder = RpcResultBuilder.success();
139                 allocateResourceOutputRpcBuilder.withResult(allocateResourceOutputBuilder.build());
140             }
141         } catch (InterruptedException | ExecutionException e) {
142             LOG.error("Allocate Resource failed for resource {} due to ", input.getResourceType(), e);
143             allocateResourceOutputRpcBuilder = RpcResultBuilder.failed();
144             allocateResourceOutputRpcBuilder.withError(RpcError.ErrorType.APPLICATION, e.getMessage());
145         }
146
147         if (allocateResourceOutputRpcBuilder == null) {
148             allocateResourceOutputRpcBuilder = RpcResultBuilder.failed();
149             allocateResourceOutputRpcBuilder.withError(RpcError.ErrorType.APPLICATION, "Resource cannot be  allocated");
150         }
151         return Futures.immediateFuture(allocateResourceOutputRpcBuilder.build());
152     }
153
154     @Override
155     public Future<RpcResult<GetResourcePoolOutput>> getResourcePool(GetResourcePoolInput input) {
156         Objects.requireNonNull(input.getResourceType(), RESOURCE_TYPE_CANNOT_BE_NULL);
157         Objects.requireNonNull(resourcesCache.get(input.getResourceType()), RESOURCE_TYPE_CANNOT_BE_NULL);
158
159         long currentTimeSec = System.currentTimeMillis() / 1000;
160         List<AvailableIds> availableIdsList = new ArrayList<>();
161         List<DelayedResourceEntries> delayedIdEntriesList = new ArrayList<>();
162         InstanceIdentifier<IdPool> parentId = ResourceManagerUtils
163                 .getIdPoolInstance(resourcesCache.get(input.getResourceType()));
164         Optional<IdPool> optionalParentIdPool = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, parentId,
165                 dataBroker);
166         if (optionalParentIdPool != null && optionalParentIdPool.isPresent()) {
167             IdPool parentIdPool = optionalParentIdPool.get();
168             AvailableIdsHolder availableParentIdsHolder = parentIdPool.getAvailableIdsHolder();
169             if (availableParentIdsHolder.getStart() < availableParentIdsHolder.getEnd()) {
170                 availableIdsList.add(new AvailableIdsBuilder().setStart(availableParentIdsHolder.getStart())
171                         .setEnd(availableParentIdsHolder.getEnd()).build());
172             }
173             ReleasedIdsHolder releasedParentIdsHolder = parentIdPool.getReleasedIdsHolder();
174             if (releasedParentIdsHolder != null) {
175                 List<DelayedIdEntries> delayedIdParentList = releasedParentIdsHolder.getDelayedIdEntries();
176                 if (delayedIdParentList != null && !delayedIdParentList.isEmpty()) {
177                     for (DelayedIdEntries delayedParentEntry : delayedIdParentList) {
178                         delayedIdEntriesList.add(new DelayedResourceEntriesBuilder().setId(delayedParentEntry.getId())
179                                 .setReadyTimeSec(delayedParentEntry.getReadyTimeSec()).build());
180                     }
181                 }
182             }
183         }
184
185         String localPool = ResourceManagerUtils.getLocalPoolName(resourcesCache.get(input.getResourceType()));
186         InstanceIdentifier<IdPool> localId = ResourceManagerUtils.getIdPoolInstance(localPool);
187         Optional<IdPool> optionalLocalId = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, localId, dataBroker);
188         if (optionalLocalId != null && optionalLocalId.isPresent()) {
189             IdPool localIdPool = optionalLocalId.get();
190             AvailableIdsHolder availableLocalIdsHolder = localIdPool.getAvailableIdsHolder();
191             if (availableLocalIdsHolder != null
192                     && availableLocalIdsHolder.getStart() < availableLocalIdsHolder.getEnd()) {
193                 availableIdsList.add(new AvailableIdsBuilder().setStart(availableLocalIdsHolder.getStart())
194                         .setEnd(availableLocalIdsHolder.getEnd()).build());
195             }
196             ReleasedIdsHolder releasedLocalIdsHolder = localIdPool.getReleasedIdsHolder();
197             if (releasedLocalIdsHolder != null) {
198                 List<DelayedIdEntries> delayedIdLocalList = releasedLocalIdsHolder.getDelayedIdEntries();
199                 if (delayedIdLocalList != null && !delayedIdLocalList.isEmpty()) {
200                     for (DelayedIdEntries delayedLocalEntry : delayedIdLocalList) {
201                         if (delayedLocalEntry.getReadyTimeSec() > currentTimeSec) {
202                             break;
203                         }
204                         delayedIdEntriesList.add(new DelayedResourceEntriesBuilder().setId(delayedLocalEntry.getId())
205                                 .setReadyTimeSec(delayedLocalEntry.getReadyTimeSec()).build());
206                     }
207                 }
208             }
209         }
210         GetResourcePoolOutput output = new GetResourcePoolOutputBuilder().setAvailableIds(availableIdsList)
211                 .setDelayedResourceEntries(delayedIdEntriesList).build();
212         return RpcResultBuilder.success(output).buildFuture();
213     }
214
215     @Override
216     public Future<RpcResult<GetAvailableResourcesOutput>> getAvailableResources(GetAvailableResourcesInput input) {
217         Objects.requireNonNull(input.getResourceType(), RESOURCE_TYPE_CANNOT_BE_NULL);
218         Objects.requireNonNull(resourcesCache.get(input.getResourceType()), RESOURCE_TYPE_NOT_FOUND);
219
220         long totalIdsAvailableForAllocation = 0;
221         long currentTimeSec = System.currentTimeMillis() / 1000;
222         InstanceIdentifier<IdPool> parentId = ResourceManagerUtils
223                 .getIdPoolInstance(resourcesCache.get(input.getResourceType()));
224         Optional<IdPool> optionalParentIdPool = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, parentId,
225                 dataBroker);
226         if (optionalParentIdPool != null && optionalParentIdPool.isPresent()) {
227             IdPool parentIdPool = optionalParentIdPool.get();
228             AvailableIdsHolder availableParentIdsHolder = parentIdPool.getAvailableIdsHolder();
229             totalIdsAvailableForAllocation = availableParentIdsHolder.getEnd() - availableParentIdsHolder.getCursor();
230             ReleasedIdsHolder releasedParentIdsHolder = parentIdPool.getReleasedIdsHolder();
231             if (releasedParentIdsHolder != null) {
232                 List<DelayedIdEntries> delayedIdParentList = releasedParentIdsHolder.getDelayedIdEntries();
233                 if (delayedIdParentList != null && !delayedIdParentList.isEmpty()) {
234                     totalIdsAvailableForAllocation += delayedIdParentList.size();
235                 }
236             }
237         }
238
239         String localPool = ResourceManagerUtils.getLocalPoolName(resourcesCache.get(input.getResourceType()));
240         InstanceIdentifier<IdPool> localId = ResourceManagerUtils.getIdPoolInstance(localPool);
241         Optional<IdPool> optionalLocalId = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, localId, dataBroker);
242         if (optionalLocalId != null && optionalLocalId.isPresent()) {
243             IdPool localIdPool = optionalLocalId.get();
244             AvailableIdsHolder availableLocalIdsHolder = localIdPool.getAvailableIdsHolder();
245             if (availableLocalIdsHolder != null) {
246                 totalIdsAvailableForAllocation += availableLocalIdsHolder.getEnd()
247                         - availableLocalIdsHolder.getCursor();
248             }
249             ReleasedIdsHolder releasedLocalIdsHolder = localIdPool.getReleasedIdsHolder();
250             if (releasedLocalIdsHolder != null) {
251                 long count = 0;
252                 List<DelayedIdEntries> delayedIdLocalList = releasedLocalIdsHolder.getDelayedIdEntries();
253                 if (delayedIdLocalList != null && !delayedIdLocalList.isEmpty()) {
254                     for (DelayedIdEntries delayedLocalEntry : delayedIdLocalList) {
255                         if (delayedLocalEntry.getReadyTimeSec() > currentTimeSec) {
256                             break;
257                         }
258                     }
259                     count++;
260                 }
261                 totalIdsAvailableForAllocation += count;
262             }
263         }
264
265         GetAvailableResourcesOutputBuilder outputBuilder = new GetAvailableResourcesOutputBuilder()
266                 .setTotalAvailableIdCount(totalIdsAvailableForAllocation);
267         RpcResultBuilder<GetAvailableResourcesOutput> rpcOutputBuilder = null;
268         rpcOutputBuilder = RpcResultBuilder.success();
269         rpcOutputBuilder.withResult(outputBuilder.build());
270
271         return Futures.immediateFuture(rpcOutputBuilder.build());
272     }
273
274     @Override
275     public Future<RpcResult<Void>> releaseResource(ReleaseResourceInput input) {
276         Objects.requireNonNull(input.getIdKey(), RESOURCE_ID_CANNOT_BE_NULL);
277         Objects.requireNonNull(input.getResourceType(), RESOURCE_TYPE_CANNOT_BE_NULL);
278
279         Objects.requireNonNull(resourcesCache.get(input.getResourceType()), RESOURCE_TYPE_NOT_FOUND);
280
281         ReleaseIdInputBuilder releaseIdInputBuilder = new ReleaseIdInputBuilder();
282         releaseIdInputBuilder.setIdKey(input.getIdKey()).setPoolName(resourcesCache.get(input.getResourceType()));
283
284         return idManager.releaseId(releaseIdInputBuilder.build());
285     }
286
287     private void createIdPool(String poolNameProperty, String lowIdProperty, String highIdProperty,
288             String poolDefaultName) {
289         JdkFutures.addErrorLogging(idManager.createIdPool(
290                 new CreateIdPoolInputBuilder().setPoolName(System.getProperty(poolNameProperty, poolDefaultName))
291                         .setLow(Long.valueOf(System.getProperty(lowIdProperty, DEFAULT_LOW_RANGE)))
292                         .setHigh(Long.valueOf(System.getProperty(highIdProperty, DEFAULT_HIGH_RANGE))).build()),
293                 LOG, "createIdPool");
294     }
295
296     private void createIdpools() {
297         // Create Tables Id Pool
298         createIdPool(RESOURCE_TABLES_NAME_PROPERTY, RESOURCE_TABLES_START_ID_PROPERTY, RESOURCE_TABLES_END_ID_PROPERTY,
299                 RESOURCE_TABLES_DEFAULT_NAME);
300
301         // Create Groups Id Pool
302         createIdPool(RESOURCE_GROUPS_NAME_PROPERTY, RESOURCE_GROUPS_START_ID_PROPERTY, RESOURCE_GROUPS_END_ID_PROPERTY,
303                 RESOURCE_GROUPS_DEFAULT_NAME);
304
305         // Create Meters Id Pool
306         createIdPool(RESOURCE_METERS_NAME_PROPERTY, RESOURCE_METERS_START_ID_PROPERTY, RESOURCE_METERS_END_ID_PROPERTY,
307                 RESOURCE_METERS_DEFAULT_NAME);
308     }
309
310     @Override
311     @PreDestroy
312     public void close() {
313         LOG.debug("{} close", getClass().getSimpleName());
314     }
315 }