blob: b33b4e16ebc110a2b22a1b147e186d61b41687fb [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2017 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.core.target;
import java.io.*;
import java.text.MessageFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetPlatformService;
import org.eclipse.pde.internal.core.ICoreConstants;
import org.eclipse.pde.internal.core.PDECore;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Provides static methods that will serialize and deserialize xml representing a target definition
*
* @see ITargetDefinition
*/
public class TargetDefinitionPersistenceHelper {
/**
* Constants for XML element names and attributes
*/
static final String ROOT = "target"; //$NON-NLS-1$
static final String ATTR_NAME = "name"; //$NON-NLS-1$
static final String LOCATIONS = "locations"; //$NON-NLS-1$
static final String LOCATION = "location"; //$NON-NLS-1$
static final String ATTR_LOCATION_PATH = "path"; //$NON-NLS-1$
static final String ATTR_LOCATION_TYPE = "type"; //$NON-NLS-1$
static final String ATTR_USE_DEFAULT = "useDefault"; //$NON-NLS-1$
static final String INCLUDE_BUNDLES = "includeBundles"; //$NON-NLS-1$
static final String ENVIRONMENT = "environment"; //$NON-NLS-1$
static final String OS = "os"; //$NON-NLS-1$
static final String WS = "ws"; //$NON-NLS-1$
static final String ARCH = "arch"; //$NON-NLS-1$
static final String NL = "nl"; //$NON-NLS-1$
static final String TARGET_JRE = "targetJRE"; //$NON-NLS-1$
static final String EXEC_ENV = "execEnv"; //$NON-NLS-1$
static final String JRE_NAME = "jreName"; //$NON-NLS-1$
static final String ARGUMENTS = "launcherArgs"; //$NON-NLS-1$
static final String PROGRAM_ARGS = "programArgs"; //$NON-NLS-1$
static final String VM_ARGS = "vmArgs"; //$NON-NLS-1$
static final String IMPLICIT = "implicitDependencies"; //$NON-NLS-1$
static final String PLUGIN = "plugin"; //$NON-NLS-1$
static final String PDE_INSTRUCTION = "pde"; //$NON-NLS-1$
static final String ATTR_ID = "id"; //$NON-NLS-1$
static final String INSTALLABLE_UNIT = "unit"; //$NON-NLS-1$
static final String REPOSITORY = "repository"; //$NON-NLS-1$
static final String ATTR_INCLUDE_MODE = "includeMode"; //$NON-NLS-1$
public static final String MODE_SLICER = "slicer"; //$NON-NLS-1$
public static final String MODE_PLANNER = "planner"; //$NON-NLS-1$
static final String ATTR_INCLUDE_ALL_PLATFORMS = "includeAllPlatforms"; //$NON-NLS-1$
static final String ATTR_INCLUDE_SOURCE = "includeSource"; //$NON-NLS-1$
static final String ATTR_INCLUDE_CONFIGURE_PHASE = "includeConfigurePhase"; //$NON-NLS-1$
static final String ATTR_VERSION = "version"; //$NON-NLS-1$
static final String ATTR_CONFIGURATION = "configuration"; //$NON-NLS-1$
static final String ATTR_SEQUENCE_NUMBER = "sequenceNumber"; //$NON-NLS-1$
static final String CONTENT = "content"; //$NON-NLS-1$
static final String ATTR_USE_ALL = "useAllPlugins"; //$NON-NLS-1$
static final String PLUGINS = "plugins"; //$NON-NLS-1$
static final String FEATURES = "features"; //$NON-NLS-1$
static final String FEATURE = "feature"; //$NON-NLS-1$
static final String EXTRA_LOCATIONS = "extraLocations"; //$NON-NLS-1$
private static ITargetPlatformService fTargetService;
/**
* Serializes a target definition to xml and writes the xml to the given stream
*
* @param definition
* target definition to serialize
* @param output
* output file buffer to write xml to
* @throws CoreException
* @throws ParserConfigurationException
* @throws TransformerException
* @throws IOException
* @throws SAXException
*/
public static void persistXML(ITargetDefinition definition, ITextFileBuffer output)
throws CoreException, ParserConfigurationException, TransformerException, IOException, SAXException {
if (output == null) {
return;
}
Document document = definition.getDocument();
DOMSource source = new DOMSource(document);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
StreamResult outputTarget = new StreamResult(outputStream);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, outputTarget);
// Convert the line separators
byte[] bytes = outputStream.toByteArray();
String encoding = output.getEncoding();
String strContent = outputStream.toString(encoding);
strContent = strContent.replace(System.getProperty("line.separator"), //$NON-NLS-1$
TextUtilities.getDefaultLineDelimiter(output.getDocument()));
bytes = strContent.getBytes(encoding);
try (OutputStream stream = output.getFileStore().openOutputStream(0, null)) {
stream.write(bytes);
}
}
/**
* Parses an xml document from the text file buffer and deserializes it into a
* target definition.
*
* @param definition
* definition to be filled with the result of
* deserialization
* @param input
* text file buffer to get xml input from
* @throws CoreException
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public static void initFromXML(ITargetDefinition definition, ITextFileBuffer input)
throws CoreException, ParserConfigurationException, SAXException, IOException {
if (input == null) {
return;
}
InputStream stream = null;
if (input.isDirty()) {
String documentContent = input.getDocument().get();
if (!documentContent.isEmpty()) {
stream = new ByteArrayInputStream(documentContent.getBytes());
} else {
return;
}
} else {
stream = input.getFileStore().openInputStream(0, null);
if (stream.available() == 0) {
// do not process empty stream
return;
}
}
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
parser.setErrorHandler(new DefaultHandler());
Document doc = parser.parse(new InputSource(stream));
stream.close();
Element root = doc.getDocumentElement();
if (!root.getNodeName().equalsIgnoreCase(ROOT)) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.TargetDefinitionPersistenceHelper_0));
}
String version = null;
NodeList list = doc.getChildNodes();
for (int i = 0; i < list.getLength(); ++i) {
Node node = list.item(i);
if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
ProcessingInstruction instruction = (ProcessingInstruction) node;
if (instruction.getTarget() == PDE_INSTRUCTION) {
String data = instruction.getData();
Pattern pattern = Pattern.compile(ATTR_VERSION + "=\"(.*)\""); //$NON-NLS-1$
Matcher matcher = pattern.matcher(data);
if (matcher.matches()) {
version = matcher.group(1);
break;
}
}
}
}
// Avoid doing the rebuilding of each part of the document, just set the
// document at the end
definition.setDocument(null);
// Select the correct helper class to use
// Note: If file structure is updated, make sure to update both default cases
if (version == null || version.length() == 0) {
// No version, default to latest
TargetPersistence38Helper.initFromDoc(definition, root);
} else if (version.equals(ICoreConstants.TARGET38)) {
TargetPersistence38Helper.initFromDoc(definition, root);
} else if (version.equals(ICoreConstants.TARGET36)) { // it can not be 3.7
TargetPersistence36Helper.initFromDoc(definition, root);
} else if (version.equals(ICoreConstants.TARGET35)) {
TargetPersistence35Helper.initFromDoc(definition, root);
} else if (version.compareTo(ICoreConstants.TARGET34) <= 0) {
TargetPersistence34Helper.initFromDoc(definition, root);
} else {
// Version doesn't match any known file structure, default to latest
String name = root.getAttribute(TargetDefinitionPersistenceHelper.ATTR_NAME);
PDECore.log(new Status(IStatus.WARNING, PDECore.PLUGIN_ID, MessageFormat.format(Messages.TargetDefinitionPersistenceHelper_2, version, name)));
TargetPersistence38Helper.initFromDoc(definition, root);
}
definition.setDocument(doc);
}
static ITargetPlatformService getTargetPlatformService() throws CoreException {
if (fTargetService == null) {
fTargetService = PDECore.getDefault().acquireService(ITargetPlatformService.class);
if (fTargetService == null) {
throw new CoreException(new Status(IStatus.ERROR, PDECore.PLUGIN_ID, Messages.TargetDefinitionPersistenceHelper_1));
}
}
return fTargetService;
}
/**
* Returns the value of any text nodes stored as children of the given element
* @param element the element to check for text content
* @return string containing text content of element or empty string
* @throws DOMException
*/
static String getTextContent(Element element) throws DOMException {
NodeList children = element.getChildNodes();
StringBuilder result = new StringBuilder();
for (int i = 0; i < children.getLength(); ++i) {
Node currentNode = children.item(i);
if (currentNode.getNodeType() == Node.TEXT_NODE) {
result.append(currentNode.getNodeValue());
}
}
return result.toString();
}
}