package com.onaro.sanscreen.client.packages; import java.util.Set; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.netapp.sanscreen.server.product.shared.features.interfaces.data.Feature; import com.onaro.sanscreen.client.Resources; import com.onaro.sanscreen.client.features.FeatureManager; import com.onaro.util.xml.XmlIterator; public class ConfigByFeatureFactory { /** * The logger for this class. */ static final Logger logger = LogManager.getLogger(ConfigByFeatureFactory.class); private Document document; private Set documentFeatures; private static final ConfigByFeatureFactory INSTANCE = new ConfigByFeatureFactory(); private static ConfigByFeatureFactory getInstance() { return INSTANCE; } private ConfigByFeatureFactory() { // do nothing } public static Document getDocument() { return getInstance().getDocumentImpl(); } private synchronized Document getDocumentImpl() { try { Set enabledFeatures = FeatureManager.getInstance().getEnabledFeatures(); // Check that the features haven't changed since the document was last loaded if (document != null) { if (!enabledFeatures.equals(documentFeatures)) { document = null; } } if (document == null) { document = Resources.INSTANCE.getConfigDocument(); // TODO: Is special handling still required for Demo licenses? // This is inconsistent with changes elsewhere to make client independent of license type. // Don't know if this check makes encoder views inconsistent with API views. if (!com.onaro.util.LicenseUtil.isDemo()) { filterDoc(document, enabledFeatures); documentFeatures = enabledFeatures; } else { // since the demo license does not include the rest of the packages, just use the config.xml without // filtering out any element } } return document; } catch (Exception e) { throw new RuntimeException("Failed to determine enabled features", e); //$NON-NLS-1$ } } /** * Gets the configuration XML. The actual XML depends on the enabled features as reported by the server. Note that * the configuration file can be specified using the "client.config" system property (this is used when launching * demo client). * * @return an XML iterator for the configuration file that matches the installed packages. */ public static XmlIterator getConfiguration() { Document document = getDocument(); return new XmlIterator(document); } private void filterDoc(Document doc, Set enabledFeatures) { Node root = doc.getDocumentElement(); recursivelyRemoveNodesWithDisabledFeature(root, enabledFeatures); } private void recursivelyRemoveNodesWithDisabledFeature(Node element, Set enabledFeatures) { NodeList childNodes = element.getChildNodes(); for (int i = childNodes.getLength() - 1; i >= 0; i--) { Node child = childNodes.item(i); if (supportedInFeature(child, enabledFeatures)) { recursivelyRemoveNodesWithDisabledFeature(child, enabledFeatures); } else { element.removeChild(child); } } } private boolean supportedInFeature(Node child, Set enabledFeatures) { String featureAttValue = getFeatureAttribute(child); if (featureAttValue != null) { // If multiple features are required using AND syntax if (featureAttValue.contains("&")) { //$NON-NLS-1$ // Parse the AND statement into required features String[] andFeatures = featureAttValue.split("\\&"); //$NON-NLS-1$ // Return true only if all of the features are enabled for (String andFeature : andFeatures) { if (!enabledFeatures.contains(Feature.valueOf(andFeature.trim()))) { return false; } } return true; // Otherwise, if multiple features are required using OR syntax } else if (featureAttValue.contains("|")) { //$NON-NLS-1$ // Parse the OR statement into required features String[] orFeatures = featureAttValue.split("\\|"); //$NON-NLS-1$ // Return true if any of the features are enabled for (String orFeature : orFeatures) { if (enabledFeatures.contains(Feature.valueOf(orFeature.trim()))) { return true; } } // Otherwise return false return false; // Otherwise, only a single feature is required } else { return enabledFeatures.contains(Feature.valueOf(featureAttValue)); } } // if the package is not specified, the element should be included return true; } private String getFeatureAttribute(Node child) { NamedNodeMap attributes = child.getAttributes(); if (attributes != null) { Node namedItem = attributes.getNamedItem("feature"); //$NON-NLS-1$ if (namedItem != null) { String featureAttribute = namedItem.getNodeValue(); if (featureAttribute != null && featureAttribute.length() > 0) { return featureAttribute; } } } return null; } }