2 * Copyright (c) 2014 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.configpusherfeature.internal;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.io.Files;
15 import java.io.FileInputStream;
16 import java.io.IOException;
17 import java.util.LinkedHashSet;
18 import java.util.List;
21 import javax.xml.bind.JAXBException;
22 import javax.xml.parsers.DocumentBuilderFactory;
23 import javax.xml.parsers.ParserConfigurationException;
24 import javax.xml.stream.XMLStreamException;
26 import org.apache.karaf.features.BundleInfo;
27 import org.apache.karaf.features.Capability;
28 import org.apache.karaf.features.Conditional;
29 import org.apache.karaf.features.ConfigFileInfo;
30 import org.apache.karaf.features.ConfigInfo;
31 import org.apache.karaf.features.Dependency;
32 import org.apache.karaf.features.Feature;
33 import org.apache.karaf.features.Library;
34 import org.apache.karaf.features.Requirement;
35 import org.apache.karaf.features.Scoping;
36 import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import org.w3c.dom.Element;
40 import org.xml.sax.SAXException;
43 * Wrap a Feature for the purposes of extracting the FeatureConfigSnapshotHolders from
44 * its underlying ConfigFileInfo's
46 * Delegates the the contained feature and provides additional methods.
48 public class AbstractFeatureWrapper implements Feature {
49 private static final Logger LOG = LoggerFactory.getLogger(AbstractFeatureWrapper.class);
51 protected static final String CONFIG_FILE_SUFFIX = "xml";
53 protected Feature feature = null;
55 protected AbstractFeatureWrapper() {
56 // prevent instantiation without Feature
60 * @param f Feature to wrap
62 public AbstractFeatureWrapper(final Feature feature) {
63 Preconditions.checkNotNull(feature, "FeatureWrapper requires non-null Feature in constructor");
64 this.feature = feature;
68 * Get FeatureConfigSnapshotHolders appropriate to feed to the config subsystem
69 * from the underlying Feature Config files
71 public Set<FeatureConfigSnapshotHolder> getFeatureConfigSnapshotHolders() throws Exception {
72 final Set<FeatureConfigSnapshotHolder> snapShotHolders = new LinkedHashSet<>();
73 for (final ConfigFileInfo c : getConfigurationFiles()) {
74 // Skip non config snapshot XML files
75 if (isConfigSnapshot(c.getFinalname())) {
76 final Optional<FeatureConfigSnapshotHolder> featureConfigSnapshotHolder =
77 getFeatureConfigSnapshotHolder(c);
78 if (featureConfigSnapshotHolder.isPresent()) {
79 snapShotHolders.add(featureConfigSnapshotHolder.get());
83 return snapShotHolders;
86 protected Optional<FeatureConfigSnapshotHolder>
87 getFeatureConfigSnapshotHolder(final ConfigFileInfo configFileInfo) {
89 return Optional.of(new FeatureConfigSnapshotHolder(configFileInfo, this));
90 } catch (final JAXBException e) {
91 LOG.warn("Unable to parse configuration snapshot. Config from '{}' will be IGNORED. "
92 + "Note that subsequent config files may fail due to this problem. "
93 + "Xml markup in this file needs to be fixed, for detailed information see enclosed exception.",
94 configFileInfo.getFinalname(), e);
95 } catch (final XMLStreamException e) {
96 // Files that cannot be loaded are ignored as non config subsystem files e.g. jetty.xml
97 LOG.debug("Unable to read configuration file '{}'. Not a configuration snapshot",
98 configFileInfo.getFinalname(), e);
100 return Optional.absent();
103 private static boolean isConfigSnapshot(final String fileName) {
104 if (!Files.getFileExtension(fileName).equals(CONFIG_FILE_SUFFIX)) {
108 if (fileName.endsWith("jetty.xml")) {
109 // Special case - ignore the jetty.xml file as it contains a DTD and causes a "Connection refused"
110 // error when it tries to go out to the network to retrieve it. We don't want it trying to go out
111 // to the network nor do we want an error logged trying to parse it.
115 File file = new File(System.getProperty("karaf.home"), fileName);
116 try (FileInputStream fis = new FileInputStream(file)) {
117 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
118 builderFactory.setNamespaceAware(true);
119 builderFactory.setCoalescing(true);
120 builderFactory.setIgnoringElementContentWhitespace(true);
121 builderFactory.setIgnoringComments(true);
123 Element root = builderFactory.newDocumentBuilder().parse(fis).getDocumentElement();
124 return ConfigSnapshot.SNAPSHOT_ROOT_ELEMENT_NAME.equals(root.getLocalName());
125 } catch (final ParserConfigurationException | IOException | SAXException e) {
126 LOG.error("Could not parse XML file {}", file, e);
132 public int hashCode() {
133 final int prime = 31;
135 result = prime * result + (feature == null ? 0 : feature.hashCode());
140 public boolean equals(final Object obj) {
147 if (getClass() != obj.getClass()) {
150 final AbstractFeatureWrapper other = (AbstractFeatureWrapper) obj;
151 if (feature == null) {
152 if (other.feature != null) {
155 } else if (!feature.equals(other.feature)) {
162 public String toString() {
163 return feature.getName();
167 public String getId() {
168 return feature.getId();
172 public String getName() {
173 return feature.getName();
177 public String getDescription() {
178 return feature.getDescription();
182 public String getDetails() {
183 return feature.getDetails();
187 public String getVersion() {
188 return feature.getVersion();
192 public boolean hasVersion() {
193 return feature.hasVersion();
197 public String getResolver() {
198 return feature.getResolver();
202 public String getInstall() {
203 return feature.getInstall();
207 public List<Dependency> getDependencies() {
208 return feature.getDependencies();
212 public List<BundleInfo> getBundles() {
213 return feature.getBundles();
217 public List<ConfigInfo> getConfigurations() {
218 return feature.getConfigurations();
222 public List<ConfigFileInfo> getConfigurationFiles() {
223 return feature.getConfigurationFiles();
227 public List<? extends Conditional> getConditional() {
228 return feature.getConditional();
232 public int getStartLevel() {
233 return feature.getStartLevel();
237 public List<? extends Capability> getCapabilities() {
238 return feature.getCapabilities();
242 public List<? extends Library> getLibraries() {
243 return feature.getLibraries();
247 public String getNamespace() {
248 return feature.getNamespace();
252 public String getRepositoryUrl() {
253 return feature.getRepositoryUrl();
257 public List<? extends Requirement> getRequirements() {
258 return feature.getRequirements();
262 public List<String> getResourceRepositories() {
263 return feature.getResourceRepositories();
267 public Scoping getScoping() {
268 return feature.getScoping();
272 public boolean isHidden() {
273 return feature.isHidden();