/** * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bushe.swing.action; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.net.URL; import java.util.ArrayList; import java.util.EmptyStackException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import java.awt.Dimension; import javax.swing.Action; import javax.swing.KeyStroke; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.DocumentBuilderFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; import org.w3c.dom.Document; /** * The ActionXMLReader reads sets of properties describing * <code>javax.swing.Action</code>s from an XML file. This class is a * fork of the ActionManager from Mark Davidson of Sun's Swing team, though the * reader was stripped out from his ActionManager into this class to read an * extended format and allow the manager to be more flexible. * <p> * The Actions are specified in an XML configuration file. The schema for the * XML document contains three major elements. * <ul> * <li><b>action</b> Represents the properties of an Action. * <li><b>action-list</b> Represents lists and trees of actions which can be * used to construct user interface components like toolbars, menus and popups. * <li><b>action-set</b> The document root which contains a set of * action-lists and actions. * </ul> * <p> * All of these elements have a unique id tag which is used by the * ActionXMLReader to reference the element. Refer to * <a href="res/action-set.dtd">action-set.dtd</a> * for details on the elements and attributes. * <p> * The order of an action in an action-list will reflect the order of the * Action based component in the container. A tree is represented as an * action-list that contains one or more action-lists. * <p> * An ActionAttributes instance is created for each set of Action properties * in the XML file. The attributes must be registered as action prototypes * with the ActionManager to be useful. ActionManager encompasses this behavior * directly like so: * <p> * <pre> * ActionManager.registerFromURL(myURL); * </pre> * <p> * Once either is performed, the ActionManager can be used normally, like so: * <pre> * ActionManager.getInstance().getAction(id).setActionCallback(this); * // Change the state of the action: * ActionManager.getInstance().getAction("new-action").setEnabled(newState); * </pre> * <p> * The ActionUIFactory can be used to create components from action id lists * registered from this class. * * @see ActionUIFactory * @see ActionManager * @see <a href="res/action-set.dtd">action-set.dtd</a> * @author Michael Bushe * @author Mark Davidson - stole his semi-working code from java.net */ public class ActionXMLReader { // Elements in the action-set.dtd public final static String ELEMENT_ACTION_SET = "action-set"; public final static String ELEMENT_ACTION = "action"; public final static String ELEMENT_ACTION_LIST = "action-list"; public final static String ELEMENT_SEPARATOR = "separator"; public final static String ELEMENT_GROUP = "group"; public final static String ELEMENT_ROLE = "role"; public final static String ELEMENT_NAME_VALUE_PAIR = "name-value-pair"; public final static String ATTRIBUTE_DEFAULT_ACTION_CLASS = "defaultActionClass"; public final static String ATTRIBUTE_TOOLBAR_BUTTON_PREF_WIDTH = "toolbarButtonPreferredWidth"; public final static String ATTRIBUTE_TOOLBAR_BUTTON_PREF_HEIGHT = "toolbarButtonPreferredHeight"; public final static String ATTRIBUTE_ACCEL = "accel"; public final static String ATTRIBUTE_DESC = "desc"; public final static String ATTRIBUTE_LONG_DESC = "longdesc"; public final static String ATTRIBUTE_LGICON = "lgicon"; public final static String ATTRIBUTE_ID = "id"; public final static String ATTRIBUTE_COMMAND = "command"; public final static String ATTRIBUTE_IDREF = "idref"; public final static String ATTRIBUTE_MNEMONIC = "mnemonic"; public final static String ATTRIBUTE_NAME = "name"; public final static String ATTRIBUTE_ENABLED = "enabled"; public final static String ATTRIBUTE_SELECTED = "selected"; public final static String ATTRIBUTE_SMICON = "smicon"; public final static String ATTRIBUTE_BUTTON_TYPE = "buttonType"; public final static String ATTRIBUTE_TOOLBAR_SHOWS_TEXT = "toolbarShowsText"; public final static String ATTRIBUTE_MENU_SHOWS_ICON = "menuShowsIcon"; public final static String ATTRIBUTE_GROUP = "group"; public final static String ATTRIBUTE_WEIGHT = "weight"; public final static String ATTRIBUTE_ACTION_CLASS = "actionClass"; public final static String ATTRIBUTE_ACTION_LIST_TRIGGER_ACTION_REF_ID = "triggerActionRefId"; public final static String ATTRIBUTE_LINE_VISIBLE = "lineVisible"; private static SAXParserFactory parserfactory; private ActionHandler handler; // A mapping between the action-set id and a list of action ids. private Map actionSetMap; //default action class of current set, if specified private String defaultActionClass; private boolean debug = false; private boolean printValidationErrors; private ActionManager actionManager; /** * Creates an action XML reader */ public ActionXMLReader(ActionManager manager) { this.actionManager = manager; } /** * @param debug whether to not to output debug messages */ public void setDebug(boolean debug) { this.debug = debug; } /** * Sets whether XML validation errors should be printed. Particularly * useful to pass false when merging multiple files using idref's * (though this can be avoided with XML's '&' entity includes) * @param printValidationErrors boolean */ public void setPrintValidationErrors(boolean printValidationErrors) { this.printValidationErrors = printValidationErrors; } /** * Most commonly used for Swing apps. Has the added benefit of setting * the parser's SystemId to the directory of the file, allowing references * to the DTD and other files to be resolved. * @param f the file to parser * @throws IOException * @throws SAXException */ public void loadActions(File f) throws IOException, SAXException { if (debug) { System.out.println("loadActions(" + f.getAbsolutePath() + ")"); } SAXParser parser = getParser(); FileInputStream fis = new FileInputStream(f); InputSource is = new InputSource(fis); is.setSystemId(new File(f.getParent()).toURL().toExternalForm()); loadActions(is, parser); } /** * Adds the set of actions and action-lists * from an action-set document into the ActionXMLReader. * A call to this method usually takes the form: * xmlReader.loadActions(getClass().getResource("myActions.xml")); * * @param url URL pointing to an actionSet document * @throws IllegalArgumentException If url param is null * @throws IOException If there is an error in parsing */ public void loadActions(URL url) throws IOException, SAXException { if (debug) { System.out.println("loadActions(" + url + ")"); } if (url == null) { throw new IllegalArgumentException("URL is null."); } InputStream stream = url.openStream(); try { loadActions(new InputSource(stream), getParser()); } finally { stream.close(); } } /** * Adds the set of actions and action-lists * from an action-set document into the ActionXMLReader. * * @param stream InputStream containing an actionSet document * @throws IOException If there is an error in parsing */ public void loadActions(InputStream stream) throws IOException, SAXException { SAXParser parser = getParser(); loadActions(new InputSource(stream), parser); } public void loadActions(InputSource is, SAXParser parser) throws IOException { try { if (handler == null) { handler = new ActionHandler(); } parser.parse(is, handler); } catch (SAXException ex) { printException("SAXException: " + ex.getMessage(), ex); throw new IOException("Error parsing: " + ex.getMessage()); } catch (IOException ex2) { printException("IOException: " + ex2.getMessage(), ex2); throw ex2; } } public SAXParser getParser() throws SAXException, IOException { if (parserfactory == null) { parserfactory = SAXParserFactory.newInstance(); parserfactory.setValidating(true); } try { return parserfactory.newSAXParser(); } catch (ParserConfigurationException ex3) { printException("ParserConfigurationException: " + ex3.getMessage(), ex3); throw new SAXException("Error parsing: " + ex3.getMessage()); } } /** * Adds the values represented in the SAX Attrributes structure * to a lightweight internal data strucure. * * @param attrs the Attributes for an action * @param actionset the parent action-set id for the action */ private void addAttributes(Attributes attrs, String actionset) { String id = attrs.getValue(ATTRIBUTE_ID); actionManager.registerActionPrototype(id, xmlAttrsToActionAttrs(attrs)); addActionIdToActionSet(attrs.getValue(ATTRIBUTE_ID), actionset); } /** * Create ActionAttributes from parsed XML Attributes, basically converting * the XML keys to Action keys. * @param attrs the XML Attributes of the action tag. * @return a new set of action attrbiutes */ public ActionAttributes xmlAttrsToActionAttrs(Attributes attrs) { ActionAttributes actionAttrs = new ActionAttributes(); updateAttributes(actionAttrs, attrs); return actionAttrs; } /** * Updates the actionAttrs by mapping the XML attributes to the action * attributes. If an XML attribute value is null, then that value is * not updated (this is how inheritence works). Roles are inherited * additively (new roles add to old roles, they do not replace them). * @param actionAttrs the attributes to update * @param attrs the XML to use to change the actionAttrs */ public void updateAttributes(ActionAttributes actionAttrs, Attributes attrs) { Object value = attrs.getValue(ActionXMLReader.ATTRIBUTE_NAME); if (value != null) { actionAttrs.putValue(Action.NAME, value); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_ID); if (value != null) { actionAttrs.putValue(ActionManager.ID, value); //Use the id as the command key unless it was explicitly set actionAttrs.putValue(Action.ACTION_COMMAND_KEY, value); } String commandKey = (String) attrs.getValue(ActionXMLReader.ATTRIBUTE_COMMAND); if (commandKey != null) { actionAttrs.putValue(Action.ACTION_COMMAND_KEY, commandKey); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_DESC); if (value != null) { actionAttrs.putValue(Action.SHORT_DESCRIPTION, value); //Use the desc for the short desc unless longdesc was explicitly set actionAttrs.putValue(Action.LONG_DESCRIPTION, value); } String longDesc = (String) attrs.getValue(ActionXMLReader.ATTRIBUTE_LONG_DESC); if (longDesc != null) { actionAttrs.putValue(Action.LONG_DESCRIPTION, longDesc); } else { value = attrs.getValue(ActionXMLReader.ATTRIBUTE_DESC); if (value != null) { actionAttrs.putValue(Action.LONG_DESCRIPTION, value); } } String mnemonic = (String) attrs.getValue(ActionXMLReader.ATTRIBUTE_MNEMONIC); if (mnemonic != null && !mnemonic.equals("")) { actionAttrs.putValue(Action.MNEMONIC_KEY, new Integer(mnemonic.charAt(0))); } String accel = (String) attrs.getValue(ActionXMLReader.ATTRIBUTE_ACCEL); if (accel != null && !accel.equals("")) { KeyStroke keyStroke = KeyStroke.getKeyStroke(accel.trim()); actionAttrs.putValue(Action.ACCELERATOR_KEY, keyStroke); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_SMICON); if (value != null) { actionAttrs.putValue(Action.SMALL_ICON, actionManager.resolveIcon((String) value)); } //note: ICON_ATTRIBUTE is not an standard action property value = attrs.getValue(ActionXMLReader.ATTRIBUTE_LGICON); if (value != null) { actionAttrs.putValue(ActionManager.LARGE_ICON, actionManager.resolveIcon((String) value)); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_TOOLBAR_SHOWS_TEXT); if (value != null) { actionAttrs.putValue(ActionManager.TOOLBAR_SHOWS_TEXT, new Boolean(value.toString())); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_MENU_SHOWS_ICON); if (value != null) { actionAttrs.putValue(ActionManager.MENU_SHOWS_ICON, new Boolean(value.toString())); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_GROUP); if (value != null) { actionAttrs.putValue(ActionManager.GROUP, value); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_BUTTON_TYPE); if (value != null) { actionAttrs.putValue(ActionManager.BUTTON_TYPE, value); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_WEIGHT); if (value != null) { actionAttrs.putValue(ActionManager.WEIGHT, value); } value = attrs.getValue(ActionXMLReader.ATTRIBUTE_ACTION_CLASS); if (value == null) { if (defaultActionClass != null) { value = defaultActionClass; } } if (value != null) { actionAttrs.putValue(ActionManager.ACTION_CLASS, value); } } public void addRoles(String action, List roles) { ActionAttributes actionAttrs = actionManager.getPrototype(action); if (actionAttrs == null) { return; } actionAttrs.putValue(ActionManager.ACTION_ROLES, roles); } /** * Stores a new set of ActionAttributes internally by creating them from * the inherited values, then overriding those values with XML * attributes. Adds the result to the given action set. * * @param actionId the id of the action to create * @param inheritedAttrs the values to start with * @param overridenAttrs the SAX Attributes to overwrite with * @param actionset the parent action-set id for the action */ private void addAttributes(String actionId, ActionAttributes inheritedAttrs, Attributes overridenAttrs, String actionset) { String id = overridenAttrs.getValue(ATTRIBUTE_ID); ActionAttributes attrs = new ActionAttributes(inheritedAttrs); attrs.putValue(ActionManager.ID, id); //by default the command matches the id, the xml can override command //if necessary, the derived action can redefine the command. attrs.putValue(Action.ACTION_COMMAND_KEY, id); // Apply redefined attributes updateAttributes(attrs, overridenAttrs); actionManager.registerActionPrototype(id, attrs); addActionIdToActionSet(id, actionset); } /** * Adds the id of the action set to an internal structure. * @param id the id of the action set * @param actionset the action set to remember. */ private void addActionIdToActionSet(String id, String actionset) { // Add this action id to the actionset if (actionset != null && !actionset.equals("")) { List list = getActionSet(actionset); if (list == null) { list = new ArrayList(); } list.add(id); addActionSet(actionset, list); } } /** * Retrieve the ids for all the managed actions-sets. * <p> * An action set is an association between an action-set id and the * action ids that it contains. For example, the actions-core.xml * action-set document has the action-set id: "core-actions" that * contains the actions: new-action, open-action, save-action, etc... * * @return a set which represents all the action-set ids */ public Set getActionSetIDs() { if (actionSetMap == null) { actionSetMap = new HashMap(); } return actionSetMap.keySet(); } /** * Return an action set for an action-set id. * @param id the action-set id * @return a List of action ids in the set */ private List getActionSet(Object id) { if (actionSetMap == null) { actionSetMap = new HashMap(); } return (List) actionSetMap.get(id); } /** * Adds an action set for an action-set id. * @param key the action-set id * @param set the action set for the key */ private void addActionSet(String key, List set) { if (actionSetMap == null) { actionSetMap = new HashMap(); } actionSetMap.put(key, set); } private void printException(String message, Exception ex) { System.out.println(message); if (debug) { ex.printStackTrace(); } } /** * A diagnostic which prints the Attributes of an action * on the printStream * @param stream the stream to print to * @param actionAttributes the attribtues to print */ static void printActionAttributes(PrintStream stream, ActionAttributes actionAttributes) { stream.println("Attributes for " + actionAttributes.getValue(Action.ACTION_COMMAND_KEY) + actionAttributes); } /** * Implemenation of the SAX event handler which acts on elements * and attributes defined in the action-set.dtd. * * This class creates the lightweight data structures which encapsulate * the parsed xml data that can be used to contruct Actions * and UI elements from Actions. */ class ActionHandler extends DefaultHandler { private String element; private Stack actionListStack; // keep track of nested action-lists. private Stack actionSetStack; // keep track of nested action-sets. private String actionset; // current action-set id private ActionList actionlist; // current action-list id private String action; // current action id private String group; // current group id private List roles; //the list of role names defined for the action public void startDocument() { element = ""; actionListStack = new Stack(); actionSetStack = new Stack(); actionset = null; actionlist = null; action = null; group = null; roles = null; } public void startElement(String nameSpace, String localName, String name, Attributes attributes) { if (debug) { System.out.print("startElement(" + nameSpace + "," + localName + "," + name + ",...)"); String id = attributes.getValue(ATTRIBUTE_ID); System.out.println("id=" + id); if (id != null && id.equals("inherit-action")) { System.out.println("in"); } } element = name; if (ELEMENT_ACTION_SET.equals(name)) { String newSet = attributes.getValue(ATTRIBUTE_ID); if (actionset != null) { actionSetStack.push(actionset); } actionset = newSet; String strWidth = attributes.getValue(ATTRIBUTE_TOOLBAR_BUTTON_PREF_WIDTH); String strHeight = attributes.getValue(ATTRIBUTE_TOOLBAR_BUTTON_PREF_HEIGHT); if (strWidth != null && strHeight != null) { int width = Integer.parseInt(strWidth); int height = Integer.parseInt(strHeight); if (width > -1 && height > -1) { ActionUIFactory.getInstance().setToolbarButtonPreferredSize(new Dimension(width, height)); } } defaultActionClass = attributes.getValue(ATTRIBUTE_DEFAULT_ACTION_CLASS); } else if (ELEMENT_ACTION_LIST.equals(name)) { // <action-list id="main-menu"> // <action-list id="file-menu" triggerActionRefId="file-menu-action"> // <action idref="new-action"/> // <action idref="open-action" mnemonic="P"/> // <action idref="save-action"/> // <separator/> // <action idref="exit-action"/> // </action-list> //checkForId String listId = attributes.getValue(ATTRIBUTE_ID); String actionListRefId = attributes.getValue(ATTRIBUTE_IDREF); if (listId == null && actionListRefId == null) { throw new IllegalArgumentException("Action lists require either an id or an idref."); } if (listId != null && actionListRefId != null) { throw new UnsupportedOperationException("Error with action-list named:"+listId +" The idref attribute in action-list elements would refer to inherited lists, but they are not yet supported. If the idref is meant to refering to the action that triggers the list (menu/toolbar), then use triggerActionRefId instead (this differs from the original JDNC XML)."); } String triggerActionRefId = attributes.getValue(ATTRIBUTE_ACTION_LIST_TRIGGER_ACTION_REF_ID); if (actionListRefId != null && triggerActionRefId != null) { throw new IllegalArgumentException("Action lists cannot use triggerActionRefId and idref, i.e. a list cannot tell another action-list what it's trigger is."); } if (triggerActionRefId == null && listId != null) { //No, the action-list can define attributes for it's own //action "in-line." //Make a new action for the action list's triggering action //whose id is the id of the action-list triggerActionRefId = listId; ActionAttributes actionAtts = actionManager.getPrototype(listId); if (actionAtts == null) { addAttributes(attributes, actionset); } } //Does the action list refer to a pre-defined action list? ActionList newOrReferredToList = null; if (actionListRefId == null) { //No, just create a new ActionList newOrReferredToList = new ActionList(listId, triggerActionRefId); String weight = attributes.getValue(ATTRIBUTE_WEIGHT); if (weight != null) { newOrReferredToList.setWeight(Double.valueOf(weight)); } actionManager.registerActionIdList(newOrReferredToList); if (actionlist != null) { //Add current action list to it's parent actionlist.add(newOrReferredToList); } } else { //Yes, get the reference from the action manager and //use that as our list reference newOrReferredToList = actionManager.getActionIdList(actionListRefId); if (newOrReferredToList == null) { throw new IllegalArgumentException("Action-list for "+ "idref "+actionListRefId+" does not exist. "+ "Note: You may need to migrate your XML if "+ "you are changing ActionManager implementations. "+ "Mark Davidson's original ActionManager uses the "+ "action-lists idref to point to actions. Use "+ "triggerActionIdRef to point to actions. Action-list "+ "idrefs are used to merge action-lists."); } } //Push parent list down the stack, and make this list the top if (actionlist != null) { actionListStack.push(actionlist); } actionlist = newOrReferredToList; } else if (ELEMENT_ACTION.equals(name)) { // If this action is not within an action-list element then // handle its attributes. action = attributes.getValue(ATTRIBUTE_ID); String inheritedAction = attributes.getValue(ATTRIBUTE_IDREF); validateAction(attributes, inheritedAction); //Add attributes for the new action if (action != null) { addAttributesFromInheritedAction(attributes, inheritedAction); } else { action = inheritedAction; } if (actionlist != null) { // If this action is within an action-list element then add // it to the list. if (!actionlist.contains(action)) { actionlist.add(action); } if (group != null) { ActionAttributes actionAttrs = actionManager.getPrototype(action); if (actionAttrs != null) { actionAttrs.putValue(ActionManager.GROUP, group); } } } } else if (ELEMENT_NAME_VALUE_PAIR.equals(name)) { ActionAttributes actionAttrs = actionManager.getPrototype(action); if (actionAttrs != null) { actionAttrs.putValue(attributes.getValue("name"), attributes.getValue("value")); } } else if (ELEMENT_ROLE.equals(name)) { if (roles == null) { roles = new ArrayList(3); } roles.add(attributes.getValue("name")); } else if (ELEMENT_GROUP.equals(name)) { group = attributes.getValue(ATTRIBUTE_ID); } else if (ELEMENT_SEPARATOR.equals(name)) { if (actionlist != null) { Number weight = null; String weightStr = null; try { //try integers first weightStr = attributes.getValue(ATTRIBUTE_WEIGHT); if (weightStr != null) { weight = Integer.valueOf(weightStr); } } catch (NumberFormatException ex) { try { weight = Double.valueOf(weightStr); } catch (NumberFormatException ex2) { } } boolean isLineVisible = true; if (attributes.getValue(ATTRIBUTE_LINE_VISIBLE) != null) { isLineVisible = Boolean.getBoolean(attributes.getValue(ATTRIBUTE_LINE_VISIBLE)); } Separator separator = new Separator(attributes.getValue(ATTRIBUTE_ID), weight, isLineVisible); actionlist.add(separator); } } } private void addAttributesFromInheritedAction(Attributes attributes, String inheritedAction) throws RuntimeException { if (inheritedAction == null) { addAttributes(attributes, actionset); } else { ActionAttributes inheritedActionAtts = actionManager.getPrototype(inheritedAction); if (inheritedActionAtts == null) { throw new RuntimeException("Action " + action + " inherits from action " + inheritedAction + " but it is not yet defined. Actions that inherit from others must be declared after the action they inherit from."); } addAttributes(action, inheritedActionAtts, attributes, actionset); } } private void validateAction(Attributes attributes, String inheritedAction) throws RuntimeException { if (action == null && inheritedAction == null) { throw new RuntimeException("Actions must have an id or an idref defined. Element name:"+element+"Attributes:"+stringForAttributes(attributes)); } //If there are any attributes on an action //besides idref, then id must be defined int numOtherAtts = attributes.getLength(); if (action != null) { numOtherAtts--; } if (inheritedAction != null) { numOtherAtts--; } if (numOtherAtts > 0 && action == null) { throw new RuntimeException( "An action that defines an attribute must declare an id. Inherited action:" + inheritedAction); } } private String stringForAttributes(Attributes attributes) { if (attributes == null) { return "null"; } String result = ""; for (int i = 0; i < attributes.getLength(); i++) { result = result + attributes.getLocalName(i) + "="+ attributes.getValue(i)+" "; } return result; } public void endElement(String nameSpace, String localName, String name) { if (debug) { System.out.println("endElement(" + nameSpace + "," + localName + "," + name + ")"); } if (ELEMENT_ACTION_SET.equals(name)) { try { actionset = (String) actionSetStack.pop(); } catch (EmptyStackException ex) { actionset = null; } } else if (ELEMENT_ACTION_LIST.equals(name)) { try { if (roles != null) { actionlist.setRoles(roles); } roles = null; actionlist = (ActionList) actionListStack.pop(); } catch (EmptyStackException ex) { actionlist = null; } } else if (ELEMENT_ACTION.equals(name)) { if (roles != null) { addRoles(action, roles); } roles = null; } else if (ELEMENT_GROUP.equals(name)) { group = null; } } public void endDocument() { element = ""; actionListStack = new Stack(); actionSetStack = new Stack(); actionset = null; actionlist = null; action = null; group = null; } // // Overloaded ErrorHandler methods for Validating parser. // public void error(SAXParseException ex) throws SAXException { if (printValidationErrors) { System.out.println("**** validation error"); reportException(ex); } } public void warning(SAXParseException ex) throws SAXException { if (printValidationErrors) { System.out.println("**** validation warning"); reportException(ex); } } public void fatalError(SAXParseException ex) throws SAXException { if (printValidationErrors) { System.out.println("**** validation fatalError"); reportException(ex); } } private void reportException(SAXParseException ex) { if (printValidationErrors) { System.out.println(ex.getLineNumber() + ":" + ex.getColumnNumber() + " " + ex.getMessage()); System.out.println("Public ID: " + ex.getPublicId() + "\t" + "System ID: " + ex.getSystemId()); } if (debug) { ex.printStackTrace(); } } } // end class ActionXMLReader /** * Parses any file into a Document * @param file the file to parse * @return a Document * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public static Document parseXMLDocument(File file) throws ParserConfigurationException, IOException, SAXException { // Create a builder factory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); // Create the builder and parse the file return factory.newDocumentBuilder().parse(file); } }