7e33ceea2a424543be139dc0641ea9bd9f2c163a
[controller.git] / opendaylight / config / config-persister-feature-adapter / src / main / java / org / opendaylight / controller / configpusherfeature / internal / AbstractFeatureWrapper.java
1 /*
2  * Copyright (c) 2014 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.configpusherfeature.internal;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.io.Files;
13 import java.io.File;
14 import java.io.FileInputStream;
15 import java.util.LinkedHashSet;
16 import java.util.List;
17 import java.util.Set;
18 import javax.xml.bind.JAXBException;
19 import javax.xml.parsers.DocumentBuilderFactory;
20 import javax.xml.stream.XMLStreamException;
21 import org.apache.karaf.features.BundleInfo;
22 import org.apache.karaf.features.Conditional;
23 import org.apache.karaf.features.ConfigFileInfo;
24 import org.apache.karaf.features.ConfigInfo;
25 import org.apache.karaf.features.Dependency;
26 import org.apache.karaf.features.Feature;
27 import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30 import org.w3c.dom.Element;
31
32 /*
33  * Wrap a Feature for the purposes of extracting the FeatureConfigSnapshotHolders from
34  * its underlying ConfigFileInfo's
35  *
36  * Delegates the the contained feature and provides additional methods.
37  */
38 public class AbstractFeatureWrapper implements Feature {
39     private static final Logger LOG = LoggerFactory.getLogger(AbstractFeatureWrapper.class);
40
41     protected static final String CONFIG_FILE_SUFFIX = "xml";
42
43     protected Feature feature = null;
44
45     protected AbstractFeatureWrapper() {
46         // prevent instantiation without Feature
47     }
48
49     /*
50      * @param f Feature to wrap
51      */
52     public AbstractFeatureWrapper(final Feature f) {
53         Preconditions.checkNotNull(f,"FeatureWrapper requires non-null Feature in constructor");
54         this.feature = f;
55     }
56
57     /*
58      * Get FeatureConfigSnapshotHolders appropriate to feed to the config subsystem
59      * from the underlying Feature Config files
60      */
61     public Set<FeatureConfigSnapshotHolder> getFeatureConfigSnapshotHolders() throws Exception {
62         final Set<FeatureConfigSnapshotHolder> snapShotHolders = new LinkedHashSet<>();
63         for(final ConfigFileInfo c: getConfigurationFiles()) {
64             // Skip non config snapshot XML files
65             if(isConfigSnapshot(c.getFinalname())) {
66                 final Optional<FeatureConfigSnapshotHolder> featureConfigSnapshotHolder = getFeatureConfigSnapshotHolder(c);
67                 if(featureConfigSnapshotHolder.isPresent()) {
68                     snapShotHolders.add(featureConfigSnapshotHolder.get());
69                 }
70             }
71         }
72         return snapShotHolders;
73     }
74
75     protected Optional<FeatureConfigSnapshotHolder> getFeatureConfigSnapshotHolder(final ConfigFileInfo c) {
76         try {
77             return Optional.of(new FeatureConfigSnapshotHolder(c, this));
78         } catch (final JAXBException e) {
79             LOG.warn("Unable to parse configuration snapshot. Config from '{}' will be IGNORED. " +
80                     "Note that subsequent config files may fail due to this problem. " +
81                     "Xml markup in this file needs to be fixed, for detailed information see enclosed exception.",
82                     c.getFinalname(), e);
83         } catch (final XMLStreamException e) {
84             // Files that cannot be loaded are ignored as non config subsystem files e.g. jetty.xml
85             LOG.debug("Unable to read configuration file '{}'. Not a configuration snapshot",
86                     c.getFinalname(), e);
87         }
88         return Optional.absent();
89     }
90
91     private static boolean isConfigSnapshot(final String fileName) {
92         if(!Files.getFileExtension(fileName).equals(CONFIG_FILE_SUFFIX)) {
93             return false;
94         }
95
96         if(fileName.endsWith("jetty.xml")) {
97             // Special case - ignore the jetty.xml file as it contains a DTD and causes a "Connection refused"
98             // error when it tries to go out to the network to retrieve it. We don't want it trying to go out
99             // to the network nor do we want an error logged trying to parse it.
100             return false;
101         }
102
103         File file = new File(System.getProperty("karaf.home"), fileName);
104         try(FileInputStream fis = new FileInputStream(file)) {
105             DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
106             builderFactory.setNamespaceAware(true);
107             builderFactory.setCoalescing(true);
108             builderFactory.setIgnoringElementContentWhitespace(true);
109             builderFactory.setIgnoringComments(true);
110
111             Element root = builderFactory.newDocumentBuilder().parse(fis).getDocumentElement();
112             return ConfigSnapshot.SNAPSHOT_ROOT_ELEMENT_NAME.equals(root.getLocalName());
113         } catch (final Exception e) {
114             LOG.error("Could not parse XML file {}", file, e);
115             return false;
116         }
117     }
118
119     @Override
120     public int hashCode() {
121         final int prime = 31;
122         int result = 1;
123         result = prime * result + (feature == null ? 0 : feature.hashCode());
124         return result;
125     }
126
127     @Override
128     public boolean equals(final Object obj) {
129         if (this == obj) {
130             return true;
131         }
132         if (obj == null) {
133             return false;
134         }
135         if (getClass() != obj.getClass()) {
136             return false;
137         }
138         final AbstractFeatureWrapper other = (AbstractFeatureWrapper) obj;
139         if (feature == null) {
140             if (other.feature != null) {
141                 return false;
142             }
143         } else if (!feature.equals(other.feature)) {
144             return false;
145         }
146         return true;
147     }
148
149     @Override
150     public String toString() {
151         return feature.getName();
152     }
153
154     /**
155      * @return
156      * @see org.apache.karaf.features.Feature#getId()
157      */
158     @Override
159     public String getId() {
160         return feature.getId();
161     }
162
163     /**
164      * @return
165      * @see org.apache.karaf.features.Feature#getName()
166      */
167     @Override
168     public String getName() {
169         return feature.getName();
170     }
171
172     /**
173      * @return
174      * @see org.apache.karaf.features.Feature#getDescription()
175      */
176     @Override
177     public String getDescription() {
178         return feature.getDescription();
179     }
180
181     /**
182      * @return
183      * @see org.apache.karaf.features.Feature#getDetails()
184      */
185     @Override
186     public String getDetails() {
187         return feature.getDetails();
188     }
189
190     /**
191      * @return
192      * @see org.apache.karaf.features.Feature#getVersion()
193      */
194     @Override
195     public String getVersion() {
196         return feature.getVersion();
197     }
198
199     /**
200      * @return
201      * @see org.apache.karaf.features.Feature#hasVersion()
202      */
203     @Override
204     public boolean hasVersion() {
205         return feature.hasVersion();
206     }
207
208     /**
209      * @return
210      * @see org.apache.karaf.features.Feature#getResolver()
211      */
212     @Override
213     public String getResolver() {
214         return feature.getResolver();
215     }
216
217     /**
218      * @return
219      * @see org.apache.karaf.features.Feature#getInstall()
220      */
221     @Override
222     public String getInstall() {
223         return feature.getInstall();
224     }
225
226     /**
227      * @return
228      * @see org.apache.karaf.features.Feature#getDependencies()
229      */
230     @Override
231     public List<Dependency> getDependencies() {
232         return feature.getDependencies();
233     }
234
235     /**
236      * @return
237      * @see org.apache.karaf.features.Feature#getBundles()
238      */
239     @Override
240     public List<BundleInfo> getBundles() {
241         return feature.getBundles();
242     }
243
244     /**
245      * @return
246      * @see org.apache.karaf.features.Feature#getConfigurations()
247      */
248     @Override
249     public List<ConfigInfo> getConfigurations() {
250         return feature.getConfigurations();
251     }
252
253     /**
254      * @return
255      * @see org.apache.karaf.features.Feature#getConfigurationFiles()
256      */
257     @Override
258     public List<ConfigFileInfo> getConfigurationFiles() {
259         return feature.getConfigurationFiles();
260     }
261
262     /**
263      * @return
264      * @see org.apache.karaf.features.Feature#getConditional()
265      */
266     @Override
267     public List<? extends Conditional> getConditional() {
268         return feature.getConditional();
269     }
270
271     /**
272      * @return
273      * @see org.apache.karaf.features.Feature#getStartLevel()
274      */
275     @Override
276     public int getStartLevel() {
277         return feature.getStartLevel();
278     }
279
280     /**
281      * @return
282      * @see org.apache.karaf.features.Feature#getRegion()
283      */
284     @Override
285     public String getRegion() {
286         return feature.getRegion();
287     }
288
289 }