3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
10 package org.opendaylight.controller.configuration.internal;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.EnumSet;
16 import java.util.HashSet;
17 import java.util.List;
19 import java.util.concurrent.ConcurrentMap;
21 import org.opendaylight.controller.clustering.services.CacheConfigException;
22 import org.opendaylight.controller.clustering.services.CacheExistException;
23 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
24 import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
25 import org.opendaylight.controller.clustering.services.IClusterServices;
26 import org.opendaylight.controller.configuration.ConfigurationEvent;
27 import org.opendaylight.controller.configuration.ConfigurationObject;
28 import org.opendaylight.controller.configuration.IConfigurationAware;
29 import org.opendaylight.controller.configuration.IConfigurationContainerService;
30 import org.opendaylight.controller.configuration.IConfigurationService;
31 import org.opendaylight.controller.sal.utils.GlobalConstants;
32 import org.opendaylight.controller.sal.utils.IObjectReader;
33 import org.opendaylight.controller.sal.utils.ObjectReader;
34 import org.opendaylight.controller.sal.utils.ObjectWriter;
35 import org.opendaylight.controller.sal.utils.Status;
36 import org.opendaylight.controller.sal.utils.StatusCode;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 * @file ConfigurationImpl.java
43 * @brief Backend functionality for all ConfigurationService related tasks.
47 public class ConfigurationService implements IConfigurationService, ICacheUpdateAware<String, String> {
48 private static final Logger logger = LoggerFactory
49 .getLogger(ConfigurationService.class);
50 public static final String SAVE_EVENT_CACHE = "config.event.save";
51 private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
52 private IClusterGlobalServices clusterServices;
53 private ConcurrentMap<String, String> configEvent;
54 private Set<IConfigurationAware> configurationAwareList = Collections
55 .synchronizedSet(new HashSet<IConfigurationAware>());
56 private ObjectReader objReader;
57 private ObjectWriter objWriter;
60 public int getConfigurationAwareListSize() {
61 return this.configurationAwareList.size();
64 public void addConfigurationAware(IConfigurationAware configurationAware) {
65 if (!this.configurationAwareList.contains(configurationAware)) {
66 this.configurationAwareList.add(configurationAware);
70 public void removeConfigurationAware(IConfigurationAware configurationAware) {
71 this.configurationAwareList.remove(configurationAware);
74 public void setClusterServices(IClusterGlobalServices i) {
75 this.clusterServices = i;
76 logger.debug("IClusterServices set");
79 public void unsetClusterServices(IClusterGlobalServices i) {
80 if (this.clusterServices == i) {
81 this.clusterServices = null;
82 logger.debug("IClusterServices Unset");
87 logger.info("ConfigurationService Manager init");
89 // Create the default startup directory, so that container unaware apps can initiate save
90 createContainerDirectory(ROOT + GlobalConstants.DEFAULT.toString());
96 objReader = new ObjectReader();
97 objWriter = new ObjectWriter();
100 public void destroy() {
101 // Clear local states
102 this.configurationAwareList.clear();
106 public Status saveConfigurations() {
107 if (configEvent != null) {
108 configEvent.put(ConfigurationEvent.SAVE.toString(), "");
110 return saveConfigurationsInternal();
114 private List<String> getContainerDirectoryList() {
115 List<String> containerList = new ArrayList<String>();
116 for (IConfigurationAware configurationAware : this.configurationAwareList) {
117 if (configurationAware instanceof IConfigurationContainerService) {
118 String containerFilePath = ((IConfigurationContainerService)configurationAware).getConfigurationRoot();
119 containerList.add(containerFilePath);
122 return containerList;
125 private void createContainerDirectory(IConfigurationAware configurationAware) {
126 String containerFilePath = ((IConfigurationContainerService) configurationAware).getConfigurationRoot();
127 createContainerDirectory(containerFilePath);
130 private void createContainerDirectory(String containerFilePath) {
133 if (!new File(containerFilePath).exists()) {
134 boolean created = new File(containerFilePath).mkdir();
136 logger.error("Failed to create config directory: {}", containerFilePath);
139 } catch (Exception e) {
140 logger.error("Failed to create config directory: {} ({})", containerFilePath, e.getMessage());
144 private void clearStaleContainerDirectories() {
145 List<String> activeContainers = getContainerDirectoryList();
146 for (File file : new File(ROOT).listFiles()) {
147 if (file.isDirectory() && !activeContainers.contains(file.toPath() + File.separator)) {
148 logger.trace("Removing directory for container {}", file.getName());
149 for (File innerFile : file.listFiles()) {
152 boolean removed = file.delete();
154 logger.warn("Failed to remove stale directory: {}", file.getName());
161 private Status saveConfigurationsInternal() {
162 boolean success = true;
163 for (IConfigurationAware configurationAware : configurationAwareList) {
164 if (configurationAware instanceof IConfigurationContainerService) {
165 // Create directory for new containers
166 createContainerDirectory(configurationAware);
168 Status status = configurationAware.saveConfiguration();
169 if (!status.isSuccess()) {
171 logger.warn("Failed to save config for {}", configurationAware.getClass().getName());
174 // Remove startup directories of containers that were removed from
175 // the configuration but not saved
176 clearStaleContainerDirectories();
179 return new Status(StatusCode.SUCCESS);
181 return new Status(StatusCode.INTERNALERROR, "Failed to Save All Configurations");
186 public void entryCreated(String key, String cacheName,
187 boolean originLocal) {
194 public void entryUpdated(String key, String new_value,
195 String cacheName, boolean originLocal) {
199 if (key.equals(ConfigurationEvent.SAVE.toString())) {
200 saveConfigurationsInternal();
205 public void entryDeleted(String key, String cacheName,
206 boolean originLocal) {
212 private void allocateCache() {
213 if (this.clusterServices == null) {
214 logger.error("uninitialized clusterServices, can't create cache");
218 this.clusterServices.createCache(SAVE_EVENT_CACHE,
219 EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
220 } catch (CacheConfigException cce) {
221 logger.debug("Error creating ConfigurationService cache ", cce);
222 } catch (CacheExistException cce) {
223 logger.debug("ConfigurationService Cache already exists, destroy and recreate ", cce);
227 @SuppressWarnings({ "unchecked" })
228 private void retrieveCache() {
229 if (this.clusterServices == null) {
230 logger.error("uninitialized clusterServices, can't retrieve cache");
233 configEvent = (ConcurrentMap<String, String>) this.clusterServices.getCache(SAVE_EVENT_CACHE);
234 if (configEvent == null) {
235 logger.error("Failed to retrieve configuration Cache");
240 public Status persistConfiguration(List<ConfigurationObject> config, String fileName) {
241 String destination = String.format("%s%s", ROOT, fileName);
242 return objWriter.write(config, destination);
246 public List<ConfigurationObject> retrieveConfiguration(IObjectReader reader, String fileName) {
247 if (!clusterServices.amICoordinator()) {
248 return Collections.emptyList();
250 String source = String.format("%s%s", ROOT, fileName);
251 Object obj = objReader.read(reader, source);
253 return Collections.<ConfigurationObject> emptyList();
255 if (obj instanceof ConcurrentMap) {
256 return new ArrayList<ConfigurationObject>(((ConcurrentMap)obj).values());
258 return (List<ConfigurationObject>) obj;