/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.configpusherfeature.internal; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.io.Files; import java.io.File; import java.io.FileInputStream; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.xml.bind.JAXBException; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLStreamException; import org.apache.karaf.features.BundleInfo; import org.apache.karaf.features.Conditional; import org.apache.karaf.features.ConfigFileInfo; import org.apache.karaf.features.ConfigInfo; import org.apache.karaf.features.Dependency; import org.apache.karaf.features.Feature; import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Element; /* * Wrap a Feature for the purposes of extracting the FeatureConfigSnapshotHolders from * its underlying ConfigFileInfo's * * Delegates the the contained feature and provides additional methods. */ public class AbstractFeatureWrapper implements Feature { private static final Logger LOG = LoggerFactory.getLogger(AbstractFeatureWrapper.class); protected static final String CONFIG_FILE_SUFFIX = "xml"; protected Feature feature = null; protected AbstractFeatureWrapper() { // prevent instantiation without Feature } /* * @param f Feature to wrap */ public AbstractFeatureWrapper(final Feature f) { Preconditions.checkNotNull(f,"FeatureWrapper requires non-null Feature in constructor"); this.feature = f; } /* * Get FeatureConfigSnapshotHolders appropriate to feed to the config subsystem * from the underlying Feature Config files */ public Set getFeatureConfigSnapshotHolders() throws Exception { final Set snapShotHolders = new LinkedHashSet<>(); for(final ConfigFileInfo c: getConfigurationFiles()) { // Skip non config snapshot XML files if(isConfigSnapshot(c.getFinalname())) { final Optional featureConfigSnapshotHolder = getFeatureConfigSnapshotHolder(c); if(featureConfigSnapshotHolder.isPresent()) { snapShotHolders.add(featureConfigSnapshotHolder.get()); } } } return snapShotHolders; } protected Optional getFeatureConfigSnapshotHolder(final ConfigFileInfo c) { try { return Optional.of(new FeatureConfigSnapshotHolder(c, this)); } catch (final JAXBException e) { LOG.warn("Unable to parse configuration snapshot. Config from '{}' will be IGNORED. " + "Note that subsequent config files may fail due to this problem. " + "Xml markup in this file needs to be fixed, for detailed information see enclosed exception.", c.getFinalname(), e); } catch (final XMLStreamException e) { // Files that cannot be loaded are ignored as non config subsystem files e.g. jetty.xml LOG.debug("Unable to read configuration file '{}'. Not a configuration snapshot", c.getFinalname(), e); } return Optional.absent(); } private static boolean isConfigSnapshot(String fileName) { if(!Files.getFileExtension(fileName).equals(CONFIG_FILE_SUFFIX)) { return false; } if(fileName.endsWith("jetty.xml")) { // Special case - ignore the jetty.xml file as it contains a DTD and causes a "Connection refused" // error when it tries to go out to the network to retrieve it. We don't want it trying to go out // to the network nor do we want an error logged trying to parse it. return false; } File file = new File(System.getProperty("karaf.home"), fileName); try(FileInputStream fis = new FileInputStream(file)) { DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setNamespaceAware(true); builderFactory.setCoalescing(true); builderFactory.setIgnoringElementContentWhitespace(true); builderFactory.setIgnoringComments(true); Element root = builderFactory.newDocumentBuilder().parse(fis).getDocumentElement(); return ConfigSnapshot.SNAPSHOT_ROOT_ELEMENT_NAME.equals(root.getLocalName()); } catch (Exception e) { LOG.error("Could not parse XML file {}", file, e); return false; } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (feature == null ? 0 : feature.hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final AbstractFeatureWrapper other = (AbstractFeatureWrapper) obj; if (feature == null) { if (other.feature != null) { return false; } } else if (!feature.equals(other.feature)) { return false; } return true; } @Override public String toString() { return feature.getName(); } /** * @return * @see org.apache.karaf.features.Feature#getId() */ @Override public String getId() { return feature.getId(); } /** * @return * @see org.apache.karaf.features.Feature#getName() */ @Override public String getName() { return feature.getName(); } /** * @return * @see org.apache.karaf.features.Feature#getDescription() */ @Override public String getDescription() { return feature.getDescription(); } /** * @return * @see org.apache.karaf.features.Feature#getDetails() */ @Override public String getDetails() { return feature.getDetails(); } /** * @return * @see org.apache.karaf.features.Feature#getVersion() */ @Override public String getVersion() { return feature.getVersion(); } /** * @return * @see org.apache.karaf.features.Feature#hasVersion() */ @Override public boolean hasVersion() { return feature.hasVersion(); } /** * @return * @see org.apache.karaf.features.Feature#getResolver() */ @Override public String getResolver() { return feature.getResolver(); } /** * @return * @see org.apache.karaf.features.Feature#getInstall() */ @Override public String getInstall() { return feature.getInstall(); } /** * @return * @see org.apache.karaf.features.Feature#getDependencies() */ @Override public List getDependencies() { return feature.getDependencies(); } /** * @return * @see org.apache.karaf.features.Feature#getBundles() */ @Override public List getBundles() { return feature.getBundles(); } /** * @return * @see org.apache.karaf.features.Feature#getConfigurations() */ @Override public List getConfigurations() { return feature.getConfigurations(); } /** * @return * @see org.apache.karaf.features.Feature#getConfigurationFiles() */ @Override public List getConfigurationFiles() { return feature.getConfigurationFiles(); } /** * @return * @see org.apache.karaf.features.Feature#getConditional() */ @Override public List getConditional() { return feature.getConditional(); } /** * @return * @see org.apache.karaf.features.Feature#getStartLevel() */ @Override public int getStartLevel() { return feature.getStartLevel(); } /** * @return * @see org.apache.karaf.features.Feature#getRegion() */ @Override public String getRegion() { return feature.getRegion(); } }