Merge "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,
51         ICacheUpdateAware<String, String> {
52     public static final String CONTAINER_SAVE_EVENT_CACHE = "config.container.event.save";
53     private static final Logger logger = LoggerFactory.getLogger(ContainerConfigurationService.class);
54     private IClusterContainerServices clusterServices;
55     private ConcurrentMap<String, String> containerConfigEvent;
56     // Directory which contains the startup files for this container
57     private String root;
58     private Set<IConfigurationContainerAware> configurationAwareList = Collections
59             .synchronizedSet(new HashSet<IConfigurationContainerAware>());
60     private ObjectReader objReader;
61     private ObjectWriter objWriter;
62     private String containerName;
63
64     public void addConfigurationContainerAware(
65             IConfigurationContainerAware configurationAware) {
66         if (!this.configurationAwareList.contains(configurationAware)) {
67             this.configurationAwareList.add(configurationAware);
68         }
69     }
70
71     public int getConfigurationAwareListSize() {
72         return this.configurationAwareList.size();
73     }
74
75     public void removeConfigurationContainerAware(
76             IConfigurationContainerAware configurationAware) {
77         this.configurationAwareList.remove(configurationAware);
78     }
79
80     public void setClusterServices(IClusterContainerServices i) {
81         this.clusterServices = i;
82         logger.debug("IClusterServices set");
83     }
84
85     public void unsetClusterServices(IClusterContainerServices i) {
86         if (this.clusterServices == i) {
87             this.clusterServices = null;
88             logger.debug("IClusterServices Unset");
89         }
90     }
91
92     void init(Component c) {
93         Dictionary<?, ?> props = c.getServiceProperties();
94         containerName = (props != null) ? (String) props.get("containerName") :
95             GlobalConstants.DEFAULT.toString();
96         root =  String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
97     }
98
99     public void start() {
100         allocateCache();
101         retrieveCache();
102         objReader = new ObjectReader();
103         objWriter = new ObjectWriter();
104     }
105
106     public void destroy() {
107         // Clear local states
108         this.configurationAwareList.clear();
109     }
110
111     /**
112      * Function called by the dependency manager before Container is Stopped and Destroyed.
113      */
114     public void containerStop() {
115         // Do nothing
116     }
117
118     @Override
119     public String getConfigurationRoot() {
120         return root;
121     }
122
123     @Override
124     public Status saveConfiguration() {
125         boolean success = true;
126
127         for (IConfigurationContainerAware configurationAware : configurationAwareList) {
128             logger.trace("Save Config triggered for {}", configurationAware.getClass().getSimpleName());
129
130             Status status = configurationAware.saveConfiguration();
131             if (!status.isSuccess()) {
132                 success = false;
133                 logger.warn("Failed to save config for {} ({})", configurationAware.getClass().getSimpleName(),
134                         status.getDescription());
135             }
136         }
137         if (success) {
138             return new Status(StatusCode.SUCCESS);
139         } else {
140             return new Status(StatusCode.INTERNALERROR, "Failed to save one or more configurations");
141         }
142     }
143
144     @Override
145     public Status saveConfigurations() {
146         containerConfigEvent.put(ConfigurationEvent.SAVE.toString(), "");
147         return saveConfiguration();
148     }
149
150     @Override
151     public void entryCreated(String key, String cacheName,
152             boolean originLocal) {
153         if (originLocal) {
154             return;
155         }
156     }
157
158     @Override
159     public void entryUpdated(String key, String new_value,
160             String cacheName, boolean originLocal) {
161         if (originLocal) {
162             return;
163         }
164         logger.debug("Processing {} event", key);
165         if (key.equals(ConfigurationEvent.SAVE.toString())) {
166             saveConfiguration();
167         }
168     }
169
170     @Override
171     public void entryDeleted(String key, String cacheName,
172             boolean originLocal) {
173         if (originLocal) {
174             return;
175         }
176     }
177
178     private void allocateCache() {
179         if (this.clusterServices == null) {
180             logger.error("uninitialized clusterServices, can't create cache");
181             return;
182         }
183         try {
184             this.clusterServices.createCache(CONTAINER_SAVE_EVENT_CACHE,
185                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
186         } catch (CacheConfigException cce) {
187             logger.debug("Error creating ContainerConfigurationService cache ", cce);
188         } catch (CacheExistException cce) {
189             logger.debug("ConfigurationService Cache already exists, destroy and recreate ", cce);
190         }
191     }
192
193     @SuppressWarnings({ "unchecked" })
194     private void retrieveCache() {
195         if (this.clusterServices == null) {
196             logger.error("uninitialized clusterServices, can't retrieve cache");
197             return;
198         }
199         containerConfigEvent =
200                 (ConcurrentMap<String, String>) this.clusterServices.getCache(CONTAINER_SAVE_EVENT_CACHE);
201         if (containerConfigEvent == null) {
202             logger.error("Failed to retrieve configuration Cache");
203         }
204     }
205
206     @Override
207     public Status persistConfiguration(List<ConfigurationObject> config, String fileName) {
208         if (!hasBeenSaved()) {
209             return new Status(StatusCode.NOTALLOWED,
210                     String.format("Container %s has not been saved yet", containerName));
211         }
212         String destination = String.format("%s%s", root, fileName);
213         return objWriter.write(config, destination);
214     }
215
216     @Override
217     public List<ConfigurationObject> retrieveConfiguration(IObjectReader reader, String fileName) {
218         if (!clusterServices.amICoordinator()) {
219             return Collections.emptyList();
220         }
221         String source = String.format("%s%s", root, fileName);
222         Object obj = objReader.read(reader, source);
223         if (obj == null) {
224             return Collections.<ConfigurationObject> emptyList();
225         }
226         if (obj instanceof ConcurrentMap) {
227             return new ArrayList<ConfigurationObject>(((ConcurrentMap)obj).values());
228         }
229         return (List<ConfigurationObject>) obj;
230     }
231
232     @Override
233     public boolean hasBeenSaved() {
234         try {
235             File configRoot = new File(this.getConfigurationRoot());
236             return configRoot.exists();
237         } catch (Exception e) {
238             return false;
239         }
240
241     }
242 }