001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: DelegatingHandler.java,v 1.2 2006/09/29 12:32:11 drmlipp Exp $
021: *
022: * $Log: DelegatingHandler.java,v $
023: * Revision 1.2 2006/09/29 12:32:11 drmlipp
024: * Consistently using WfMOpen as projct name now.
025: *
026: * Revision 1.1.1.1 2003/06/30 20:05:12 drmlipp
027: * Initial import
028: *
029: * Revision 1.7 2003/06/27 08:51:46 lipp
030: * Fixed copyright/license information.
031: *
032: * Revision 1.6 2003/04/22 14:34:27 lipp
033: * Added handler type.
034: *
035: * Revision 1.5 2003/04/22 11:13:31 lipp
036: * Various fixes.
037: *
038: * Revision 1.4 2003/04/21 20:25:41 lipp
039: * Major revision of implementation.
040: *
041: * Revision 1.3 2003/04/17 21:04:13 lipp
042: * Minor updates for namespace support.
043: *
044: * Revision 1.2 2002/01/28 13:43:32 lipp
045: * Added namespace handling in DelegatingHandler.
046: *
047: * Revision 1.1 2002/01/23 10:42:20 lipp
048: * Added delegating handler.
049: *
050: */
051: package de.danet.an.util.sax;
052:
053: import java.util.HashMap;
054: import java.util.Iterator;
055: import java.util.Map;
056:
057: import org.xml.sax.Attributes;
058: import org.xml.sax.ContentHandler;
059: import org.xml.sax.SAXException;
060:
061: /**
062: * <code>DelegatingHandler</code> waits for predefined elements and,
063: * if encountered, installs associated handlers on the
064: * {@link HandlerStack <code>HandlerStack</code>}.
065: */
066: public class DelegatingHandler extends StackedHandler {
067:
068: private class MatchInfo {
069: private String matchExpr;
070: private Object handler;
071:
072: public MatchInfo(String cond, Object theHandler) {
073: matchExpr = cond;
074: handler = theHandler;
075: }
076:
077: public ContentHandler getHandler()
078: throws InstantiationException, IllegalAccessException {
079: ContentHandler h = null;
080: if (handler instanceof Class) {
081: h = (ContentHandler) ((Class) handler).newInstance();
082: } else {
083: h = (ContentHandler) handler;
084: }
085: if (h instanceof StackedHandler) {
086: ((StackedHandler) h).setStack(getStack());
087: }
088: return h;
089: }
090: }
091:
092: private Map elementHandlerMap = new HashMap();
093: private Map pathHandlerMap = new HashMap();
094: private Map subPathHandlerMap = new HashMap();
095:
096: /**
097: * Adds a new element to be handled. When receiving a
098: * <code>startElement</code> event, the {@link
099: * HandlerStack#currentPath current path} is matched against
100: * <code>searchExpr</code>. If the search expression starts with a
101: * slash, the current path must match exactly. Else, the current
102: * path must end with the search expression.<P>
103: *
104: * Namespaces are represented in the search expression using the
105: * notation "'{' uri '}' localName".<P>
106: *
107: * Search expressions starting with a slash take precedence over
108: * serach expressions without a slash. Both take precedence over
109: * {@link #addHandler(String,Class) simple element matches}.
110: *
111: * @param searchExpr the expression to match.
112: * @param handlerClass the associated handler class.
113: * @throws IllegalStateException if <code>handlerClass</code>
114: * is not derived from {@link StackedHandler <code>StackedHandler</code>}.
115: */
116: public void addHandler(String searchExpr, Class handlerClass)
117: throws IllegalStateException {
118: if (!StackedHandler.class.isAssignableFrom(handlerClass)) {
119: throw new IllegalArgumentException(
120: "Class is not derived from StackedHandler.");
121: }
122: if (searchExpr.startsWith("/")) {
123: pathHandlerMap.put(searchExpr, new MatchInfo(searchExpr,
124: handlerClass));
125: } else {
126: subPathHandlerMap.put(searchExpr, new MatchInfo(searchExpr,
127: handlerClass));
128: }
129: }
130:
131: /**
132: * Adds a new element to be handled. When receiving a
133: * <code>startElement</code> event, the {@link
134: * HandlerStack#currentPath current path} is matched against
135: * <code>searchExpr</code>. If the search expression starts with a
136: * slash, the current path must match exactly. Else, the current
137: * path must end with the search expression.<P>
138: *
139: * Namespaces are represented in the search expression using the
140: * notation "'{' uri '}' localName".<P>
141: *
142: * Search expressions starting with a slash take precedence over
143: * serach expressions without a slash. Both take precedence over
144: * {@link #addHandler(String,Class) simple element matches}.
145: *
146: * @param searchExpr the expression to match.
147: * @param handler the associated handler.
148: */
149: public void addHandler(String searchExpr, ContentHandler handler) {
150: if (searchExpr.startsWith("/")) {
151: pathHandlerMap.put(searchExpr, new MatchInfo(searchExpr,
152: handler));
153: } else {
154: subPathHandlerMap.put(searchExpr, new MatchInfo(searchExpr,
155: handler));
156: }
157: }
158:
159: /**
160: * Adds a new element to be handled. The stream of
161: * <code>startElement</code> events is matched against the
162: * <code>uri</code> and <code>localName</code>.
163: *
164: * @param uri the Namespace URI, or the empty string if the
165: * handler is to match the global namespace.
166: * @param localName the element name to match.
167: * @param handlerClass the associated handler class.
168: * @throws IllegalStateException if <code>handlerClass</code>
169: * is not derived from {@link StackedHandler <code>StackedHandler</code>}.
170: */
171: public void addHandler(String uri, String localName,
172: Class handlerClass) throws IllegalStateException {
173: if (!StackedHandler.class.isAssignableFrom(handlerClass)) {
174: throw new IllegalArgumentException(
175: "Class is not derived from StackedHandler.");
176: }
177: String name = (uri == null || uri.length() == 0) ? localName
178: : "{" + uri + "}" + localName;
179: elementHandlerMap.put(name, new MatchInfo(name, handlerClass));
180: }
181:
182: /**
183: * Adds a new element to be handled. The stream of
184: * <code>startElement</code> events is matched against the
185: * <code>uri</code> and <code>localName</code>.
186: *
187: * @param uri the Namespace URI, or the empty string if the
188: * handler is to match the global namespace.
189: * @param localName the element name to match.
190: * @param handler the associated handler.
191: */
192: public void addHandler(String uri, String localName,
193: ContentHandler handler) {
194: String name = (uri == null || uri.length() == 0) ? localName
195: : "{" + uri + "}" + localName;
196: elementHandlerMap.put(name, new MatchInfo(name, handler));
197: }
198:
199: /**
200: * Checks the uri and local name against the registered handlers
201: * and, if matches, creates a new associated handler and pushes it
202: * on the handler stack.
203: *
204: * @param uri the Namespace URI, or the empty string if the
205: * element has no Namespace URI or if Namespace processing is not
206: * being performed.
207: * @param localName the local name (without prefix), or the empty
208: * string if Namespace processing is not being performed.
209: * @param qName the qualified name (with prefix), or the empty
210: * string if qualified names are not available.
211: * @param atts the attributes attached to the element. If there
212: * are no attributes, it shall be an empty Attributes object.
213: * @throws SAXException any SAX exception, possibly wrapping
214: * another exception.
215: */
216: public void startElement(String uri, String localName,
217: String qName, Attributes atts) throws SAXException {
218: String curPath = currentPath();
219: MatchInfo match = (MatchInfo) pathHandlerMap.get(curPath);
220: if (match == null) {
221: for (Iterator i = subPathHandlerMap.keySet().iterator(); i
222: .hasNext();) {
223: String e = (String) i.next();
224: if (curPath.equals(e) || curPath.endsWith('/' + e)) {
225: match = (MatchInfo) subPathHandlerMap.get(e);
226: break;
227: }
228: }
229: }
230: if (match == null) {
231: String matchExpr = qName;
232: if (uri.length() > 0) {
233: matchExpr = "{" + uri + "}" + localName;
234: }
235: match = (MatchInfo) elementHandlerMap.get(matchExpr);
236: }
237: if (match != null) {
238: try {
239: getStack().push(match.getHandler());
240: } catch (InstantiationException iex) {
241: throw new SAXException(iex);
242: } catch (IllegalAccessException aex) {
243: throw new SAXException(aex);
244: }
245: }
246: }
247:
248: }
|