blob: aa7a7b6b6041670151428b08a36d65eb539f5c1f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* xored software, Inc. - initial API and Implementation
*******************************************************************************/
package org.eclipse.dltk.validators.internal.core;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.validators.core.IValidator;
import org.eclipse.dltk.validators.core.IValidatorType;
import org.eclipse.dltk.validators.core.ValidatorRuntime;
import org.eclipse.osgi.util.NLS;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class ValidatorDefinitionsContainer {
private static final String NODE_VALIDATOR_SETTINGS = "validatorSettings"; //$NON-NLS-1$
private static final String NODE_VALIDATOR_TYPE = "validatorType"; //$NON-NLS-1$
private static final String NODE_VALIDATOR = "validator"; //$NON-NLS-1$
private static final String ATTR_ID = "id"; //$NON-NLS-1$
private final Map<IValidatorType, List<IValidator>> fValidatorsByType = new HashMap<>(10);
private final List<IValidator> fValidatorList = new ArrayList<>(10);
public void addValidator(IValidator validator) {
if (!fValidatorList.contains(validator)) {
fValidatorList.add(validator);
IValidatorType type = validator.getValidatorType();
List<IValidator> typeValidators = fValidatorsByType.get(type);
if (typeValidators == null) {
typeValidators = new ArrayList<>(3);
fValidatorsByType.put(type, typeValidators);
}
typeValidators.add(validator);
}
}
public void addValidators(List<IValidator> validatorList) {
for (IValidator validator : validatorList) {
addValidator(validator);
}
}
public void addValidators(IValidator[] validators) {
for (int i = 0; i < validators.length; ++i) {
addValidator(validators[i]);
}
}
/**
* Returns unmodifiable list of all {@link IValidator}s
*
* @return
*/
public List<IValidator> getValidatorList() {
return Collections.unmodifiableList(fValidatorList);
}
/**
* Returns unmodifiable list of {@link IValidator}s of the specified nature,
* validators contributed to all natures are also returned.
*
* @param nature
* @return
*/
public List<IValidator> getValidatorList(String nature) {
final List<IValidator> result = new ArrayList<>(fValidatorList.size());
for (Iterator<Entry<IValidatorType, List<IValidator>>> i = fValidatorsByType.entrySet().iterator(); i
.hasNext();) {
final Entry<IValidatorType, List<IValidator>> entry = i.next();
final IValidatorType type = entry.getKey();
final String typeNature = type.getNature();
if (nature.equals(typeNature) || ValidatorRuntime.ANY_NATURE.equals(typeNature)) {
result.addAll(entry.getValue());
}
}
return Collections.unmodifiableList(result);
}
public String getAsXML() throws ParserConfigurationException, IOException, TransformerException {
// Create the Document and the top-level node
Document doc = ValidatorsCore.getDocument();
Element config = doc.createElement(NODE_VALIDATOR_SETTINGS);
doc.appendChild(config);
// Create a node for each validator type represented in this container
for (Iterator<Entry<IValidatorType, List<IValidator>>> i = fValidatorsByType.entrySet().iterator(); i
.hasNext();) {
final Entry<IValidatorType, List<IValidator>> entry = i.next();
final IValidatorType validatorType = entry.getKey();
if (validatorType.isConfigurable()) {
Element valiatorTypeElement = validatorTypeAsElement(doc, validatorType, entry.getValue());
config.appendChild(valiatorTypeElement);
}
}
// Serialize the Document and return the resulting String
return ValidatorsCore.serializeDocument(doc);
}
private Element validatorTypeAsElement(Document doc, IValidatorType validatorType, List<IValidator> validatorList) {
// Create a node for the Interpreter type and set its 'id' attribute
Element element = doc.createElement(NODE_VALIDATOR_TYPE);
element.setAttribute(ATTR_ID, validatorType.getID());
// For each validator of the specified type, create a subordinate node
// for it
for (Iterator<IValidator> i = validatorList.iterator(); i.hasNext();) {
IValidator validator = i.next();
Element validatorElement = validatorAsElement(doc, validator);
element.appendChild(validatorElement);
}
return element;
}
private Element validatorAsElement(Document doc, IValidator validator) {
// Create the node for the validator and set its 'id' & 'name'
// attributes
Element element = doc.createElement(NODE_VALIDATOR);
element.setAttribute(ATTR_ID, validator.getID());
validator.storeTo(doc, element);
return element;
}
public static ValidatorDefinitionsContainer createFromXML(Reader input) throws IOException {
ValidatorDefinitionsContainer container = new ValidatorDefinitionsContainer();
container.parseXML(new InputSource(input));
return container;
}
public void parseXML(InputSource input) throws IOException {
// Do the parsing and obtain the top-level node
Element config = null;
try {
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
parser.setErrorHandler(new DefaultHandler());
config = parser.parse(input).getDocumentElement();
} catch (SAXException e) {
throw new IOException(ValidatorMessages.ValidatorRuntime_badFormat);
} catch (ParserConfigurationException e) {
throw new IOException(ValidatorMessages.ValidatorRuntime_badFormat);
}
// If the top-level node wasn't what we expected, bail out
if (!config.getNodeName().equalsIgnoreCase(NODE_VALIDATOR_SETTINGS)) {
throw new IOException(ValidatorMessages.ValidatorRuntime_badFormat);
}
// Traverse the parsed structure and populate the InterpreterType to
// Interpreter Map
NodeList list = config.getChildNodes();
int length = list.getLength();
for (int i = 0; i < length; ++i) {
Node node = list.item(i);
short type = node.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element validatorTypeElement = (Element) node;
if (validatorTypeElement.getNodeName().equalsIgnoreCase(NODE_VALIDATOR_TYPE)) {
populateValidatorType(validatorTypeElement);
}
}
}
}
/**
* For the specified Interpreter type node, parse all subordinate
* Interpreter definitions and add them to the specified container.
*/
private void populateValidatorType(Element validatorTypeElement) {
// Retrieve the 'id' attribute and the corresponding Interpreter type
// object
String id = validatorTypeElement.getAttribute(ATTR_ID);
IValidatorType validatorType = ValidatorManager.getValidatorTypeFromID(id);
if (validatorType != null) {
// For each validator child node, populate the container with a
// subordinate node
NodeList validatorNodeList = validatorTypeElement.getChildNodes();
for (int i = 0; i < validatorNodeList.getLength(); ++i) {
Node childNode = validatorNodeList.item(i);
short type = childNode.getNodeType();
if (type == Node.ELEMENT_NODE) {
Element validatorElement = (Element) childNode;
if (validatorElement.getNodeName().equalsIgnoreCase(NODE_VALIDATOR)) {
populateValidator(validatorType, validatorElement);
}
}
}
} else {
final String msg = ValidatorMessages.ValidatorDefinitionsContainer_unknownValidatorType;
ValidatorsCore.warn(NLS.bind(msg, id));
}
}
/**
* Parse the specified Interpreter node, create a InterpreterStandin for it,
* and add this to the specified container.
*/
private void populateValidator(IValidatorType type, Element element) {
String id = element.getAttribute(ATTR_ID);
if (id != null) {
try {
final IValidator validator;
if (type.isBuiltin()) {
validator = type.findValidator(id);
} else {
validator = type.createValidator(id);
}
if (validator != null) {
if (type.isConfigurable()) {
validator.loadFrom(element);
}
addValidator(validator);
}
} catch (DOMException e) {
final String msg = ValidatorMessages.ValidatorDefinitionsContainer_failedToLoadValidatorFromXml;
ValidatorsCore.error(msg, e);
}
} else {
if (DLTKCore.DEBUG) {
System.err.println("id attribute missing from validator element specification."); //$NON-NLS-1$
}
}
}
/**
* Removes the specified {@link IValidator} from this container.
*
* @param validator
* validator instance
*/
public void removeValidator(IValidator validator) {
fValidatorList.remove(validator);
List<IValidator> list = fValidatorsByType.get(validator.getValidatorType());
if (list != null) {
list.remove(validator);
}
}
}