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