Fix for possible NPE if Bundle is stopped.
[controller.git] / opendaylight / configuration / implementation / src / main / java / org / opendaylight / controller / configuration / internal / ContainerConfigurationService.java
1
2 /*
3  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 package org.opendaylight.controller.configuration.internal;
11
12 import java.io.File;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.Dictionary;
16 import java.util.EnumSet;
17 import java.util.HashSet;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.concurrent.ConcurrentMap;
21
22 import org.apache.felix.dm.Component;
23 import org.opendaylight.controller.clustering.services.CacheConfigException;
24 import org.opendaylight.controller.clustering.services.CacheExistException;
25 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
26 import org.opendaylight.controller.clustering.services.IClusterContainerServices;
27 import org.opendaylight.controller.clustering.services.IClusterServices;
28 import org.opendaylight.controller.configuration.ConfigurationEvent;
29 import org.opendaylight.controller.configuration.ConfigurationObject;
30 import org.opendaylight.controller.configuration.IConfigurationAware;
31 import org.opendaylight.controller.configuration.IConfigurationContainerAware;
32 import org.opendaylight.controller.configuration.IConfigurationContainerService;
33 import org.opendaylight.controller.sal.utils.GlobalConstants;
34 import org.opendaylight.controller.sal.utils.IObjectReader;
35 import org.opendaylight.controller.sal.utils.ObjectReader;
36 import org.opendaylight.controller.sal.utils.ObjectWriter;
37 import org.opendaylight.controller.sal.utils.Status;
38 import org.opendaylight.controller.sal.utils.StatusCode;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * @file   ConfigurationImpl.java
44  *
45  * @brief  Backend functionality for all ConfigurationService related tasks.
46  *
47  */
48
49 public class ContainerConfigurationService implements IConfigurationContainerService,
50         IConfigurationAware, ICacheUpdateAware<ConfigurationEvent, String> {
51     public static final String CONTAINER_SAVE_EVENT_CACHE = "config.container.event.save";
52     private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class);
53     private IClusterContainerServices clusterServices;
54     private ConcurrentMap <ConfigurationEvent, String> containerConfigEvent;
55     // Directory which contains the startup files for this container
56     private String root;
57     private Set<IConfigurationContainerAware> configurationAwareList = Collections
58             .synchronizedSet(new HashSet<IConfigurationContainerAware>());
59     private ObjectReader objReader;
60     private ObjectWriter objWriter;
61     private String containerName;
62
63     public void addConfigurationContainerAware(
64             IConfigurationContainerAware configurationAware) {
65         if (!this.configurationAwareList.contains(configurationAware)) {
66             this.configurationAwareList.add(configurationAware);
67         }
68     }
69
70     public int getConfigurationAwareListSize() {
71         return this.configurationAwareList.size();
72     }
73
74     public void removeConfigurationContainerAware(
75             IConfigurationContainerAware configurationAware) {
76         this.configurationAwareList.remove(configurationAware);
77     }
78
79     public void setClusterServices(IClusterContainerServices i) {
80         this.clusterServices = i;
81         logger.debug("IClusterServices set");
82     }
83
84     public void unsetClusterServices(IClusterContainerServices i) {
85         if (this.clusterServices == i) {
86             this.clusterServices = null;
87             logger.debug("IClusterServices Unset");
88         }
89     }
90
91     void init(Component c) {
92         Dictionary<?, ?> props = c.getServiceProperties();
93         containerName = (props != null) ? (String) props.get("containerName") :
94             GlobalConstants.DEFAULT.toString();
95         root =  String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
96     }
97
98     public void start() {
99         allocateCache();
100         retrieveCache();
101         objReader = new ObjectReader();
102         objWriter = new ObjectWriter();
103     }
104
105     public void destroy() {
106         // Clear local states
107         this.configurationAwareList.clear();
108     }
109
110     /**
111      * Function called by the dependency manager before Container is Stopped and Destroyed.
112      */
113     public void containerStop() {
114         // Do nothing
115     }
116
117     @Override
118     public String getConfigurationRoot() {
119         return root;
120     }
121
122     @Override
123     public Status saveConfiguration() {
124         boolean success = true;
125
126         for (IConfigurationContainerAware configurationAware : configurationAwareList) {
127             logger.trace("Save Config triggered for {}", configurationAware.getClass().getSimpleName());
128
129             Status status = configurationAware.saveConfiguration();
130             if (!status.isSuccess()) {
131                 success = false;
132                 logger.warn("Failed to save config for {} ({})", configurationAware.getClass().getSimpleName(),
133                         status.getDescription());
134             }
135         }
136         if (success) {
137             return new Status(StatusCode.SUCCESS);
138         } else {
139             return new Status(StatusCode.INTERNALERROR, "Failed to save one or more configurations");
140         }
141     }
142
143     @Override
144     public Status saveConfigurations() {
145         containerConfigEvent.put(ConfigurationEvent.SAVE, "");
146         return saveConfiguration();
147     }
148
149     @Override
150     public void entryCreated(ConfigurationEvent key, String cacheName,
151             boolean originLocal) {
152         if (originLocal) {
153             return;
154         }
155     }
156
157     @Override
158     public void entryUpdated(ConfigurationEvent key, String new_value,
159             String cacheName, boolean originLocal) {
160         if (originLocal) {
161             return;
162         }
163         logger.debug("Processing {} event", key);
164         if (key == ConfigurationEvent.SAVE) {
165             saveConfiguration();
166         }
167     }
168
169     @Override
170     public void entryDeleted(ConfigurationEvent key, String cacheName,
171             boolean originLocal) {
172         if (originLocal) {
173             return;
174         }
175     }
176
177     private void allocateCache() {
178         if (this.clusterServices == null) {
179             logger.error("uninitialized clusterServices, can't create cache");
180             return;
181         }
182         try {
183             this.clusterServices.createCache(CONTAINER_SAVE_EVENT_CACHE,
184                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
185         } catch (CacheConfigException cce) {
186             logger.debug("Error creating ContainerConfigurationService cache ", cce);
187         } catch (CacheExistException cce) {
188             logger.debug("ConfigurationService Cache already exists, destroy and recreate ", cce);
189         }
190     }
191
192     @SuppressWarnings({ "unchecked" })
193     private void retrieveCache() {
194         if (this.clusterServices == null) {
195             logger.error("uninitialized clusterServices, can't retrieve cache");
196             return;
197         }
198         containerConfigEvent = (ConcurrentMap<ConfigurationEvent, String>) this.clusterServices.getCache(CONTAINER_SAVE_EVENT_CACHE);
199         if (containerConfigEvent == null) {
200             logger.error("Failed to retrieve configuration Cache");
201         }
202     }
203
204     @Override
205     public Status persistConfiguration(List<ConfigurationObject> config, String fileName) {
206         if (!hasBeenSaved()) {
207             return new Status(StatusCode.NOTALLOWED,
208                     String.format("Container %s has not been saved yet", containerName));
209         }
210         String destination = String.format("%s%s", root, fileName);
211         return objWriter.write(config, destination);
212     }
213
214     @Override
215     public List<ConfigurationObject> retrieveConfiguration(IObjectReader reader, String fileName) {
216         if (!clusterServices.amICoordinator()) {
217             return Collections.emptyList();
218         }
219         String source = String.format("%s%s", root, fileName);
220         Object obj = objReader.read(reader, source);
221         if (obj == null) {
222             return Collections.<ConfigurationObject> emptyList();
223         }
224         if (obj instanceof ConcurrentMap) {
225             return new ArrayList<ConfigurationObject>(((ConcurrentMap)obj).values());
226         }
227         return (List<ConfigurationObject>) obj;
228     }
229
230     @Override
231     public boolean hasBeenSaved() {
232         try {
233             File configRoot = new File(this.getConfigurationRoot());
234             return configRoot.exists();
235         } catch (Exception e) {
236             return false;
237         }
238
239     }
240 }