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