68a33be5e67e02cf30f9fa83ca123fd82545ad76
[controller.git] / opendaylight / config / config-persister-file-xml-adapter / src / main / java / org / opendaylight / controller / config / persist / storage / file / xml / model / Config.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.file.xml.model;
9
10 import com.google.common.base.Optional;
11 import com.google.common.collect.Iterables;
12 import com.google.common.collect.Lists;
13 import com.google.common.io.Files;
14 import java.io.File;
15 import java.io.IOException;
16 import java.nio.charset.StandardCharsets;
17 import java.util.List;
18 import javax.xml.bind.JAXBContext;
19 import javax.xml.bind.JAXBException;
20 import javax.xml.bind.Marshaller;
21 import javax.xml.bind.Unmarshaller;
22 import javax.xml.bind.annotation.XmlElement;
23 import javax.xml.bind.annotation.XmlElementWrapper;
24 import javax.xml.bind.annotation.XmlRootElement;
25 import javax.xml.stream.XMLInputFactory;
26 import javax.xml.stream.XMLStreamException;
27 import javax.xml.stream.XMLStreamReader;
28 import javax.xml.transform.stream.StreamSource;
29 import org.apache.commons.lang3.StringUtils;
30
31 @XmlRootElement(name = "persisted-snapshots")
32 public final class Config {
33
34     private List<ConfigSnapshot> snapshots;
35
36     Config(List<ConfigSnapshot> snapshots) {
37         this.snapshots = snapshots;
38     }
39
40     public Config() {
41         this.snapshots = Lists.newArrayList();
42     }
43
44     @XmlElement(name = "snapshot")
45     @XmlElementWrapper(name = "snapshots")
46     public List<ConfigSnapshot> getSnapshots() {
47         return snapshots;
48     }
49
50     public void setSnapshots(List<ConfigSnapshot> snapshots) {
51         this.snapshots = snapshots;
52     }
53
54     public void toXml(File to) {
55         try {
56
57             // TODO Moxy has to be used instead of default jaxb impl due to a bug
58             // default implementation has a bug that prevents from serializing xml in a string
59             JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Config.class}, null);
60
61             Marshaller marshaller = jaxbContext.createMarshaller();
62
63             marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
64
65             marshaller.marshal(this, to);
66         } catch (JAXBException e) {
67             throw new PersistException("Unable to persist configuration", e);
68         }
69     }
70
71     public static Config fromXml(File from) {
72         if(isEmpty(from)) {
73             return new Config();
74         }
75
76         try {
77             JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
78             Unmarshaller um = jaxbContext.createUnmarshaller();
79             XMLInputFactory xif = XMLInputFactory.newFactory();
80             xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
81             xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
82             XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource(from));
83             return ((Config) um.unmarshal(xsr));
84         } catch (JAXBException | XMLStreamException e) {
85             throw new PersistException("Unable to restore configuration", e);
86         }
87     }
88
89     private static boolean isEmpty(File from) {
90         return from.length() == 0 || isBlank(from);
91     }
92
93     private static boolean isBlank(File from) {
94         try {
95             return StringUtils.isBlank(Files.toString(from, StandardCharsets.UTF_8));
96         } catch (IOException e) {
97             throw new IllegalStateException("Unexpected error reading file" + from, e);
98         }
99     }
100
101     public Optional<ConfigSnapshot> getLastSnapshot() {
102         ConfigSnapshot last = Iterables.getLast(snapshots, null);
103         return last == null ? Optional.<ConfigSnapshot>absent() : Optional.of(last);
104     }
105
106     public void addConfigSnapshot(ConfigSnapshot snap, int numberOfStoredBackups) {
107         if(shouldReplaceLast(numberOfStoredBackups) && snapshots.isEmpty() == false) {
108             snapshots.remove(0);
109         }
110         snapshots.add(snap);
111     }
112
113     private boolean shouldReplaceLast(int numberOfStoredBackups) {
114         return numberOfStoredBackups == snapshots.size();
115     }
116 }