blob: 47c2de70a7f0bd8f0b2f939753524229c64f8040 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 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
* Red Hat Inc. - 378338: Support for "bundle" element
*******************************************************************************/
package org.eclipse.equinox.internal.p2.updatesite;
import java.io.*;
import java.net.URI;
import java.util.*;
import javax.xml.parsers.*;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.core.helpers.*;
import org.eclipse.equinox.p2.publisher.eclipse.URLEntry;
import org.eclipse.osgi.util.NLS;
import org.w3c.dom.*;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
/**
* Parses a site.xml file.
* This class was initially copied from org.eclipse.update.core.model.DefaultSiteParser.
*/
public class DefaultSiteParser extends DefaultHandler {
private static final String ARCHIVE = "archive"; //$NON-NLS-1$
private static final String CATEGORY = "category"; //$NON-NLS-1$
private static final String CATEGORY_DEF = "category-def"; //$NON-NLS-1$
private static final String ASSOCIATE_SITES_URL = "associateSitesURL"; //$NON-NLS-1$
private static final String ASSOCIATE_SITE = "associateSite"; //$NON-NLS-1$
private static final String DEFAULT_INFO_URL = "index.html"; //$NON-NLS-1$
private static final String DESCRIPTION = "description"; //$NON-NLS-1$
private static final String FEATURE = "feature"; //$NON-NLS-1$
private static final String BUNDLE = "bundle"; //$NON-NLS-1$
private static final String FEATURES = "features/"; //$NON-NLS-1$
private static final String PLUGINS = "plugins/"; //$NON-NLS-1$
private final static SAXParserFactory parserFactory = SecureXMLUtil.newSecureSAXParserFactory();
private static final String PLUGIN_ID = Activator.ID;
private static final String SITE = "site"; //$NON-NLS-1$
private static final int STATE_ARCHIVE = 3;
private static final int STATE_CATEGORY = 4;
private static final int STATE_CATEGORY_DEF = 5;
private static final int STATE_DESCRIPTION_CATEGORY_DEF = 7;
private static final int STATE_DESCRIPTION_SITE = 6;
private static final int STATE_FEATURE = 2;
private static final int STATE_BUNDLE = 8;
private static final int STATE_IGNORED_ELEMENT = -1;
private static final int STATE_INITIAL = 0;
private static final int STATE_SITE = 1;
private int currentState;
private boolean DESCRIPTION_SITE_ALREADY_SEEN = false;
// Current object stack (used to hold the current object we are
// populating in this plugin descriptor
Stack<Object> objectStack = new Stack<Object>();
private SAXParser parser;
// Current State Information
Stack<Integer> stateStack = new Stack<Integer>();
// List of string keys for translated strings
private final List<String> messageKeys = new ArrayList<String>(4);
private MultiStatus status;
private final URI siteLocation;
/*
*
*/
private static void debug(String s) {
Tracing.debug("DefaultSiteParser: " + s); //$NON-NLS-1$
}
private static URLEntry[] getAssociateSites(String associateSitesURL) {
try {
DocumentBuilderFactory domFactory = SecureXMLUtil.newSecureDocumentBuilderFactory();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document document = builder.parse(associateSitesURL);
if (document == null)
return null;
NodeList mirrorNodes = document.getElementsByTagName(ASSOCIATE_SITE);
URLEntry[] mirrors = new URLEntry[mirrorNodes.getLength()];
for (int i = 0; i < mirrorNodes.getLength(); i++) {
Element mirrorNode = (Element) mirrorNodes.item(i);
mirrors[i] = new URLEntry();
String infoURL = mirrorNode.getAttribute("url"); //$NON-NLS-1$
String label = mirrorNode.getAttribute("label"); //$NON-NLS-1$
mirrors[i].setURL(infoURL);
mirrors[i].setAnnotation(label);
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("Processed mirror: url:" + infoURL + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$
}
return mirrors;
} catch (Exception e) {
// log if absolute url
if (associateSitesURL != null && (associateSitesURL.startsWith("http://") //$NON-NLS-1$
|| associateSitesURL.startsWith("https://") //$NON-NLS-1$
|| associateSitesURL.startsWith("file://") //$NON-NLS-1$
|| associateSitesURL.startsWith("ftp://") //$NON-NLS-1$
|| associateSitesURL.startsWith("jar://"))) //$NON-NLS-1$
log(Messages.DefaultSiteParser_mirrors, e);
return null;
}
}
static void log(Exception e) {
LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Internal Error", e)); //$NON-NLS-1$
}
static void log(String message) {
LogHelper.log(new Status(IStatus.WARNING, Activator.ID, message, null));
}
static void log(String message, Exception e) {
LogHelper.log(new Status(IStatus.WARNING, Activator.ID, message, e));
}
/**
* Constructs a site parser.
*/
public DefaultSiteParser(URI siteLocation) {
super();
this.siteLocation = siteLocation;
stateStack = new Stack<Integer>();
objectStack = new Stack<Object>();
status = null;
DESCRIPTION_SITE_ALREADY_SEEN = false;
try {
parserFactory.setNamespaceAware(true);
this.parser = parserFactory.newSAXParser();
} catch (ParserConfigurationException e) {
log(e);
} catch (SAXException e) {
log(e);
}
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("Created"); //$NON-NLS-1$
}
/**
* Handle character text
* @see DefaultHandler#characters(char[], int, int)
* @since 2.0
*/
public void characters(char[] ch, int start, int length) {
String text = new String(ch, start, length);
//only push if description
int state = stateStack.peek().intValue();
if (state == STATE_DESCRIPTION_SITE || state == STATE_DESCRIPTION_CATEGORY_DEF)
objectStack.push(text);
}
/**
* Handle end of element tags
* @see DefaultHandler#endElement(String, String, String)
* @since 2.0
*/
public void endElement(String uri, String localName, String qName) {
String text = null;
URLEntry info = null;
int state = stateStack.peek().intValue();
switch (state) {
case STATE_IGNORED_ELEMENT :
case STATE_ARCHIVE :
case STATE_CATEGORY :
stateStack.pop();
break;
case STATE_INITIAL :
internalError(Messages.DefaultSiteParser_ParsingStackBackToInitialState);
break;
case STATE_SITE :
stateStack.pop();
if (objectStack.peek() instanceof String) {
text = (String) objectStack.pop();
SiteModel site = (SiteModel) objectStack.peek();
site.getDescription().setAnnotation(text);
}
//do not pop the object
break;
case STATE_FEATURE :
stateStack.pop();
objectStack.pop();
break;
case STATE_BUNDLE :
stateStack.pop();
objectStack.pop();
break;
case STATE_CATEGORY_DEF :
stateStack.pop();
if (objectStack.peek() instanceof String) {
text = (String) objectStack.pop();
SiteCategory category = (SiteCategory) objectStack.peek();
category.setDescription(text);
}
objectStack.pop();
break;
case STATE_DESCRIPTION_SITE :
stateStack.pop();
text = ""; //$NON-NLS-1$
while (objectStack.peek() instanceof String) {
// add text, preserving at most one space between text fragments
String newText = (String) objectStack.pop();
if (trailingSpace(newText) && !leadingSpace(text)) {
text = " " + text; //$NON-NLS-1$
}
text = newText.trim() + text;
if (leadingSpace(newText) && !leadingSpace(text)) {
text = " " + text; //$NON-NLS-1$
}
}
text = text.trim();
info = (URLEntry) objectStack.pop();
if (text != null)
info.setAnnotation(text);
SiteModel siteModel = (SiteModel) objectStack.peek();
// override description.
// do not raise error as previous description may be default one
// when parsing site tag
if (DESCRIPTION_SITE_ALREADY_SEEN)
debug(NLS.bind(Messages.DefaultSiteParser_ElementAlreadySet, (new String[] {getState(state)})));
siteModel.setDescription(info);
DESCRIPTION_SITE_ALREADY_SEEN = true;
break;
case STATE_DESCRIPTION_CATEGORY_DEF :
stateStack.pop();
text = ""; //$NON-NLS-1$
while (objectStack.peek() instanceof String) {
// add text, preserving at most one space between text fragments
String newText = (String) objectStack.pop();
if (trailingSpace(newText) && !leadingSpace(text)) {
text = " " + text; //$NON-NLS-1$
}
text = newText.trim() + text;
if (leadingSpace(newText) && !leadingSpace(text)) {
text = " " + text; //$NON-NLS-1$
}
}
text = text.trim();
info = (URLEntry) objectStack.pop();
if (text != null)
info.setAnnotation(text);
SiteCategory category = (SiteCategory) objectStack.peek();
if (category.getDescription() != null)
internalError(NLS.bind(Messages.DefaultSiteParser_ElementAlreadySet, (new String[] {getState(state), category.getLabel()})));
else {
checkTranslated(info.getAnnotation());
category.setDescription(info.getAnnotation());
}
break;
default :
internalError(NLS.bind(Messages.DefaultSiteParser_UnknownEndState, (new String[] {getState(state)})));
break;
}
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("End Element:" + uri + ":" + localName + ":" + qName);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
/*
* Handles an error state specified by the status. The collection of all logged status
* objects can be accessed using <code>getStatus()</code>.
*
* @param error a status detailing the error condition
*/
private void error(IStatus error) {
if (status == null) {
status = new MultiStatus(PLUGIN_ID, 0, Messages.DefaultSiteParser_ErrorParsingSite, null);
}
status.add(error);
if (Tracing.DEBUG_GENERATOR_PARSING)
LogHelper.log(error);
}
/**
* Handle errors
* @see DefaultHandler#error(SAXParseException)
* @since 2.0
*/
public void error(SAXParseException ex) {
logStatus(ex);
}
/**
* Handle fatal errors
* @see DefaultHandler#fatalError(SAXParseException)
* @exception SAXException
* @since 2.0
*/
public void fatalError(SAXParseException ex) throws SAXException {
logStatus(ex);
throw ex;
}
/*
* return the state as String
*/
private String getState(int state) {
switch (state) {
case STATE_IGNORED_ELEMENT :
return "Ignored"; //$NON-NLS-1$
case STATE_INITIAL :
return "Initial"; //$NON-NLS-1$
case STATE_SITE :
return "Site"; //$NON-NLS-1$
case STATE_FEATURE :
return "Feature"; //$NON-NLS-1$
case STATE_BUNDLE :
return "Bundle"; //$NON-NLS-1$
case STATE_ARCHIVE :
return "Archive"; //$NON-NLS-1$
case STATE_CATEGORY :
return "Category"; //$NON-NLS-1$
case STATE_CATEGORY_DEF :
return "Category Def"; //$NON-NLS-1$
case STATE_DESCRIPTION_CATEGORY_DEF :
return "Description / Category Def"; //$NON-NLS-1$
case STATE_DESCRIPTION_SITE :
return "Description / Site"; //$NON-NLS-1$
default :
return Messages.DefaultSiteParser_UnknownState;
}
}
/**
* Returns all status objects accumulated by the parser.
*
* @return multi-status containing accumulated status, or <code>null</code>.
* @since 2.0
*/
public MultiStatus getStatus() {
return status;
}
private void handleCategoryDefState(String elementName, Attributes attributes) {
if (elementName.equals(FEATURE)) {
stateStack.push(Integer.valueOf(STATE_FEATURE));
processFeature(attributes);
} else if (elementName.equals(BUNDLE)) {
stateStack.push(Integer.valueOf(STATE_BUNDLE));
processBundle(attributes);
} else if (elementName.equals(ARCHIVE)) {
stateStack.push(Integer.valueOf(STATE_ARCHIVE));
processArchive(attributes);
} else if (elementName.equals(CATEGORY_DEF)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY_DEF));
processCategoryDef(attributes);
} else if (elementName.equals(DESCRIPTION)) {
stateStack.push(Integer.valueOf(STATE_DESCRIPTION_CATEGORY_DEF));
processInfo(attributes);
} else
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)})));
}
private void handleCategoryState(String elementName, Attributes attributes) {
if (elementName.equals(DESCRIPTION)) {
stateStack.push(Integer.valueOf(STATE_DESCRIPTION_SITE));
processInfo(attributes);
} else if (elementName.equals(FEATURE)) {
stateStack.push(Integer.valueOf(STATE_FEATURE));
processFeature(attributes);
} else if (elementName.equals(BUNDLE)) {
stateStack.push(Integer.valueOf(STATE_BUNDLE));
processBundle(attributes);
} else if (elementName.equals(ARCHIVE)) {
stateStack.push(Integer.valueOf(STATE_ARCHIVE));
processArchive(attributes);
} else if (elementName.equals(CATEGORY_DEF)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY_DEF));
processCategoryDef(attributes);
} else if (elementName.equals(CATEGORY)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY));
processCategory(attributes);
} else
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)})));
}
private void handleFeatureState(String elementName, Attributes attributes) {
if (elementName.equals(DESCRIPTION)) {
stateStack.push(Integer.valueOf(STATE_DESCRIPTION_SITE));
processInfo(attributes);
} else if (elementName.equals(FEATURE)) {
stateStack.push(Integer.valueOf(STATE_FEATURE));
processFeature(attributes);
} else if (elementName.equals(ARCHIVE)) {
stateStack.push(Integer.valueOf(STATE_ARCHIVE));
processArchive(attributes);
} else if (elementName.equals(CATEGORY_DEF)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY_DEF));
processCategoryDef(attributes);
} else if (elementName.equals(CATEGORY)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY));
processCategory(attributes);
} else
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)})));
}
private void handleBundleState(String elementName, Attributes attributes) {
if (elementName.equals(DESCRIPTION)) {
stateStack.push(Integer.valueOf(STATE_DESCRIPTION_SITE));
processInfo(attributes);
} else if (elementName.equals(ARCHIVE)) {
stateStack.push(Integer.valueOf(STATE_ARCHIVE));
processArchive(attributes);
} else if (elementName.equals(CATEGORY_DEF)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY_DEF));
processCategoryDef(attributes);
} else if (elementName.equals(CATEGORY)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY));
processCategory(attributes);
} else
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)})));
}
private void handleInitialState(String elementName, Attributes attributes) throws SAXException {
if (elementName.equals(SITE)) {
stateStack.push(Integer.valueOf(STATE_SITE));
processSite(attributes);
} else {
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)})));
// what we received was not a site.xml, no need to continue
throw new SAXException(Messages.DefaultSiteParser_InvalidXMLStream);
}
}
private void handleSiteState(String elementName, Attributes attributes) {
if (elementName.equals(DESCRIPTION)) {
stateStack.push(Integer.valueOf(STATE_DESCRIPTION_SITE));
processInfo(attributes);
} else if (elementName.equals(FEATURE)) {
stateStack.push(Integer.valueOf(STATE_FEATURE));
processFeature(attributes);
} else if (elementName.equals(BUNDLE)) {
stateStack.push(Integer.valueOf(STATE_BUNDLE));
processBundle(attributes);
} else if (elementName.equals(ARCHIVE)) {
stateStack.push(Integer.valueOf(STATE_ARCHIVE));
processArchive(attributes);
} else if (elementName.equals(CATEGORY_DEF)) {
stateStack.push(Integer.valueOf(STATE_CATEGORY_DEF));
processCategoryDef(attributes);
} else
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {elementName, getState(currentState)})));
}
/*
*
*/
private void internalError(String message) {
error(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.OK, message, null));
}
/*
*
*/
private void internalErrorUnknownTag(String msg) {
stateStack.push(Integer.valueOf(STATE_IGNORED_ELEMENT));
internalError(msg);
}
private boolean leadingSpace(String str) {
if (str.length() <= 0) {
return false;
}
return Character.isWhitespace(str.charAt(0));
}
/*
*
*/
private void logStatus(SAXParseException ex) {
String name = ex.getSystemId();
if (name == null)
name = ""; //$NON-NLS-1$
else
name = name.substring(1 + name.lastIndexOf("/")); //$NON-NLS-1$
String msg;
if (name.equals("")) //$NON-NLS-1$
name = siteLocation.toString();
String[] values = new String[] {name, Integer.toString(ex.getLineNumber()), Integer.toString(ex.getColumnNumber()), ex.getMessage()};
msg = NLS.bind(Messages.DefaultSiteParser_ErrorlineColumnMessage, values);
error(new Status(IStatus.ERROR, PLUGIN_ID, msg, ex));
}
/**
* Parses the specified input steam and constructs a site model.
* The input stream is not closed as part of this operation.
*
* @param in input stream
* @return site model
* @exception SAXException
* @exception IOException
* @since 2.0
*/
public SiteModel parse(InputStream in) throws SAXException, IOException {
stateStack.push(Integer.valueOf(STATE_INITIAL));
currentState = stateStack.peek().intValue();
parser.parse(new InputSource(in), this);
if (objectStack.isEmpty())
throw new SAXException(Messages.DefaultSiteParser_NoSiteTag);
if (objectStack.peek() instanceof SiteModel) {
SiteModel site = (SiteModel) objectStack.pop();
site.setMessageKeys(messageKeys);
return site;
}
String stack = ""; //$NON-NLS-1$
Iterator<Object> iter = objectStack.iterator();
while (iter.hasNext()) {
stack = stack + iter.next().toString() + "\r\n"; //$NON-NLS-1$
}
throw new SAXException(NLS.bind(Messages.DefaultSiteParser_WrongParsingStack, (new String[] {stack})));
}
/*
* process archive info
*/
private void processArchive(Attributes attributes) {
URLEntry archive = new URLEntry();
String id = attributes.getValue("path"); //$NON-NLS-1$
if (id == null || id.trim().equals("")) { //$NON-NLS-1$
internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] {"path", getState(currentState)}))); //$NON-NLS-1$
}
archive.setAnnotation(id);
String url = attributes.getValue("url"); //$NON-NLS-1$
if (url == null || url.trim().equals("")) { //$NON-NLS-1$
internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] {"archive", getState(currentState)}))); //$NON-NLS-1$
} else {
archive.setURL(url);
SiteModel site = (SiteModel) objectStack.peek();
site.addArchive(archive);
}
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("End processing Archive: path:" + id + " url:" + url);//$NON-NLS-1$ //$NON-NLS-2$
}
/*
* process the Category info
*/
private void processCategory(Attributes attributes) {
String category = attributes.getValue("name"); //$NON-NLS-1$
Object item = objectStack.peek();
if (item instanceof SiteFeature) {
SiteFeature feature = (SiteFeature) item;
feature.addCategoryName(category);
} else if (item instanceof SiteBundle) {
SiteBundle bundle = (SiteBundle) item;
bundle.addCategoryName(category);
}
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("End processing Category: name:" + category); //$NON-NLS-1$
}
/*
* process category def info
*/
private void processCategoryDef(Attributes attributes) {
SiteCategory category = new SiteCategory();
String name = attributes.getValue("name"); //$NON-NLS-1$
String label = attributes.getValue("label"); //$NON-NLS-1$
checkTranslated(label);
category.setName(name);
category.setLabel(label);
SiteModel site = (SiteModel) objectStack.peek();
site.addCategory(category);
objectStack.push(category);
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("End processing CategoryDef: name:" + name + " label:" + label); //$NON-NLS-1$ //$NON-NLS-2$
}
/*
* process feature info
*/
private void processFeature(Attributes attributes) {
SiteFeature feature = new SiteFeature();
// feature location on the site
String urlInfo = attributes.getValue("url"); //$NON-NLS-1$
// identifier and version
String id = attributes.getValue("id"); //$NON-NLS-1$
String ver = attributes.getValue("version"); //$NON-NLS-1$
boolean noURL = (urlInfo == null || urlInfo.trim().equals("")); //$NON-NLS-1$
boolean noId = (id == null || id.trim().equals("")); //$NON-NLS-1$
boolean noVersion = (ver == null || ver.trim().equals("")); //$NON-NLS-1$
// We need to have id and version, or the url, or both.
if (noURL) {
if (noId || noVersion)
internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] {"url", getState(currentState)}))); //$NON-NLS-1$
else
// default url
urlInfo = FEATURES + id + '_' + ver; //
}
feature.setURLString(urlInfo);
String type = attributes.getValue("type"); //$NON-NLS-1$
feature.setType(type);
// if one is null, and not the other
if (noId ^ noVersion) {
String[] values = new String[] {id, ver, getState(currentState)};
log(NLS.bind(Messages.DefaultFeatureParser_IdOrVersionInvalid, values));
} else {
feature.setFeatureIdentifier(id);
feature.setFeatureVersion(ver);
}
// get label if it exists
String label = attributes.getValue("label"); //$NON-NLS-1$
if (label != null) {
if ("".equals(label.trim())) //$NON-NLS-1$
label = null;
checkTranslated(label);
}
feature.setLabel(label);
// OS
String os = attributes.getValue("os"); //$NON-NLS-1$
feature.setOS(os);
// WS
String ws = attributes.getValue("ws"); //$NON-NLS-1$
feature.setWS(ws);
// NL
String nl = attributes.getValue("nl"); //$NON-NLS-1$
feature.setNL(nl);
// arch
String arch = attributes.getValue("arch"); //$NON-NLS-1$
feature.setArch(arch);
//patch
String patch = attributes.getValue("patch"); //$NON-NLS-1$
feature.setPatch(patch);
SiteModel site = (SiteModel) objectStack.peek();
site.addFeature(feature);
feature.setSiteModel(site);
objectStack.push(feature);
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("End Processing DefaultFeature Tag: url:" + urlInfo + " type:" + type); //$NON-NLS-1$ //$NON-NLS-2$
}
/*
* process feature info
*/
private void processBundle(Attributes attributes) {
SiteBundle bundle = new SiteBundle();
// feature location on the site
String urlInfo = attributes.getValue("url"); //$NON-NLS-1$
// identifier and version
String id = attributes.getValue("id"); //$NON-NLS-1$
String ver = attributes.getValue("version"); //$NON-NLS-1$
boolean noURL = (urlInfo == null || urlInfo.trim().equals("")); //$NON-NLS-1$
boolean noId = (id == null || id.trim().equals("")); //$NON-NLS-1$
boolean noVersion = (ver == null || ver.trim().equals("")); //$NON-NLS-1$
// We need to have id and version, or the url, or both.
if (noURL) {
if (noId || noVersion)
internalError(NLS.bind(Messages.DefaultSiteParser_Missing, (new String[] {"url", getState(currentState)}))); //$NON-NLS-1$
else
// default url
urlInfo = PLUGINS + id + '_' + ver; //
}
bundle.setURLString(urlInfo);
String type = attributes.getValue("type"); //$NON-NLS-1$
bundle.setType(type);
// if one is null, and not the other
if (noId ^ noVersion) {
String[] values = new String[] {id, ver, getState(currentState)};
log(NLS.bind(Messages.DefaultFeatureParser_IdOrVersionInvalid, values));
} else {
bundle.setBundleIdentifier(id);
bundle.setBundleVersion(ver);
}
// get label if it exists
String label = attributes.getValue("label"); //$NON-NLS-1$
if (label != null) {
if ("".equals(label.trim())) //$NON-NLS-1$
label = null;
checkTranslated(label);
}
bundle.setLabel(label);
// OS
String os = attributes.getValue("os"); //$NON-NLS-1$
bundle.setOS(os);
// WS
String ws = attributes.getValue("ws"); //$NON-NLS-1$
bundle.setWS(ws);
// NL
String nl = attributes.getValue("nl"); //$NON-NLS-1$
bundle.setNL(nl);
// arch
String arch = attributes.getValue("arch"); //$NON-NLS-1$
bundle.setArch(arch);
//patch
String patch = attributes.getValue("patch"); //$NON-NLS-1$
bundle.setPatch(patch);
SiteModel site = (SiteModel) objectStack.peek();
site.addBundle(bundle);
bundle.setSiteModel(site);
objectStack.push(bundle);
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("End Processing DefaultFeature Tag: url:" + urlInfo + " type:" + type); //$NON-NLS-1$ //$NON-NLS-2$
}
/*
* process URL info with element text
*/
private void processInfo(Attributes attributes) {
URLEntry inf = new URLEntry();
String infoURL = attributes.getValue("url"); //$NON-NLS-1$
inf.setURL(infoURL);
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("Processed Info: url:" + infoURL); //$NON-NLS-1$
objectStack.push(inf);
}
/*
* process site info
*/
private void processSite(Attributes attributes) {
// create site map
SiteModel site = new SiteModel();
// if URL is specified, it replaces the URL of the site
// used to calculate the location of features and archives
String siteURL = attributes.getValue("url"); //$NON-NLS-1$
if (siteURL != null && !("".equals(siteURL.trim()))) { //$NON-NLS-1$
if (!siteURL.endsWith("/") && !siteURL.endsWith(File.separator)) { //$NON-NLS-1$
siteURL += "/"; //$NON-NLS-1$
}
site.setLocationURIString(siteURL);
}
// provide default description URL
// If <description> is specified, for the site, it takes precedence
URLEntry description = new URLEntry();
description.setURL(DEFAULT_INFO_URL);
site.setDescription(description);
// verify we can parse the site ...if the site has
// a different type throw an exception to force reparsing
// with the matching parser
String type = attributes.getValue("type"); //$NON-NLS-1$
site.setType(type);
// get mirrors, if any
String mirrorsURL = attributes.getValue("mirrorsURL"); //$NON-NLS-1$
if (mirrorsURL != null && mirrorsURL.trim().length() > 0) {
// URLEntry[] mirrors = getMirrors(mirrorsURL);
// if (mirrors != null)
// site.setMirrors(mirrors);
// else
//Since we are parsing the site at p2 generation time and the
//mirrors may change, there is no point doing the mirror expansion now
site.setMirrorsURIString(mirrorsURL);
}
String pack200 = attributes.getValue("pack200"); //$NON-NLS-1$
if (pack200 != null && Boolean.parseBoolean(pack200)) {
site.setSupportsPack200(true);
}
String digestURL = attributes.getValue("digestURL"); //$NON-NLS-1$
if (digestURL != null)
site.setDigestURIString(digestURL);
// TODO: Digest locales
// if ((attributes.getValue("availableLocales") != null) && (!attributes.getValue("availableLocales").trim().equals(""))) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
// StringTokenizer locals = new StringTokenizer(attributes.getValue("availableLocales"), ","); //$NON-NLS-1$//$NON-NLS-2$
// String[] availableLocals = new String[locals.countTokens()];
// int i = 0;
// while (locals.hasMoreTokens()) {
// availableLocals[i++] = locals.nextToken();
// }
// extendedSite.setAvailableLocals(availableLocals);
// }
// }
//
final String associateURL = attributes.getValue(ASSOCIATE_SITES_URL);
if (associateURL != null) {
//resolve the URI relative to the site location
URI resolvedLocation = siteLocation.resolve(associateURL);
site.setAssociateSites(getAssociateSites(resolvedLocation.toString()));
}
objectStack.push(site);
if (Tracing.DEBUG_GENERATOR_PARSING)
debug("End process Site tag: siteURL:" + siteURL + " type:" + type);//$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Handle start of element tags
* @see DefaultHandler#startElement(String, String, String, Attributes)
* @since 2.0
*/
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (Tracing.DEBUG_GENERATOR_PARSING) {
debug("State: " + currentState); //$NON-NLS-1$
debug("Start Element: uri:" + uri + " local Name:" + localName + " qName:" + qName);//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
switch (currentState) {
case STATE_IGNORED_ELEMENT :
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownElement, (new String[] {localName, getState(currentState)})));
break;
case STATE_INITIAL :
handleInitialState(localName, attributes);
break;
case STATE_SITE :
handleSiteState(localName, attributes);
break;
case STATE_FEATURE :
handleFeatureState(localName, attributes);
break;
case STATE_BUNDLE :
handleBundleState(localName, attributes);
break;
case STATE_ARCHIVE :
handleSiteState(localName, attributes);
break;
case STATE_CATEGORY :
handleCategoryState(localName, attributes);
break;
case STATE_CATEGORY_DEF :
handleCategoryDefState(localName, attributes);
break;
case STATE_DESCRIPTION_SITE :
handleSiteState(localName, attributes);
break;
case STATE_DESCRIPTION_CATEGORY_DEF :
handleSiteState(localName, attributes);
break;
default :
internalErrorUnknownTag(NLS.bind(Messages.DefaultSiteParser_UnknownStartState, (new String[] {getState(currentState)})));
break;
}
int newState = stateStack.peek().intValue();
if (newState != STATE_IGNORED_ELEMENT)
currentState = newState;
}
private boolean trailingSpace(String str) {
if (str.length() <= 0) {
return false;
}
return Character.isWhitespace(str.charAt(str.length() - 1));
}
// Add translatable strings from the site.xml
// to the list of message keys.
private void checkTranslated(String value) {
if (value != null && value.length() > 1 && value.startsWith("%")) //$NON-NLS-1$
messageKeys.add(value.substring(1));
}
}