blob: b618ac606befd5145e7fd0a54a6addfa8e812331 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2016 GianMaria Romanato
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.virgo.ide.facet.internal.core;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.eclipse.core.resources.IFile;
import org.osgi.framework.Version;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* A reader that builds a minimal plan descriptor for a plan file in the workspace. This class is a simplified version
* of a similar class existing in the Virgo Server runtime. This parser is not able to capture all the features of a
* plan; it just creates a minimal Plan object which lists the plan name, version and any other referred plan. Other
* type of child artifacts (e.g. bundles) or plan attributes (e.g. URI) are ignored as they are not relevant for the
* purpose of deploying workspace plan to the Virgo Runtime Environment.
*
*/
public final class PlanReader {
private static final String PLAN = "plan"; //$NON-NLS-1$
private static final String TYPE_ATTRIBUTE = "type"; //$NON-NLS-1$
private static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$
private static final String VERSION_ATTRIBUTE = "version"; //$NON-NLS-1$
private static final String ARTIFACT_ELEMENT = "artifact"; //$NON-NLS-1$
private static final String ATTRIBUTE_ELEMENT = "attribute"; //$NON-NLS-1$
private static final String VALUE_ATTRIBUTE = "value"; //$NON-NLS-1$
private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; //$NON-NLS-1$
private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema"; //$NON-NLS-1$
private static final Object BUNDLE = "bundle"; //$NON-NLS-1$
/**
* Creates a {@link PlanDescriptor} meta-data artifact from an {@link InputStream}
*
* @param inputStream from which the plan is to be read
* @return The plan descriptor (meta-data) from the input stream
*/
public Plan read(IFile file) {
org.eclipse.core.runtime.Assert.isNotNull(file, "file cannot be null");
InputStream inputStream = null;
try {
inputStream = file.getContents();
Document doc = readDocument(inputStream);
Element element = doc.getDocumentElement();
return parsePlanElement(file, element);
} catch (Exception e) {
throw new RuntimeException("Failed to read plan descriptor", e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
}
}
}
}
private Document readDocument(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilder builder = createDocumentBuilderFactory().newDocumentBuilder();
builder.setErrorHandler(new ErrorHandler() {
public void warning(SAXParseException exception) throws SAXException {
}
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
});
return builder.parse(inputStream);
}
private DocumentBuilderFactory createDocumentBuilderFactory() {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(false);
factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
return factory;
}
private Plan parsePlanElement(IFile file, Element element) {
String name = element.getAttribute(NAME_ATTRIBUTE);
Version version = new Version(element.getAttribute(VERSION_ATTRIBUTE));
Properties attributes = parseAttributes(element);
List<Artifact> artifacts = parseNestedArtifacts(element.getElementsByTagName(ARTIFACT_ELEMENT), attributes);
return new Plan(name, version, artifacts);
}
private Properties parseAttributes(Element element) {
Properties result = new Properties();
NodeList attributeElements = element.getElementsByTagName(ATTRIBUTE_ELEMENT);
for (int x = 0; x < attributeElements.getLength(); x++) {
Element attribute = (Element) attributeElements.item(x);
String name = attribute.getAttribute(NAME_ATTRIBUTE);
String value = attribute.getAttribute(VALUE_ATTRIBUTE);
result.put(name, value);
}
return result;
}
private List<Artifact> parseNestedArtifacts(NodeList artifactElements, Properties attributes) {
List<Artifact> refs = new ArrayList<Artifact>();
for (int i = 0; i < artifactElements.getLength(); i++) {
Element artifactElement = (Element) artifactElements.item(i);
String type = artifactElement.getAttribute(TYPE_ATTRIBUTE);
String name = artifactElement.getAttribute(NAME_ATTRIBUTE);
String versionString = artifactElement.getAttribute(VERSION_ATTRIBUTE);
Version version = null;
if (versionString != null && !versionString.isEmpty()) {
version = new Version(versionString);
}
if (PLAN.equals(type)) {
refs.add(new PlanReference(name, version));
} else if (BUNDLE.equals(type)) {
refs.add(new BundleReference(name, version));
}
}
return refs;
}
}