Merge "BUG 2317 : StatisticsManager does not unregister from yang notifications on...
[controller.git] / opendaylight / config / config-persister-directory-xml-adapter / src / main / java / org / opendaylight / controller / config / persist / storage / directory / xml / XmlDirectoryPersister.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.xml;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import com.google.common.base.Optional;
12 import com.google.common.io.Files;
13 import java.io.File;
14 import java.io.FilenameFilter;
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Set;
21 import java.util.SortedSet;
22 import javax.xml.bind.JAXBContext;
23 import javax.xml.bind.JAXBException;
24 import javax.xml.bind.Unmarshaller;
25 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
26 import org.opendaylight.controller.config.persist.api.Persister;
27 import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 public class XmlDirectoryPersister implements Persister {
32     private static final Logger LOG = LoggerFactory.getLogger(XmlDirectoryPersister.class);
33
34     private final File storage;
35     private final Optional<FilenameFilter> extensionsFilter;
36
37     /**
38      * Creates XmlDirectoryPersister that picks up all files in specified folder
39      */
40     public XmlDirectoryPersister(final File storage) {
41         this(storage, Optional.<FilenameFilter>absent());
42     }
43
44     /**
45      * Creates XmlDirectoryPersister that picks up files only with specified file extension
46      */
47     public XmlDirectoryPersister(final File storage, final Set<String> fileExtensions) {
48         this(storage, Optional.of(getFilter(fileExtensions)));
49     }
50
51     private XmlDirectoryPersister(final File storage, final Optional<FilenameFilter> extensionsFilter) {
52         checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
53         this.storage = storage;
54         this.extensionsFilter = extensionsFilter;
55     }
56
57     @Override
58     public void persistConfig(final ConfigSnapshotHolder holder) throws IOException {
59         throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
60     }
61
62     @Override
63     public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
64         File[] filesArray = extensionsFilter.isPresent() ? storage.listFiles(extensionsFilter.get()) : storage.listFiles();
65         if (filesArray == null || filesArray.length == 0) {
66             return Collections.emptyList();
67         }
68         List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
69         Collections.sort(sortedFiles);
70         // combine all found files
71         LOG.debug("Reading files in following order: {}", sortedFiles);
72
73         List<ConfigSnapshotHolder> result = new ArrayList<>();
74         for (File file : sortedFiles) {
75             LOG.trace("Adding file '{}' to combined result", file);
76             Optional<ConfigSnapshotHolder> h = fromXmlSnapshot(file);
77             // Ignore non valid snapshot
78             if(h.isPresent() == false) {
79                 continue;
80             }
81
82             result.add(h.get());
83         }
84         return result;
85     }
86
87     private Optional<ConfigSnapshotHolder> fromXmlSnapshot(final File file) {
88         try {
89             return Optional.of(loadLastConfig(file));
90         } catch (JAXBException e) {
91             // In case of parse error, issue a warning, ignore and continue
92             LOG.warn(
93                     "Unable to parse configuration snapshot from {}. Initial config from {} will be IGNORED in this run. " +
94                     "Note that subsequent config files may fail due to this problem. " +
95                     "Xml markup in this file needs to be fixed, for detailed information see enclosed exception.",
96                     file, file, e);
97         }
98
99         return Optional.absent();
100     }
101
102     public static ConfigSnapshotHolder loadLastConfig(final File file) throws JAXBException {
103         JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
104         Unmarshaller um = jaxbContext.createUnmarshaller();
105
106         return asHolder((ConfigSnapshot) um.unmarshal(file));
107     }
108
109     private static ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) {
110         return new ConfigSnapshotHolder() {
111             @Override
112             public String getConfigSnapshot() {
113                 return unmarshalled.getConfigSnapshot();
114             }
115
116             @Override
117             public SortedSet<String> getCapabilities() {
118                 return unmarshalled.getCapabilities();
119             }
120
121             @Override
122             public String toString() {
123                 return unmarshalled.toString();
124             }
125         };
126     }
127
128     private static FilenameFilter getFilter(final Set<String>fileExtensions) {
129         checkArgument(fileExtensions.isEmpty() == false, "No file extension provided", fileExtensions);
130
131         return new FilenameFilter() {
132             @Override
133             public boolean accept(final File dir, final String name) {
134                 String ext = Files.getFileExtension(name);
135                 return fileExtensions.contains(ext);
136             }
137         };
138     }
139
140     @Override
141     public void close() {
142
143     }
144
145     @Override
146     public String toString() {
147         final StringBuffer sb = new StringBuffer("XmlDirectoryPersister{");
148         sb.append("storage=").append(storage);
149         sb.append('}');
150         return sb.toString();
151     }
152 }