blob: 3a4975e7ae3036656464566685dd0c3d6375b68b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 IBM Corporation 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.validation.internal;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IContributor;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.validation.MessageSeveritySetting;
import org.eclipse.wst.validation.Validator;
import org.eclipse.wst.validation.Validator.V2;
import org.eclipse.wst.validation.internal.model.FilterGroup;
import org.eclipse.wst.validation.internal.model.FilterRule;
import org.eclipse.wst.validation.internal.plugin.ValidationPlugin;
/**
* Process the validator (version 2) extension point.
*
* @author karasiuk
*
*/
public class ValidatorExtensionReader {
private static ValidatorExtensionReader _me;
public static ValidatorExtensionReader getDefault(){
if (_me == null)_me = new ValidatorExtensionReader();
return _me;
}
private ValidatorExtensionReader(){}
/**
* Read the extensions.
*/
Collection<Validator> process() {
Map<String,Validator> map = new HashMap<String, Validator>(100);
IExtensionPoint extensionPoint = getExtensionPoint();
if (extensionPoint == null)return map.values();
for (IExtension ext : extensionPoint.getExtensions()){
for (IConfigurationElement validator : ext.getConfigurationElements()){
Validator v = processValidator(validator, ext.getUniqueIdentifier(), ext.getLabel(), null);
if (v != null)map.put(v.getId(),v);
}
}
extensionPoint = getExtensionPointExclude();
if (extensionPoint != null){
for (IExtension ext : extensionPoint.getExtensions()){
for (IConfigurationElement validator : ext.getConfigurationElements()){
String id = validator.getAttribute(ExtensionConstants.Exclude.id);
Validator v = map.get(id);
V2 v2 = null;
if (v != null)v2 = v.asV2Validator();
if (v2 == null){
String msg = NLS.bind("Plug-in configuration error, extension {0} references validator id {1} but this id does not exist.", //$NON-NLS-1$
extensionPoint.getUniqueIdentifier(), id);
CoreException ex = new CoreException(new Status(IStatus.ERROR, ValidationPlugin.PLUGIN_ID, msg));
ValidationPlugin.getPlugin().handleException(ex);
}
else {
for (IConfigurationElement exclude : validator.getChildren()){
FilterGroup fg = createFilterGroup(exclude);
if (fg != null && fg.isExclude()){
mergeExcludeGroup(v2, fg);
}
}
}
}
}
}
return map.values();
}
/**
* Merge the rules from the filter group into the current exclude group, creating a current exclude
* group if need be.
* @param v2
* @param fg
*/
private void mergeExcludeGroup(V2 v2, FilterGroup fg){
FilterGroup existing = null;
for (FilterGroup group : v2.getGroups()){
if (group.isExclude()){
existing = group;
break;
}
}
if (existing == null)v2.add(fg);
else {
for (FilterRule rule : fg.getRules()){
existing.add(rule);
}
v2.bumpChangeCountGroups();
}
}
/**
* Process the validator element in a validator extension.
*
* @param validator
* The validator element.
*
* @param deep
* If true load all the configuration elements for each
* validator, if false do a shallow load, where only the
* validator class, id and name's are loaded.
*
* @param project
* The project that you are defined in. This can be null which
* means that you are a global validator.
*
* @return a configured validator or null if there was an error.
*/
private Validator processValidator(IConfigurationElement validator, String id, String label, IProject project) {
Validator.V2 v = null;
try {
v = Validator.create(validator, project).asV2Validator();
v.setLevel(Validator.Level.Extension);
v.setId(id);
v.setName(label);
v.setBuildValidation(getAttribute(validator, ExtensionConstants.build, true));
v.setManualValidation(getAttribute(validator, ExtensionConstants.manual, true));
v.setMarkerId(validator.getAttribute(ExtensionConstants.markerId));
v.setVersion(getAttribute(validator, ExtensionConstants.version, 1));
v.setSourceId(validator.getAttribute(ExtensionConstants.sourceId));
IConfigurationElement[] children = validator.getChildren();
for (IConfigurationElement child : children)processIncludeAndExcludeElement(v, child);
}
catch (Exception e){
ValidationPlugin.getPlugin().handleException(e);
IContributor contrib = validator.getContributor();
String message = NLS.bind(ValMessages.ErrConfig, contrib.getName());
ValidationPlugin.getPlugin().logMessage(IStatus.ERROR, message);
}
return v;
}
/**
* Answer all the messages that this validator has defined.
* @param v
* @return an empty list if the validator did not define any messages.
*/
public List<MessageSeveritySetting> addMessages(Validator v){
List<MessageSeveritySetting> list = new LinkedList<MessageSeveritySetting>();
IExtensionPoint extensionPoint = getExtensionPoint();
if (extensionPoint == null)return list;
IExtension ext = extensionPoint.getExtension(v.getId());
if (ext == null)return list;
for (IConfigurationElement elem : ext.getConfigurationElements()){
for (IConfigurationElement ce : elem.getChildren(ExtensionConstants.MessageCategory.name)){
list.add(processMessage(ce));
}
}
return list;
}
/**
* Answer the extension point for the validators.
*
* @return null if there is a problem or no extensions.
*/
private IExtensionPoint getExtensionPoint() {
IExtensionRegistry registry = Platform.getExtensionRegistry();
return registry.getExtensionPoint(ValidationPlugin.PLUGIN_ID, ExtensionConstants.validator);
}
/**
* Answer the extension point for adding exclusion filters.
*
* @return null if there is a problem or no extensions.
*/
private IExtensionPoint getExtensionPointExclude() {
IExtensionRegistry registry = Platform.getExtensionRegistry();
return registry.getExtensionPoint(ValidationPlugin.PLUGIN_ID, ExtensionConstants.excludeExtension);
}
/**
* Process a message element for the validator, by creating a MessageCategory for it.
*
* @param ce a MessageCategory element.
*/
private MessageSeveritySetting processMessage(IConfigurationElement ce) {
String s = ce.getAttribute(ExtensionConstants.MessageCategory.severity);
MessageSeveritySetting.Severity sev = null;
if (ExtensionConstants.MessageCategory.sevError.equals(s))sev = MessageSeveritySetting.Severity.Error;
else if (ExtensionConstants.MessageCategory.sevWarning.equals(s))sev = MessageSeveritySetting.Severity.Warning;
else if (ExtensionConstants.MessageCategory.sevIgnore.equals(s))sev = MessageSeveritySetting.Severity.Ignore;
return new MessageSeveritySetting(ce.getAttribute(ExtensionConstants.MessageCategory.id),
ce.getAttribute(ExtensionConstants.MessageCategory.label), sev);
}
/**
* Process the include and exclude elements.
*
* @param v The validator that we are building up.
* @param group The children of the validator tag. This may included include and exclude elements.
* Other elements are ignored.
*/
private void processIncludeAndExcludeElement(Validator.V2 v, IConfigurationElement group) {
FilterGroup fg = createFilterGroup(group);
if (fg != null)v.add(fg);
}
/**
* Process an include or exclude element, returning a filter group for it.
*
* @param group
* An include, exclude or some other element. Only include and
* exclude elements are processed, other types are ignored.
*
* @return a filter group that corresponds to the include or exclude
* element, or null if the element was not an include or exclude
* element.
*/
private FilterGroup createFilterGroup(IConfigurationElement group){
FilterGroup fg = FilterGroup.create(group.getName());
if (fg == null)return null;
IConfigurationElement[] rules = group.getChildren(ExtensionConstants.rules);
// there should only be one
for (int i=0; i<rules.length; i++){
IConfigurationElement[] r = rules[i].getChildren();
for(int j=0; j<r.length; j++){
processRule(fg, r[j]);
}
}
return fg;
}
/**
* Process a rule in one of the rule groups.
*
* @param fg the filter group that we are building up
* @param rule a rule in the group, like fileext.
*/
private void processRule(FilterGroup fg, IConfigurationElement rule) {
FilterRule fr = FilterRule.create(rule.getName());
if (fr == null)throw new IllegalStateException(ValMessages.ErrFilterRule);
fr.setData(rule);
fg.add(fr);
}
/**
* Determine if any of the validators need to be migrated, and if so answer a new
* Validator array.
*
* @param validators the existing validators (from the preferences).
*
* @return null if no validators needed to be migrated.
*/
Validator[] migrate(Validator[] validators, IProject project) {
int count = 0;
Map<String, Validator> map = new HashMap<String, Validator>(validators.length);
for (Validator v : validators)map.put(v.getId(), v);
IExtensionPoint extensionPoint = getExtensionPoint();
if (extensionPoint == null)return null;
for (IExtension ext : extensionPoint.getExtensions()){
for (IConfigurationElement validator : ext.getConfigurationElements()){
Validator v = processValidator(validator, ext.getUniqueIdentifier(), ext.getLabel(), project);
if (v == null)continue;
Validator old = map.get(v.getId());
if (old == null || old.getVersion() < v.getVersion()){
//TODO we may be replacing user preferences, at some point we may want to do a real migration.
map.put(v.getId(), v);
count++;
}
}
}
if (count > 0){
Validator[] vals = new Validator[map.size()];
map.values().toArray(vals);
return vals;
}
return null;
}
private boolean getAttribute(IConfigurationElement element, String name, boolean dft){
String v = element.getAttribute(name);
if (v == null)return dft;
if ("true".equalsIgnoreCase(v))return true; //$NON-NLS-1$
if ("false".equalsIgnoreCase(v))return false; //$NON-NLS-1$
return dft;
}
private int getAttribute(IConfigurationElement element, String name, int dft){
String v = element.getAttribute(name);
if (v == null)return dft;
try {
return Integer.parseInt(v);
}
catch (Exception e){
// eat it.
}
return dft;
}
// /**
// * This method is only used for debugging.
// * @param elem
// */
// private static void dump(IConfigurationElement elem){
// String name = elem.getName();
// String[] attribs = elem.getAttributeNames();
// String[] vals = new String[attribs.length];
// for (int i=0; i<vals.length; i++)vals[i] = elem.getAttribute(attribs[i]);
// String v = elem.getValue();
// IConfigurationElement[] children = elem.getChildren();
// for (int i=0; i<children.length; i++)dump(children[i]);
// }
}