blob: 55eb3212312ef1dcc10c9e821b53100064819f5f [file] [log] [blame]
package org.eclipse.update.core.model;
/*
* (c) Copyright IBM Corp. 2000, 2002.
* All Rights Reserved.
*/
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;
import org.apache.xerces.parsers.SAXParser;
import org.eclipse.core.runtime.*;
import org.eclipse.update.core.URLEntry;
import org.eclipse.update.internal.core.UpdateManagerPlugin;
import org.eclipse.update.internal.core.UpdateManagerUtils;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
/**
* parse default site.xml
*/
public class DefaultSiteParser extends DefaultHandler {
private SAXParser parser;
private SiteModelFactory factory;
private MultiStatus status;
private static final int IGNORED_ELEMENT_STATE = -1;
private static final int STATE_INITIAL = 0;
private static final int STATE_SITE = 1;
private static final int STATE_FEATURE = 2;
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 = 6;
private static final String PLUGIN_ID = UpdateManagerPlugin.getPlugin().getDescriptor().getUniqueIdentifier();
public static boolean DEBUG = false;
public static final String SITE = "site";
public static final String FEATURE = "feature";
public static final String ARCHIVE = "archive";
public static final String CATEGORY_DEF = "category-def";
public static final String CATEGORY = "category";
public static final String DESCRIPTION = "description";
private static final String DEFAULT_INFO_URL = "index.html";
// Current State Information
Stack stateStack = new Stack();
// Current object stack (used to hold the current object we are
// populating in this plugin descriptor
Stack objectStack = new Stack();
/**
* Constructor for DefaultSiteParser
*/
public DefaultSiteParser(SiteModelFactory factory) {
super();
this.parser = new SAXParser();
this.parser.setContentHandler(this);
this.factory = factory;
if (DEBUG)
debug("Created");
}
/**
* @since 2.0
*/
public SiteMapModel parse(InputStream in) throws SAXException, IOException {
stateStack.push(new Integer(STATE_INITIAL));
parser.parse(new InputSource(in));
return (SiteMapModel) objectStack.pop();
}
/**
* @see DefaultHandler#startElement(String, String, String, Attributes)
*/
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (DEBUG) {
debug("State: " + (Integer) stateStack.peek());
debug("Start Element: uri:" + uri + " local Name:" + localName + " qName:" + qName);
}
String tag = localName.trim();
int state = ((Integer) stateStack.peek()).intValue();
switch (state) {
case IGNORED_ELEMENT_STATE :
internalErrorUnknownTag("unknown element in ingored state:" + localName);
break;
case STATE_INITIAL :
handleInitialState(localName, attributes);
break;
case STATE_SITE :
handleSiteState(localName, attributes);
break;
case STATE_FEATURE :
handleFeatureState(localName, attributes);
break;
case STATE_ARCHIVE :
handleArchiveState(localName, attributes);
break;
case STATE_CATEGORY :
handleCategoryState(localName, attributes);
break;
case STATE_CATEGORY_DEF :
handleCategoryDefState(localName, attributes);
break;
case STATE_DESCRIPTION :
handleDescriptionState(localName, attributes);
break;
default :
internalErrorUnknownTag("unknown state:" + state);
break;
}
}
public void handleInitialState(String elementName, Attributes attributes) throws SAXException {
if (elementName.equals(SITE)) {
stateStack.push(new Integer(STATE_SITE));
processSite(attributes);
} else
internalErrorUnknownTag("unknown root element:" + elementName);
}
public void handleSiteState(String elementName, Attributes attributes) {
if (elementName.equals(DESCRIPTION)) {
stateStack.push(new Integer(STATE_DESCRIPTION));
processInfo(attributes);
} else if (elementName.equals(FEATURE)) {
stateStack.push(new Integer(STATE_FEATURE));
processFeature(attributes);
} else if (elementName.equals(ARCHIVE)) {
stateStack.push(new Integer(STATE_ARCHIVE));
processArchive(attributes);
} else if (elementName.equals(CATEGORY_DEF)) {
stateStack.push(new Integer(STATE_CATEGORY_DEF));
processCategoryDef(attributes);
} else
internalErrorUnknownTag("unknown element :" + elementName+" insie site tag.");
}
public void handleFeatureState(String elementName, Attributes attributes) {
if (elementName.equals(CATEGORY)) {
stateStack.push(new Integer(STATE_CATEGORY));
processCategory(attributes);
} else
internalErrorUnknownTag("unknown element:" + elementName+" inside feature tag.");
}
public void handleArchiveState(String elementName, Attributes attributes) {
internalErrorUnknownTag("unknown element:" + elementName+" inside archive tag.");
}
public void handleCategoryState(String elementName, Attributes attributes) {
internalErrorUnknownTag("unknown element:" + elementName+" inside category tag.");
}
public void handleCategoryDefState(String elementName, Attributes attributes) {
if (elementName.equals(DESCRIPTION)) {
stateStack.push(new Integer(STATE_DESCRIPTION));
processInfo(attributes);
} else
internalErrorUnknownTag("unknown element:" + elementName+" inside category definition tag.");
}
public void handleDescriptionState(String elementName, Attributes attributes) {
internalErrorUnknownTag("unknown element:" + elementName+" inside description tag.");
}
/**
* process site info
*/
private void processSite(Attributes attributes) throws SAXException {
// create site map
SiteMapModel site = factory.createSiteMapModel();
// Compatibility support for <site url=""/>. If <description> is specified,
// it takes precedence
// FIXME: do we still need it ?
String infoURL = attributes.getValue("url");
if (infoURL == null || infoURL.trim().equals(""))
infoURL = DEFAULT_INFO_URL;
URLEntryModel description = factory.createURLEntryModel();
description.setURLString(infoURL);
site.setDescriptionModel(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");
if (!factory.canParseSiteType(type)) {
throw new SAXException(new InvalidSiteTypeException(type));
}
site.setType(type);
objectStack.push(site);
if (DEBUG)
debug("End process Site tag: infoURL:" + infoURL + " type:" + type);
}
/**
* process feature info
*/
private void processFeature(Attributes attributes) {
FeatureReferenceModel feature = factory.createFeatureReferenceModel();
String urlInfo = UpdateManagerUtils.encode(attributes.getValue("url"));
if (urlInfo == null || urlInfo.trim().equals(""))
internalError("Invalid URL tag of a feature tag. Value is required.");
feature.setURLString(urlInfo);
String type = attributes.getValue("type");
feature.setType(type);
SiteMapModel site = (SiteMapModel) objectStack.peek();
site.addFeatureReferenceModel(feature);
feature.setSiteModel(site);
objectStack.push(feature);
if (DEBUG)
debug("End Processing DefaultFeature Tag: url:" + urlInfo + " type:" + type);
}
/**
* process archive info
*/
private void processArchive(Attributes attributes) {
ArchiveReferenceModel archive = factory.createArchiveReferenceModel();
String id = attributes.getValue("path");
if (id == null || id.trim().equals("")) {
internalError("The id tag of an archive is null or does not exist.");
} else {
archive.setPath(id);
String url = attributes.getValue("url");
if (url == null || url.trim().equals("")) {
internalError("The url tag of an archive is null or does not exist.");
} else {
url = UpdateManagerUtils.encode(url);
archive.setURLString(url);
SiteMapModel site = (SiteMapModel) objectStack.peek();
site.addArchiveReferenceModel(archive);
}
if (DEBUG)
debug("End processing Archive: path:" + id + " url:" + url);
}
}
/**
* process the Category info
*/
private void processCategory(Attributes attributes) {
String category = attributes.getValue("name");
FeatureReferenceModel feature = (FeatureReferenceModel) objectStack.peek();
feature.addCategoryName(category);
if (DEBUG)
debug("End processing Category: name:" + category);
}
/**
* process category def info
*/
private void processCategoryDef(Attributes attributes) {
SiteCategoryModel category = factory.createSiteCategoryModel();
String name = attributes.getValue("name");
String label = attributes.getValue("label");
category.setName(name);
category.setLabel(label);
SiteMapModel site = (SiteMapModel) objectStack.peek();
site.addCategoryModel(category);
objectStack.push(category);
if (DEBUG)
debug("End processing CategoryDef: name:" + name + " label:" + label);
}
/**
* process URL info with element text
*/
private void processInfo(Attributes attributes) {
URLEntryModel inf = factory.createURLEntryModel();
String infoURL = attributes.getValue("url");
inf.setURLString(infoURL);
if (DEBUG)
debug("Processed Info: url:" + infoURL);
objectStack.push(inf);
}
/**
* @see DefaultHandler#endElement(String, String, String)
*/
public void endElement(String uri, String localName, String qName) {
String tag = localName.trim();
int state = ((Integer) stateStack.peek()).intValue();
switch (state) {
case IGNORED_ELEMENT_STATE :
case STATE_ARCHIVE :
case STATE_CATEGORY :
stateStack.pop();
break;
case STATE_INITIAL :
internalError("Stack back to Initial State, error parsing file");
break;
case STATE_SITE :
stateStack.pop();
if (objectStack.peek() instanceof String) {
String text = (String) objectStack.pop();
SiteMapModel site = (SiteMapModel) objectStack.peek();
site.getDescriptionModel().setAnnotation(text);
}
//do not pop
break;
case STATE_FEATURE :
stateStack.pop();
objectStack.pop();
break;
case STATE_CATEGORY_DEF :
stateStack.pop();
if (objectStack.peek() instanceof String) {
String text = (String) objectStack.pop();
SiteCategoryModel category = (SiteCategoryModel) objectStack.peek();
category.getDescriptionModel().setAnnotation(text);
}
objectStack.pop();
break;
case STATE_DESCRIPTION :
stateStack.pop();
URLEntryModel info = (URLEntry) objectStack.pop();
int innerState = ((Integer) stateStack.peek()).intValue();
switch (innerState) {
case STATE_SITE :
SiteMapModel siteModel = (SiteMapModel) objectStack.peek();
siteModel.setDescriptionModel(info);
break;
case STATE_CATEGORY_DEF :
SiteCategoryModel category = (SiteCategoryModel) objectStack.peek();
category.setDescriptionModel(info);
break;
default :
internalError("Description in wrong state:" + state);
break;
}
break;
default :
internalError("unknown state:" + state);
break;
}
if (DEBUG)
debug("End Element:" + uri + ":" + localName + ":" + qName);
}
/**
* @see DefaultHandler#characters(char[], int, int)
*/
public void characters(char[] ch, int start, int length) {
String text = new String(ch, start, length).trim();
if (!text.equals(""))
objectStack.push(text);
}
private void debug(String s) {
System.out.println("DefaultSiteParser: " + s);
}
public void error(SAXParseException ex) {
logStatus(ex);
}
public void fatalError(SAXParseException ex) throws SAXException {
logStatus(ex);
throw ex;
}
private void logStatus(SAXParseException ex) {
String name = ex.getSystemId();
if (name == null)
name = "";
else
name = name.substring(1 + name.lastIndexOf("/"));
String msg;
if (name.equals(""))
msg = "Error Parsing";
else
msg = "Error:" + name + " line:" + Integer.toString(ex.getLineNumber()) + " column:" + Integer.toString(ex.getColumnNumber()) + " message:" + ex.getMessage();
error(new Status(IStatus.WARNING, PLUGIN_ID, Platform.PARSE_PROBLEM, msg, ex));
}
/**
* 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
*/
public void error(IStatus error) {
getStatus().add(error);
UpdateManagerPlugin.getPlugin().getLog().log(error);
if (UpdateManagerPlugin.DEBUG && UpdateManagerPlugin.DEBUG_SHOW_PARSING)
UpdateManagerPlugin.getPlugin().debug(error.toString());
}
/**
*
*/
public void internalErrorUnknownTag(String msg) {
stateStack.push(new Integer(IGNORED_ELEMENT_STATE));
internalError(msg);
}
/**
* Returns all of the status objects logged thus far by this factory.
*
* @return a multi-status containing all of the logged status objects
*/
public MultiStatus getStatus() {
if (status == null) {
status = new MultiStatus(PLUGIN_ID, Platform.PARSE_PROBLEM, "Error parsing Site.xml", null);
}
return status;
}
private void internalError(String message) {
error(new Status(IStatus.WARNING, PLUGIN_ID, Platform.PARSE_PROBLEM, message, null));
}
}