Merge "Backward compatibility change for Configuration Service"
[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     /*
56      * Collection containing the configuration objects.
57      * This is configuration world: container names (also the map key)
58      * are maintained as they were configured by user, same case
59      */
60     private Set<IConfigurationContainerAware> configurationAwareList = Collections
61             .synchronizedSet(new HashSet<IConfigurationContainerAware>());
62     private String root;
63     private ObjectReader objReader;
64     private ObjectWriter objWriter;
65
66     public void addConfigurationContainerAware(
67             IConfigurationContainerAware configurationAware) {
68         if (!this.configurationAwareList.contains(configurationAware)) {
69             this.configurationAwareList.add(configurationAware);
70         }
71     }
72
73     public int getConfigurationAwareListSize() {
74         return this.configurationAwareList.size();
75     }
76
77     public void removeConfigurationContainerAware(
78             IConfigurationContainerAware configurationAware) {
79         this.configurationAwareList.remove(configurationAware);
80     }
81
82     public void setClusterServices(IClusterContainerServices i) {
83         this.clusterServices = i;
84         logger.debug("IClusterServices set");
85     }
86
87     public void unsetClusterServices(IClusterContainerServices i) {
88         if (this.clusterServices == i) {
89             this.clusterServices = null;
90             logger.debug("IClusterServices Unset");
91         }
92     }
93
94     void init(Component c) {
95         Dictionary<?, ?> props = c.getServiceProperties();
96         String containerName = (props != null) ? (String) props.get("containerName") : GlobalConstants.DEFAULT.toString();
97         root = String.format("%s%s/", GlobalConstants.STARTUPHOME.toString(), containerName);
98         if (!new File(root).exists()) {
99             boolean created = new File(root).mkdir();
100             if (!created) {
101                 logger.error("Failed to create startup config directory for container {}", containerName);
102             }
103         }
104     }
105
106     public void start() {
107         allocateCache();
108         retrieveCache();
109         objReader = new ObjectReader();
110         objWriter = new ObjectWriter();
111     }
112
113     public void destroy() {
114         // Clear local states
115         this.configurationAwareList.clear();
116     }
117
118     /**
119      * Function called by the dependency manager before Container is Stopped and Destroyed.
120      */
121     public void containerStop() {
122         // Remove container directory along with its startup files
123         File[] files = new File(root).listFiles();
124         for (File file : files) {
125             file.delete();
126         }
127         new File(root).delete();
128     }
129
130     @Override
131     public Status saveConfiguration() {
132         boolean success = true;
133         for (IConfigurationContainerAware configurationAware : configurationAwareList) {
134             logger.trace("Save Config triggered for {}", configurationAware.getClass().getSimpleName());
135
136             Status status = configurationAware.saveConfiguration();
137             if (!status.isSuccess()) {
138                 success = false;
139                 logger.warn("Failed to save config for {}", configurationAware.getClass().getSimpleName());
140             }
141         }
142         if (success) {
143             return new Status(StatusCode.SUCCESS);
144         } else {
145             return new Status(StatusCode.INTERNALERROR, "Failed to Save All Configurations");
146         }
147     }
148
149     @Override
150     public Status saveConfigurations() {
151         containerConfigEvent.put(ConfigurationEvent.SAVE, "");
152         return saveConfiguration();
153     }
154
155     @Override
156     public void entryCreated(ConfigurationEvent key, String cacheName,
157             boolean originLocal) {
158         if (originLocal) {
159             return;
160         }
161     }
162
163     @Override
164     public void entryUpdated(ConfigurationEvent key, String new_value,
165             String cacheName, boolean originLocal) {
166         if (originLocal) {
167             return;
168         }
169         logger.debug("Processing {} event", key);
170         if (key == ConfigurationEvent.SAVE) {
171             saveConfiguration();
172         }
173     }
174
175     @Override
176     public void entryDeleted(ConfigurationEvent key, String cacheName,
177             boolean originLocal) {
178         if (originLocal) {
179             return;
180         }
181     }
182
183     private void allocateCache() {
184         if (this.clusterServices == null) {
185             logger.error("uninitialized clusterServices, can't create cache");
186             return;
187         }
188         try {
189             this.clusterServices.createCache(CONTAINER_SAVE_EVENT_CACHE,
190                     EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
191         } catch (CacheConfigException cce) {
192             logger.debug("Error creating ContainerConfigurationService cache ", cce);
193         } catch (CacheExistException cce) {
194             logger.debug("ConfigurationService Cache already exists, destroy and recreate ", cce);
195         }
196     }
197
198     @SuppressWarnings({ "unchecked" })
199     private void retrieveCache() {
200         if (this.clusterServices == null) {
201             logger.error("uninitialized clusterServices, can't retrieve cache");
202             return;
203         }
204         containerConfigEvent = (ConcurrentMap<ConfigurationEvent, String>) this.clusterServices.getCache(CONTAINER_SAVE_EVENT_CACHE);
205         if (containerConfigEvent == null) {
206             logger.error("Failed to retrieve configuration Cache");
207         }
208     }
209
210     @Override
211     public Status persistConfiguration(List<ConfigurationObject> config, String fileName) {
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 }