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;
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;
23 import java.util.SortedSet;
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;
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;
39 public class XmlDirectoryPersister implements Persister {
40 private static final Logger LOG = LoggerFactory.getLogger(XmlDirectoryPersister.class);
42 private final File storage;
43 private final Optional<FilenameFilter> extensionsFilter;
46 * Creates XmlDirectoryPersister that picks up all files in specified folder.
48 public XmlDirectoryPersister(final File storage) {
49 this(storage, Optional.<FilenameFilter>absent());
53 * Creates XmlDirectoryPersister that picks up files only with specified file extension.
55 public XmlDirectoryPersister(final File storage, final Set<String> fileExtensions) {
56 this(storage, Optional.of(getFilter(fileExtensions)));
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;
66 public void persistConfig(final ConfigSnapshotHolder holder) throws IOException {
67 throw new UnsupportedOperationException("This adapter is read only. Please set readonly=true on " + getClass());
71 public List<ConfigSnapshotHolder> loadLastConfigs() throws IOException {
73 extensionsFilter.isPresent() ? storage.listFiles(extensionsFilter.get()) : storage.listFiles();
74 if (filesArray == null || filesArray.length == 0) {
75 return Collections.emptyList();
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);
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()) {
91 result.add(configSnapshotHolderOptional.get());
96 private Optional<ConfigSnapshotHolder> fromXmlSnapshot(final File file) {
98 return Optional.of(loadLastConfig(file));
99 } catch (final JAXBException e) {
100 // In case of parse error, issue a warning, ignore and continue
102 "Unable to parse configuration snapshot from {}. "
103 + "Initial config from {} will be IGNORED in this run. ",
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.",
111 return Optional.absent();
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);
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);
128 private static ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) {
129 return new ConfigSnapshotHolder() {
131 public String getConfigSnapshot() {
132 return unmarshalled.getConfigSnapshot();
136 public SortedSet<String> getCapabilities() {
137 return unmarshalled.getCapabilities();
141 public String toString() {
142 return unmarshalled.toString();
147 private static FilenameFilter getFilter(final Set<String> fileExtensions) {
148 checkArgument(!fileExtensions.isEmpty(), "No file extension provided", fileExtensions);
150 return (dir, name) -> {
151 String ext = Files.getFileExtension(name);
152 return fileExtensions.contains(ext);
157 public void close() {
161 public String toString() {
162 return "XmlDirectoryPersister{storage=" + storage + "}";