001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.xsom.impl.parser.state;
027:
028: import org.xml.sax.Attributes;
029: import org.xml.sax.SAXException;
030:
031: /**
032: * Dispatches incoming events into sub handlers appropriately
033: * so that the interleaving semantics will be correctly realized.
034: *
035: * @author Kohsuke Kawaguchi (kk@kohsuke.org)
036: */
037: public abstract class NGCCInterleaveFilter implements NGCCEventSource,
038: NGCCEventReceiver {
039: protected NGCCInterleaveFilter(NGCCHandler parent, int cookie) {
040: this ._parent = parent;
041: this ._cookie = cookie;
042: }
043:
044: protected void setHandlers(NGCCEventReceiver[] receivers) {
045: this ._receivers = receivers;
046: }
047:
048: /** event receiverse. */
049: protected NGCCEventReceiver[] _receivers;
050:
051: public int replace(NGCCEventReceiver oldHandler,
052: NGCCEventReceiver newHandler) {
053: for (int i = 0; i < _receivers.length; i++)
054: if (_receivers[i] == oldHandler) {
055: _receivers[i] = newHandler;
056: return i;
057: }
058: throw new InternalError(); // a bug in RelaxNGCC.
059: }
060:
061: /** Parent handler. */
062: private final NGCCHandler _parent;
063: /** Cookie given by the parent. */
064: private final int _cookie;
065:
066: //
067: //
068: // event handler
069: //
070: //
071: /**
072: * Receiver that is being locked and therefore receives all the events.
073: * <pre><xmp>
074: * <interleave>
075: * <element name="foo"/>
076: * <element name="bar">
077: * <element name="foo"/>
078: * </element>
079: * </interlaeve>
080: * </xmp></pre>
081: * When processing inside the bar element, this receiver is
082: * "locked" so that it can correctly receive its child foo element.
083: */
084: private int lockedReceiver;
085: /**
086: * Nest level. Lock will be release when the lockCount becomes 0.
087: */
088: private int lockCount = 0;
089:
090: public void enterElement(String uri, String localName,
091: String qname, Attributes atts) throws SAXException {
092:
093: if (isJoining)
094: return; // ignore any token if we are joining. See joinByXXXX.
095:
096: if (lockCount++ == 0) {
097: lockedReceiver = findReceiverOfElement(uri, localName);
098: if (lockedReceiver == -1) {
099: // we can't process this token. join.
100: joinByEnterElement(null, uri, localName, qname, atts);
101: return;
102: }
103: }
104:
105: _receivers[lockedReceiver].enterElement(uri, localName, qname,
106: atts);
107: }
108:
109: public void leaveElement(String uri, String localName, String qname)
110: throws SAXException {
111: if (isJoining)
112: return; // ignore any token if we are joining. See joinByXXXX.
113:
114: if (lockCount-- == 0)
115: joinByLeaveElement(null, uri, localName, qname);
116: else
117: _receivers[lockedReceiver].leaveElement(uri, localName,
118: qname);
119: }
120:
121: public void enterAttribute(String uri, String localName,
122: String qname) throws SAXException {
123: if (isJoining)
124: return; // ignore any token if we are joining. See joinByXXXX.
125:
126: if (lockCount++ == 0) {
127: lockedReceiver = findReceiverOfAttribute(uri, localName);
128: if (lockedReceiver == -1) {
129: // we can't process this token. join.
130: joinByEnterAttribute(null, uri, localName, qname);
131: return;
132: }
133: }
134:
135: _receivers[lockedReceiver]
136: .enterAttribute(uri, localName, qname);
137: }
138:
139: public void leaveAttribute(String uri, String localName,
140: String qname) throws SAXException {
141: if (isJoining)
142: return; // ignore any token if we are joining. See joinByXXXX.
143:
144: if (lockCount-- == 0)
145: joinByLeaveAttribute(null, uri, localName, qname);
146: else
147: _receivers[lockedReceiver].leaveAttribute(uri, localName,
148: qname);
149: }
150:
151: public void text(String value) throws SAXException {
152: if (isJoining)
153: return; // ignore any token if we are joining. See joinByXXXX.
154:
155: if (lockCount != 0)
156: _receivers[lockedReceiver].text(value);
157: else {
158: int receiver = findReceiverOfText();
159: if (receiver != -1)
160: _receivers[receiver].text(value);
161: else
162: joinByText(null, value);
163: }
164: }
165:
166: /**
167: * Implemented by the generated code to determine the handler
168: * that can receive the given element.
169: *
170: * @return
171: * Thread ID of the receiver that can handle this event,
172: * or -1 if none.
173: */
174: protected abstract int findReceiverOfElement(String uri,
175: String local);
176:
177: /**
178: * Returns the handler that can receive the given attribute, or null.
179: */
180: protected abstract int findReceiverOfAttribute(String uri,
181: String local);
182:
183: /**
184: * Returns the handler that can receive text events, or null.
185: */
186: protected abstract int findReceiverOfText();
187:
188: //
189: //
190: // join method
191: //
192: //
193:
194: /**
195: * Set to true when this handler is in the process of
196: * joining all branches.
197: */
198: private boolean isJoining = false;
199:
200: /**
201: * Joins all the child receivers.
202: *
203: * <p>
204: * This method is called by a child receiver when it sees
205: * something that it cannot handle, or by this object itself
206: * when it sees an event that it can't process.
207: *
208: * <p>
209: * This method forces children to move to its final state,
210: * then revert to the parent.
211: *
212: * @param source
213: * If this method is called by one of the child receivers,
214: * the receiver object. If this method is called by itself,
215: * null.
216: */
217: public void joinByEnterElement(NGCCEventReceiver source,
218: String uri, String local, String qname, Attributes atts)
219: throws SAXException {
220:
221: if (isJoining)
222: return; // we are already in the process of joining. ignore.
223: isJoining = true;
224:
225: // send special token to the rest of the branches.
226: // these branches don't understand this token, so they will
227: // try to move to a final state and send the token back to us,
228: // which this object will ignore (because isJoining==true)
229: // Otherwise branches will find an error.
230: for (int i = 0; i < _receivers.length; i++)
231: if (_receivers[i] != source)
232: _receivers[i].enterElement(uri, local, qname, atts);
233:
234: // revert to the parent
235: _parent._source.replace(this , _parent);
236: _parent.onChildCompleted(null, _cookie, true);
237: // send this event to the parent
238: _parent.enterElement(uri, local, qname, atts);
239: }
240:
241: public void joinByLeaveElement(NGCCEventReceiver source,
242: String uri, String local, String qname) throws SAXException {
243:
244: if (isJoining)
245: return; // we are already in the process of joining. ignore.
246: isJoining = true;
247:
248: // send special token to the rest of the branches.
249: // these branches don't understand this token, so they will
250: // try to move to a final state and send the token back to us,
251: // which this object will ignore (because isJoining==true)
252: // Otherwise branches will find an error.
253: for (int i = 0; i < _receivers.length; i++)
254: if (_receivers[i] != source)
255: _receivers[i].leaveElement(uri, local, qname);
256:
257: // revert to the parent
258: _parent._source.replace(this , _parent);
259: _parent.onChildCompleted(null, _cookie, true);
260: // send this event to the parent
261: _parent.leaveElement(uri, local, qname);
262: }
263:
264: public void joinByEnterAttribute(NGCCEventReceiver source,
265: String uri, String local, String qname) throws SAXException {
266:
267: if (isJoining)
268: return; // we are already in the process of joining. ignore.
269: isJoining = true;
270:
271: // send special token to the rest of the branches.
272: // these branches don't understand this token, so they will
273: // try to move to a final state and send the token back to us,
274: // which this object will ignore (because isJoining==true)
275: // Otherwise branches will find an error.
276: for (int i = 0; i < _receivers.length; i++)
277: if (_receivers[i] != source)
278: _receivers[i].enterAttribute(uri, local, qname);
279:
280: // revert to the parent
281: _parent._source.replace(this , _parent);
282: _parent.onChildCompleted(null, _cookie, true);
283: // send this event to the parent
284: _parent.enterAttribute(uri, local, qname);
285: }
286:
287: public void joinByLeaveAttribute(NGCCEventReceiver source,
288: String uri, String local, String qname) throws SAXException {
289:
290: if (isJoining)
291: return; // we are already in the process of joining. ignore.
292: isJoining = true;
293:
294: // send special token to the rest of the branches.
295: // these branches don't understand this token, so they will
296: // try to move to a final state and send the token back to us,
297: // which this object will ignore (because isJoining==true)
298: // Otherwise branches will find an error.
299: for (int i = 0; i < _receivers.length; i++)
300: if (_receivers[i] != source)
301: _receivers[i].leaveAttribute(uri, local, qname);
302:
303: // revert to the parent
304: _parent._source.replace(this , _parent);
305: _parent.onChildCompleted(null, _cookie, true);
306: // send this event to the parent
307: _parent.leaveAttribute(uri, local, qname);
308: }
309:
310: public void joinByText(NGCCEventReceiver source, String value)
311: throws SAXException {
312:
313: if (isJoining)
314: return; // we are already in the process of joining. ignore.
315: isJoining = true;
316:
317: // send special token to the rest of the branches.
318: // these branches don't understand this token, so they will
319: // try to move to a final state and send the token back to us,
320: // which this object will ignore (because isJoining==true)
321: // Otherwise branches will find an error.
322: for (int i = 0; i < _receivers.length; i++)
323: if (_receivers[i] != source)
324: _receivers[i].text(value);
325:
326: // revert to the parent
327: _parent._source.replace(this , _parent);
328: _parent.onChildCompleted(null, _cookie, true);
329: // send this event to the parent
330: _parent.text(value);
331: }
332:
333: //
334: //
335: // event dispatching methods
336: //
337: //
338:
339: public void sendEnterAttribute(int threadId, String uri,
340: String local, String qname) throws SAXException {
341:
342: _receivers[threadId].enterAttribute(uri, local, qname);
343: }
344:
345: public void sendEnterElement(int threadId, String uri,
346: String local, String qname, Attributes atts)
347: throws SAXException {
348:
349: _receivers[threadId].enterElement(uri, local, qname, atts);
350: }
351:
352: public void sendLeaveAttribute(int threadId, String uri,
353: String local, String qname) throws SAXException {
354:
355: _receivers[threadId].leaveAttribute(uri, local, qname);
356: }
357:
358: public void sendLeaveElement(int threadId, String uri,
359: String local, String qname) throws SAXException {
360:
361: _receivers[threadId].leaveElement(uri, local, qname);
362: }
363:
364: public void sendText(int threadId, String value)
365: throws SAXException {
366: _receivers[threadId].text(value);
367: }
368:
369: }
|