2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.config.persist.storage.directory.xml;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.base.Optional;
13 import com.google.common.io.Files;
15 import java.io.FilenameFilter;
16 import java.io.IOException;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.List;
22 import java.util.SortedSet;
23 import javax.xml.bind.JAXBContext;
24 import javax.xml.bind.JAXBException;
25 import javax.xml.bind.Unmarshaller;
26 import javax.xml.stream.XMLInputFactory;
27 import javax.xml.stream.XMLStreamException;
28 import javax.xml.stream.XMLStreamReader;
29 import javax.xml.transform.stream.StreamSource;
30 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
31 import org.opendaylight.controller.config.persist.api.Persister;
32 import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 public class XmlDirectoryPersister implements Persister {
37 private static final Logger LOG = LoggerFactory.getLogger(XmlDirectoryPersister.class);
39 private final File storage;
40 private final Optional<FilenameFilter> extensionsFilter;
43 * Creates XmlDirectoryPersister that picks up all files in specified folder
45 public XmlDirectoryPersister(final File storage) {
46 this(storage, Optional.<FilenameFilter>absent());
50 * Creates XmlDirectoryPersister that picks up files only with specified file extension
52 public XmlDirectoryPersister(final File storage, final Set<String> fileExtensions) {
53 this(storage, Optional.of(getFilter(fileExtensions)));
56 private XmlDirectoryPersister(final File storage, final Optional<FilenameFilter> extensionsFilter) {
57 checkArgument(storage.exists() && storage.isDirectory(), "Storage directory does not exist: " + storage);
58 this.storage = storage;
59 this.extensionsFilter = extensionsFilter;
63 public void persistConfig(final ConfigSnapshotHolder holder) throws IOException {
64 throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
68 public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
69 File[] filesArray = extensionsFilter.isPresent() ? storage.listFiles(extensionsFilter.get()) : storage.listFiles();
70 if (filesArray == null || filesArray.length == 0) {
71 return Collections.emptyList();
73 List<File> sortedFiles = new ArrayList<>(Arrays.asList(filesArray));
74 Collections.sort(sortedFiles);
75 // combine all found files
76 LOG.debug("Reading files in following order: {}", sortedFiles);
78 List<ConfigSnapshotHolder> result = new ArrayList<>();
79 for (File file : sortedFiles) {
80 LOG.trace("Adding file '{}' to combined result", file);
81 Optional<ConfigSnapshotHolder> h = fromXmlSnapshot(file);
82 // Ignore non valid snapshot
83 if(h.isPresent() == false) {
92 private Optional<ConfigSnapshotHolder> fromXmlSnapshot(final File file) {
94 return Optional.of(loadLastConfig(file));
95 } catch (JAXBException e) {
96 // In case of parse error, issue a warning, ignore and continue
98 "Unable to parse configuration snapshot from {}. Initial config from {} will be IGNORED in this run. ",
101 "Note that subsequent config files may fail due to this problem. ",
102 "Xml markup in this file needs to be fixed, for detailed information see enclosed exception.",
106 return Optional.absent();
109 public static ConfigSnapshotHolder loadLastConfig(final File file) throws JAXBException {
110 JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
111 Unmarshaller um = jaxbContext.createUnmarshaller();
112 XMLInputFactory xif = XMLInputFactory.newFactory();
113 xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
114 xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
116 XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource(file));
117 return asHolder((ConfigSnapshot) um.unmarshal(xsr));
118 } catch (final XMLStreamException e) {
119 throw new JAXBException(e);
123 private static ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) {
124 return new ConfigSnapshotHolder() {
126 public String getConfigSnapshot() {
127 return unmarshalled.getConfigSnapshot();
131 public SortedSet<String> getCapabilities() {
132 return unmarshalled.getCapabilities();
136 public String toString() {
137 return unmarshalled.toString();
142 private static FilenameFilter getFilter(final Set<String>fileExtensions) {
143 checkArgument(fileExtensions.isEmpty() == false, "No file extension provided", fileExtensions);
145 return new FilenameFilter() {
147 public boolean accept(final File dir, final String name) {
148 String ext = Files.getFileExtension(name);
149 return fileExtensions.contains(ext);
155 public void close() {
160 public String toString() {
161 final StringBuffer sb = new StringBuffer("XmlDirectoryPersister{");
162 sb.append("storage=").append(storage);
164 return sb.toString();