25628b6041de94cc099eef49314756b77171324d
[controller.git] / opendaylight / config / config-persister-directory-adapter / src / main / java / org / opendaylight / controller / config / persist / storage / directory / DirectoryPersister.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. 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 package org.opendaylight.controller.config.persist.storage.directory;
9
10 import com.google.common.base.Charsets;
11 import com.google.common.base.Optional;
12 import com.google.common.io.Files;
13 import org.apache.commons.io.IOUtils;
14 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
15 import org.opendaylight.controller.config.persist.api.Persister;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.charset.Charset;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.SortedSet;
27 import java.util.TreeSet;
28
29 import static com.google.common.base.Preconditions.checkArgument;
30 import static com.google.common.base.Preconditions.checkState;
31
32 public class DirectoryPersister implements Persister {
33     private static final Logger logger = LoggerFactory.getLogger(DirectoryPersister.class);
34     private static final Charset ENCODING = Charsets.UTF_8;
35
36     static final String MODULES_START = "//MODULES START";
37     static final String SERVICES_START = "//SERVICES START";
38     static final String CAPABILITIES_START = "//CAPABILITIES START";
39
40
41     private final File storage;
42     private final String header, middle, footer;
43
44     public DirectoryPersister(File storage) {
45         checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
46         this.storage = storage;
47         header = readResource("header.txt");
48         middle = readResource("middle.txt");
49         footer = readResource("footer.txt");
50
51     }
52
53     private static String readResource(String resource) {
54         try {
55             return IOUtils.toString(DirectoryPersister.class.getResourceAsStream("/" + resource));
56         } catch (IOException e) {
57             throw new IllegalStateException("Cannot load " + resource, e);
58         }
59     }
60
61     @Override
62     public void persistConfig(ConfigSnapshotHolder holder) throws IOException {
63         throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
64     }
65
66     @Override
67     public Optional<ConfigSnapshotHolder> loadLastConfig() throws IOException {
68         File[] filesArray = storage.listFiles();
69         if (filesArray.length == 0) {
70             return Optional.absent();
71         }
72         List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
73         Collections.sort(sortedFiles);
74         // combine all found files
75
76         SortedSet<String> combinedCapabilities = new TreeSet<>();
77         StringBuilder modulesBuilder = new StringBuilder(), servicesBuilder = new StringBuilder();
78         for (File file : sortedFiles) {
79             logger.trace("Adding file '{}' to combined result", file);
80
81             final MyLineProcessor lineProcessor = new MyLineProcessor(file.getAbsolutePath());
82             Files.readLines(file, ENCODING, lineProcessor);
83
84             modulesBuilder.append(lineProcessor.getModules());
85             servicesBuilder.append(lineProcessor.getServices());
86             combinedCapabilities.addAll(lineProcessor.getCapabilities());
87         }
88         String combinedSnapshot = header + modulesBuilder.toString() + middle + servicesBuilder.toString() + footer;
89         ConfigSnapshotHolder result = new ConfigSnapshotHolderImpl(combinedSnapshot, combinedCapabilities);
90         return Optional.of(result);
91     }
92
93
94     @Override
95     public void close() {
96
97     }
98
99     @Override
100     public String toString() {
101         return "FileStorageAdapter [storage=" + storage + "]";
102     }
103 }
104
105 class MyLineProcessor implements com.google.common.io.LineProcessor<String> {
106     private final String fileNameForReporting;
107
108     private boolean inModules, inServices, inCapabilities;
109     private final StringBuffer modulesBuffer = new StringBuffer(), servicesBuilder = new StringBuffer();
110     private final SortedSet<String> caps = new TreeSet<>();
111
112     MyLineProcessor(String fileNameForReporting) {
113         this.fileNameForReporting = fileNameForReporting;
114     }
115
116     @Override
117     public String getResult() {
118         return null;
119     }
120
121     @Override
122     public boolean processLine(String line) throws IOException {
123
124         String lineWithNewLine = line + System.lineSeparator();
125         if (line.equals(DirectoryPersister.MODULES_START)) {
126             checkState(inModules == false && inServices == false && inCapabilities == false);
127             inModules = true;
128         } else if (line.equals(DirectoryPersister.SERVICES_START)) {
129             checkState(inModules == true && inServices == false && inCapabilities == false);
130             inModules = false;
131             inServices = true;
132         } else if (line.equals(DirectoryPersister.CAPABILITIES_START)) {
133             checkState(inModules == false && inServices == true && inCapabilities == false);
134             inServices = false;
135             inCapabilities = true;
136         } else if (inModules) {
137             modulesBuffer.append(lineWithNewLine);
138         } else if (inServices) {
139             servicesBuilder.append(lineWithNewLine);
140         } else {
141             caps.add(line);
142         }
143         return true;
144     }
145
146     private void checkFileConsistency(){
147         checkState(inCapabilities, "File {} is missing delimiters in this order: {}", fileNameForReporting,
148                 Arrays.asList(DirectoryPersister.MODULES_START,
149                         DirectoryPersister.SERVICES_START,
150                         DirectoryPersister.CAPABILITIES_START));
151     }
152
153     String getModules() {
154         checkFileConsistency();
155         return modulesBuffer.toString();
156     }
157
158     String getServices() {
159         checkFileConsistency();
160         return servicesBuilder.toString();
161     }
162
163     SortedSet<String> getCapabilities() {
164         checkFileConsistency();
165         return caps;
166     }
167
168 }
169
170 class ConfigSnapshotHolderImpl implements ConfigSnapshotHolder {
171
172     private final String snapshot;
173     private final SortedSet<String> caps;
174
175     public ConfigSnapshotHolderImpl(String configSnapshot, SortedSet<String> capabilities) {
176         this.snapshot = configSnapshot;
177         this.caps = capabilities;
178     }
179
180     @Override
181     public String getConfigSnapshot() {
182         return snapshot;
183     }
184
185     @Override
186     public SortedSet<String> getCapabilities() {
187         return caps;
188     }
189 }