blob: fff5db79799696149cba1b99c1cf0d0291da7025 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2013 Tasktop Technologies 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:
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.bugzilla.core;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* Quick config rdf parser.
*
* <pre>
* config.cgi?ctype=rdf
* </pre>
*
* Populates a <link>RepositoryConfiguration</link> data structure.
*
* @author Rob Elves
*/
public class SaxConfigurationContentHandler extends DefaultHandler {
private static final String ELEMENT_RESOLUTION = "resolution"; //$NON-NLS-1$
private static final String ELEMENT_STATUS_OPEN = "status_open"; //$NON-NLS-1$
private static final String ELEMENT_STATUS_CLOSED = "status_closed"; //$NON-NLS-1$
private static final String ELEMENT_TARGET_MILESTONE = "target_milestone"; //$NON-NLS-1$
private static final String ELEMENT_TARGET_MILESTONES = "target_milestones"; //$NON-NLS-1$
private static final String ELEMENT_INSTALL_VERSION = "install_version"; //$NON-NLS-1$
private static final String ELEMENT_DB_ENCODING = "db_encoding"; //$NON-NLS-1$
private static final String ATTRIBUTE_RDF_ABOUT = "rdf:about"; //$NON-NLS-1$
private static final String ATTRIBUTE_RESOURCE = "resource"; //$NON-NLS-1$
private static final String ELEMENT_VERSION = "version"; //$NON-NLS-1$
private static final String ELEMENT_VERSIONS = "versions"; //$NON-NLS-1$
private static final String ELEMENT_COMPONENT = "component"; //$NON-NLS-1$
private static final String ELEMENT_COMPONENTS = "components"; //$NON-NLS-1$
private static final String ELEMENT_NAME = "name"; //$NON-NLS-1$
private static final String ELEMENT_PRODUCTS = "products"; //$NON-NLS-1$
private static final String ELEMENT_DESCRIPTION = "description"; //$NON-NLS-1$
private static final String ELEMENT_FIELDS = "fields"; //$NON-NLS-1$
private static final String ELEMENT_FIELD = "field"; //$NON-NLS-1$
private static final String ELEMENT_FLAG_TYPES = "flag_types"; //$NON-NLS-1$
private static final String ELEMENT_FLAG_TYPE = "flag_type"; //$NON-NLS-1$
private static final String ELEMENT_SEVERITY = "severity"; //$NON-NLS-1$
private static final String ELEMENT_PRIORITY = "priority"; //$NON-NLS-1$
private static final String ELEMENT_KEYWORD = "keyword"; //$NON-NLS-1$
private static final String ELEMENT_KEYWORDS = "keywords"; //$NON-NLS-1$
private static final String ELEMENT_OP_SYS = "op_sys"; //$NON-NLS-1$
private static final String ELEMENT_PLATFORM = "platform"; //$NON-NLS-1$
private static final String ELEMENT_LI = "li"; //$NON-NLS-1$
private static final String ELEMENT_STATUS = "status"; //$NON-NLS-1$
private static final String ELEMENT_TYPE = "type"; //$NON-NLS-1$
private static final String ELEMENT_ENTER_BUG = "enter_bug"; //$NON-NLS-1$
private static final String ELEMENT_REQUESTABLE = "requestable"; //$NON-NLS-1$
private static final String ELEMENT_SPECIFICALLY_REQUESTABLE = "specifically_requestable"; //$NON-NLS-1$
private static final String ELEMENT_ID = "id"; //$NON-NLS-1$
private static final String ELEMENT_MULTIPLICABLE = "multiplicable"; //$NON-NLS-1$
private static final String ELEMENT_ALLOWS_UNCONFIRMED = "allows_unconfirmed"; //$NON-NLS-1$
private static final int EXPECTING_ROOT = 0;
private static final int IN_INSTALL_VERSION = 1 << 1;
private static final int IN_STATUS = 1 << 2;
private static final int IN_PLATFORM = 1 << 3;
private static final int IN_OP_SYS = 1 << 4;
private static final int IN_PRIORITY = 1 << 5;
private static final int IN_SEVERITY = 1 << 6;
private static final int IN_PRODUCTS = 1 << 7;
private static final int IN_COMPONENTS = 1 << 8;
private static final int IN_VERSIONS = 1 << 9;
private static final int IN_LI = 1 << 10;
private static final int IN_LI_LI = 1 << 11;
private static final int IN_NAME = 1 << 12;
private static final int IN_COMPONENT = 1 << 13;
private static final int IN_VERSION = 1 << 14;
private static final int IN_TARGET_MILESTONES = 1 << 15;
private static final int IN_TARGET_MILESTONE = 1 << 16;
private static final int IN_STATUS_OPEN = 1 << 17;
private static final int IN_RESOLUTION = 1 << 18;
private static final int IN_KEYWORD = 1 << 19;
private static final int IN_STATUS_CLOSED = 1 << 20;
private static final int IN_FIELDS = 1 << 21;
private static final int IN_FIELD = 1 << 22;
private static final int IN_CUSTOM_OPTION = 1 << 23;
private static final int IN_FLAG_TYPES = 1 << 24;
private static final int IN_FLAG_TYPE = 1 << 25;
private static final int IN_DB_ENCODING = 1 << 26;
private static final int IN_KEYWORDS = 1 << 27;
private int state = EXPECTING_ROOT;
private String currentProduct = ""; //$NON-NLS-1$
private String currentName = ""; //$NON-NLS-1$
private String currentDescription = ""; //$NON-NLS-1$
private String currentType;
private String currentRequestable;
private String currentSpecifically_requestable;
private String currentMultiplicable;
private int currentId;
private String currentEnterBug = ""; //$NON-NLS-1$
private StringBuffer characters = new StringBuffer();
private String about;
private final RepositoryConfiguration configuration;
private final Map<String, List<String>> components = new HashMap<String, List<String>>();
private final Map<String, List<String>> versions = new HashMap<String, List<String>>();
private final Map<String, List<String>> milestones = new HashMap<String, List<String>>();
private final Map<String, String> componentNames = new HashMap<String, String>();
private final Map<String, String> versionNames = new HashMap<String, String>();
private final Map<String, String> milestoneNames = new HashMap<String, String>();
private final Map<String, List<String>> customOption = new HashMap<String, List<String>>();
private final Map<String, Map<String, List<String>>> flagsInComponent = new HashMap<String, Map<String, List<String>>>();
private final Map<String, Integer> flagIds = new HashMap<String, Integer>();
private String currentComponent = ""; //$NON-NLS-1$
private String currentCustomOptionName = ""; //$NON-NLS-1$
public SaxConfigurationContentHandler() {
configuration = new RepositoryConfiguration();
}
public RepositoryConfiguration getConfiguration() {
return configuration;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
characters.append(ch, start, length);
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
characters = new StringBuffer();
if (localName.equals(ELEMENT_STATUS)) {
state = state | IN_STATUS;
} else if (localName.equals(ELEMENT_LI) && ((state & IN_LI) == IN_LI)) {
state = state | IN_LI_LI;
parseResource(attributes);
} else if (localName.equals(ELEMENT_LI) && ((state & IN_LI) != IN_LI)) {
state = state | IN_LI;
} else if (localName.equals(ELEMENT_PLATFORM)) {
state = state | IN_PLATFORM;
} else if (localName.equals(ELEMENT_OP_SYS)) {
state = state | IN_OP_SYS;
} else if (localName.equals(ELEMENT_PRIORITY)) {
state = state | IN_PRIORITY;
} else if (localName.equals(ELEMENT_SEVERITY)) {
state = state | IN_SEVERITY;
} else if (localName.equals(ELEMENT_PRODUCTS)) {
state = state | IN_PRODUCTS;
} else if (localName.equals(ELEMENT_OP_SYS)) {
state = state | IN_OP_SYS;
} else if (localName.equals(ELEMENT_NAME)) {
state = state | IN_NAME;
} else if (localName.equals(ELEMENT_COMPONENTS)) {
state = state | IN_COMPONENTS;
} else if (localName.equals(ELEMENT_COMPONENT)) {
state = state | IN_COMPONENT;
parseResource(attributes);
} else if (localName.equals(ELEMENT_VERSIONS)) {
state = state | IN_VERSIONS;
} else if (localName.equals(ELEMENT_VERSION)) {
state = state | IN_VERSION;
parseResource(attributes);
} else if (localName.equals(ELEMENT_INSTALL_VERSION)) {
state = state | IN_INSTALL_VERSION;
} else if (localName.equals(ELEMENT_DB_ENCODING)) {
state = state | IN_DB_ENCODING;
} else if (localName.equals(ELEMENT_TARGET_MILESTONES)) {
state = state | IN_TARGET_MILESTONES;
} else if (localName.equals(ELEMENT_TARGET_MILESTONE)) {
state = state | IN_TARGET_MILESTONE;
parseResource(attributes);
} else if (localName.equals(ELEMENT_STATUS_OPEN)) {
state = state | IN_STATUS_OPEN;
} else if (localName.equals(ELEMENT_STATUS_CLOSED)) {
state = state | IN_STATUS_CLOSED;
} else if (localName.equals(ELEMENT_RESOLUTION)) {
state = state | IN_RESOLUTION;
} else if (localName.equals(ELEMENT_KEYWORD)) {
state = state | IN_KEYWORD;
} else if (localName.equals(ELEMENT_KEYWORDS)) {
state = state | IN_KEYWORDS;
} else if (localName.equals(ELEMENT_FIELDS)) {
state = state | IN_FIELDS;
} else if (localName.equals(ELEMENT_FIELD)) {
state = state | IN_FIELD;
parseResource(attributes);
currentName = ""; //$NON-NLS-1$
currentDescription = ""; //$NON-NLS-1$
currentType = ""; //$NON-NLS-1$
currentEnterBug = ""; //$NON-NLS-1$
currentId = -1;
} else if (localName.equals(ELEMENT_FLAG_TYPES)) {
state = state | IN_FLAG_TYPES;
} else if (localName.equals(ELEMENT_FLAG_TYPE)) {
state = state | IN_FLAG_TYPE;
parseResource(attributes);
} else if (localName.startsWith(BugzillaCustomField.CUSTOM_FIELD_PREFIX)) {
state = state | IN_CUSTOM_OPTION;
currentCustomOptionName = localName;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// KEEP: && ((state & IN_LI) == IN_LI)
if (localName.equals(ELEMENT_STATUS)) {
state = state & ~IN_STATUS;
} else if (localName.equals(ELEMENT_LI) && ((state & IN_LI_LI) == IN_LI_LI)) {
state = state & ~IN_LI_LI;
} else if (localName.equals(ELEMENT_LI) && ((state & IN_LI_LI) != IN_LI_LI)) {
state = state & ~IN_LI;
if (characters.length() == 0) {
return;
}
if (state == (IN_STATUS)) {
configuration.addItem(BugzillaAttribute.BUG_STATUS, characters.toString());
} else if (state == (IN_STATUS_OPEN)) {
configuration.addOpenStatusValue(characters.toString());
} else if (state == (IN_STATUS_CLOSED)) {
configuration.addClosedStatusValue(characters.toString());
} else if (state == (IN_RESOLUTION)) {
configuration.addItem(BugzillaAttribute.RESOLUTION, characters.toString());
} else if (state == (IN_KEYWORD)) {
configuration.addItem(BugzillaAttribute.KEYWORDS, characters.toString());
} else if (state == (IN_PLATFORM)) {
configuration.addItem(BugzillaAttribute.REP_PLATFORM, characters.toString());
} else if (state == (IN_OP_SYS)) {
configuration.addItem(BugzillaAttribute.OP_SYS, characters.toString());
} else if (state == (IN_PRIORITY)) {
configuration.addItem(BugzillaAttribute.PRIORITY, characters.toString());
} else if (state == (IN_SEVERITY)) {
configuration.addItem(BugzillaAttribute.BUG_SEVERITY, characters.toString());
} else if (state == (IN_CUSTOM_OPTION)) {
// Option for CutstomFields
if (currentCustomOptionName != null) {
if (characters.length() > 0) {
List<String> customOptionList = customOption.get(currentCustomOptionName);
if (customOptionList == null) {
customOptionList = new ArrayList<String>();
customOption.put(currentCustomOptionName, customOptionList);
}
customOptionList.add(characters.toString());
}
}
}
} else if (localName.equals(ELEMENT_PLATFORM)) {
state = state & ~IN_PLATFORM;
} else if (localName.equals(ELEMENT_OP_SYS)) {
state = state & ~IN_OP_SYS;
} else if (localName.equals(ELEMENT_PRIORITY)) {
state = state & ~IN_PRIORITY;
} else if (localName.equals(ELEMENT_SEVERITY)) {
state = state & ~IN_SEVERITY;
} else if (localName.equals(ELEMENT_PRODUCTS)) {
state = state & ~IN_PRODUCTS;
} else if (localName.equals(ELEMENT_OP_SYS)) {
state = state & ~IN_OP_SYS;
} else if (localName.equals(ELEMENT_NAME)) {
state = state & ~IN_NAME;
if (state == (IN_PRODUCTS | IN_LI)) {
// PRODUCT NAME
currentProduct = characters.toString();
configuration.addProduct(currentProduct);
} else if (state == (IN_VERSIONS | IN_LI | IN_VERSION)) {
// VERSION NAME
if (about != null && !versionNames.containsValue(about)) {
if (characters.length() > 0) {
versionNames.put(about, characters.toString());
}
}
} else if (state == (IN_COMPONENTS | IN_LI | IN_COMPONENT)) {
// COMPONENT NAME
currentComponent = characters.toString();
if (about != null && !componentNames.containsValue(about)) {
if (currentComponent.length() > 0) {
componentNames.put(about, currentComponent);
}
}
} else if (state == (IN_TARGET_MILESTONES | IN_LI | IN_TARGET_MILESTONE)) {
// MILESTONE NAME
if (about != null && !milestoneNames.containsValue(about)) {
if (characters.length() > 0) {
milestoneNames.put(about, characters.toString());
}
}
} else if (state == (IN_KEYWORDS | IN_LI | IN_KEYWORD)) {
// KEYWORD NAME
currentName = characters.toString();
} else if (state == (IN_FIELDS | IN_LI | IN_FIELD) || state == (IN_FLAG_TYPES | IN_LI | IN_FLAG_TYPE)) {
// FIELDS NAME
currentName = characters.toString();
}
} else if (localName.equals(ELEMENT_COMPONENTS)) {
state = state & ~IN_COMPONENTS;
} else if (localName.equals(ELEMENT_COMPONENT)) {
state = state & ~IN_COMPONENT;
} else if (localName.equals(ELEMENT_VERSION)) {
state = state & ~IN_VERSION;
} else if (localName.equals(ELEMENT_VERSIONS)) {
state = state & ~IN_VERSIONS;
} else if (localName.equals(ELEMENT_INSTALL_VERSION)) {
state = state & ~IN_INSTALL_VERSION;
configuration.setInstallVersion(characters.toString());
} else if (localName.equals(ELEMENT_DB_ENCODING)) {
state = state & ~IN_DB_ENCODING;
String charsetString = characters.toString().trim();
if (charsetString.length() > 0) {
try {
Charset.forName(charsetString);
configuration.setEncoding(charsetString);
} catch (Exception e) {
StatusHandler.log(new Status(IStatus.WARNING, BugzillaCorePlugin.ID_PLUGIN,
"Unrecognized encoding in configuration: " + charsetString)); //$NON-NLS-1$
}
}
} else if (localName.equals(ELEMENT_TARGET_MILESTONE)) {
state = state & ~IN_TARGET_MILESTONE;
} else if (localName.equals(ELEMENT_TARGET_MILESTONES)) {
state = state & ~IN_TARGET_MILESTONES;
} else if (localName.equals(ELEMENT_STATUS_OPEN)) {
state = state & ~IN_STATUS_OPEN;
} else if (localName.equals(ELEMENT_STATUS_CLOSED)) {
state = state & ~IN_STATUS_CLOSED;
} else if (localName.equals(ELEMENT_RESOLUTION)) {
state = state & ~IN_RESOLUTION;
} else if (localName.equals(ELEMENT_KEYWORD)) {
if (state == (IN_KEYWORDS | IN_LI | IN_KEYWORD)) {
configuration.addItem(BugzillaAttribute.KEYWORDS, currentName);
}
state = state & ~IN_KEYWORD;
} else if (localName.equals(ELEMENT_KEYWORDS)) {
state = state & ~IN_KEYWORDS;
} else if (localName.equals(ELEMENT_FIELDS)) {
state = state & ~IN_FIELDS;
} else if (localName.equals(ELEMENT_FIELD)) {
if (currentName.startsWith(BugzillaCustomField.CUSTOM_FIELD_PREFIX)) {
BugzillaCustomField newField = new BugzillaCustomField(currentDescription, currentName, currentType,
currentEnterBug);
List<String> customOptionList = customOption.get(currentName);
if (customOptionList != null && !customOptionList.isEmpty()) {
newField.setOptions(customOptionList);
}
configuration.addCustomField(newField);
}
state = state & ~IN_FIELD;
} else if (localName.equals(ELEMENT_DESCRIPTION)) {
currentDescription = characters.toString();
} else if (localName.equals(ELEMENT_TYPE)) {
currentType = characters.toString();
} else if (localName.equals(ELEMENT_ID)) {
currentId = Integer.parseInt(characters.toString());
} else if (localName.equals(ELEMENT_ENTER_BUG)) {
currentEnterBug = characters.toString();
} else if (localName.equals(ELEMENT_REQUESTABLE)) {
currentRequestable = characters.toString();
} else if (localName.equals(ELEMENT_SPECIFICALLY_REQUESTABLE)) {
currentSpecifically_requestable = characters.toString();
} else if (localName.equals(ELEMENT_MULTIPLICABLE)) {
currentMultiplicable = characters.toString();
} else if (localName.equals(ELEMENT_FLAG_TYPES)) {
state = state & ~IN_FLAG_TYPES;
} else if (localName.equals(ELEMENT_FLAG_TYPE)) {
if (currentId != -1) {
if (about != null && !flagIds.containsValue(currentId)) {
flagIds.put(about, currentId);
}
BugzillaFlag newFlag = new BugzillaFlag(currentName, currentDescription, currentType,
currentRequestable, currentSpecifically_requestable, currentMultiplicable, currentId);
configuration.addFlag(newFlag);
}
state = state & ~IN_FLAG_TYPE;
} else if (localName.startsWith(BugzillaCustomField.CUSTOM_FIELD_PREFIX)) {
state = state & ~IN_CUSTOM_OPTION;
currentCustomOptionName = ""; //$NON-NLS-1$
} else if (localName.equals(ELEMENT_ALLOWS_UNCONFIRMED)) {
String value = characters.toString();
Boolean boolValue = value.equals("0") ? false : true; //$NON-NLS-1$
configuration.addUnconfirmedAllowed(currentProduct, boolValue);
}
}
private void parseResource(Attributes attributes) {
switch (state) {
case IN_PRODUCTS | IN_LI | IN_COMPONENTS | IN_LI_LI:
if (attributes != null) {
String compURI = attributes.getValue(ATTRIBUTE_RESOURCE);
if (compURI != null && currentProduct.length() > 0) {
List<String> compURIs = components.get(currentProduct);
if (compURIs == null) {
compURIs = new ArrayList<String>();
components.put(currentProduct, compURIs);
}
compURIs.add(compURI);
}
}
break;
case IN_PRODUCTS | IN_LI | IN_VERSIONS | IN_LI_LI:
if (attributes != null) {
String resourceURI = attributes.getValue(ATTRIBUTE_RESOURCE);
if (resourceURI != null && currentProduct.length() > 0) {
List<String> versionUris = versions.get(currentProduct);
if (versionUris == null) {
versionUris = new ArrayList<String>();
versions.put(currentProduct, versionUris);
}
versionUris.add(resourceURI);
}
}
break;
case IN_PRODUCTS | IN_LI | IN_TARGET_MILESTONES | IN_LI_LI:
if (attributes != null) {
String resourceURI = attributes.getValue(ATTRIBUTE_RESOURCE);
if (resourceURI != null) {
List<String> milestoneUris = milestones.get(currentProduct);
if (milestoneUris == null) {
milestoneUris = new ArrayList<String>();
milestones.put(currentProduct, milestoneUris);
}
milestoneUris.add(resourceURI);
}
}
break;
case IN_COMPONENTS | IN_LI | IN_COMPONENT | IN_FLAG_TYPES | IN_LI_LI:
if (attributes != null) {
String compURI = attributes.getValue(ATTRIBUTE_RESOURCE);
if (compURI != null && currentComponent.length() > 0 && currentProduct.length() > 0
&& compURI.length() > 0) {
Map<String, List<String>> flagComponentList = flagsInComponent.get(currentProduct);
if (flagComponentList == null) {
flagComponentList = new HashMap<String, List<String>>();
flagsInComponent.put(currentProduct, flagComponentList);
}
List<String> flagsForComponent = flagComponentList.get(currentComponent);
if (flagsForComponent == null) {
flagsForComponent = new ArrayList<String>();
flagComponentList.put(currentComponent, flagsForComponent);
}
flagsForComponent.add(compURI.replace("flags.cgi?id=", "flag.cgi?id=")); //$NON-NLS-1$ //$NON-NLS-2$
}
}
break;
case IN_COMPONENTS | IN_LI | IN_COMPONENT:
if (attributes != null) {
about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
int idx = about.indexOf("&product="); //$NON-NLS-1$
if (idx != -1) {
currentProduct = about.substring(idx + 9);
currentProduct = currentProduct.replaceAll("%20", " "); //$NON-NLS-1$ //$NON-NLS-2$
}
}
break;
case IN_VERSIONS | IN_LI | IN_VERSION:
if (attributes != null) {
about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
}
break;
case IN_TARGET_MILESTONES | IN_LI | IN_TARGET_MILESTONE:
if (attributes != null) {
about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
}
break;
case IN_FIELDS | IN_LI | IN_FIELD:
if (attributes != null) {
about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
}
break;
case IN_FLAG_TYPES | IN_LI | IN_FLAG_TYPE:
if (attributes != null) {
about = attributes.getValue(ATTRIBUTE_RDF_ABOUT);
}
break;
}
}
@Override
public void endDocument() throws SAXException {
for (String product : components.keySet()) {
List<String> componentURIs = components.get(product);
for (String uri : componentURIs) {
String realName = componentNames.get(uri);
if (realName != null) {
configuration.addItem2ProductConfiguration(BugzillaAttribute.COMPONENT, product, realName);
}
}
}
for (String product : versions.keySet()) {
List<String> versionURIs = versions.get(product);
for (String uri : versionURIs) {
String realName = versionNames.get(uri);
if (realName != null) {
configuration.addItem2ProductConfiguration(BugzillaAttribute.VERSION, product, realName);
}
}
}
for (String product : milestones.keySet()) {
List<String> milestoneURIs = milestones.get(product);
for (String uri : milestoneURIs) {
String realName = milestoneNames.get(uri);
if (realName != null) {
configuration.addItem2ProductConfiguration(BugzillaAttribute.TARGET_MILESTONE, product, realName);
}
}
}
for (String flagProduct : flagsInComponent.keySet()) {
Map<String, List<String>> flagComponentUsage = flagsInComponent.get(flagProduct);
for (String flagusageList : flagComponentUsage.keySet()) {
List<String> flagList = flagComponentUsage.get(flagusageList);
for (String flagAbout : flagList) {
Integer flagId = flagIds.get(flagAbout);
BugzillaFlag flag = configuration.getFlagWithId(flagId);
flag.addUsed(flagProduct, flagusageList);
}
}
}
super.endDocument();
}
}