14fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/****************************************************************
24fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Licensed to the Apache Software Foundation (ASF) under one   *
34fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * or more contributor license agreements.  See the NOTICE file *
44fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * distributed with this work for additional information        *
54fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * regarding copyright ownership.  The ASF licenses this file   *
64fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * to you under the Apache License, Version 2.0 (the            *
74fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * "License"); you may not use this file except in compliance   *
84fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * with the License.  You may obtain a copy of the License at   *
94fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *                                                              *
104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *   http://www.apache.org/licenses/LICENSE-2.0                 *
114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *                                                              *
124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Unless required by applicable law or agreed to in writing,   *
134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * software distributed under the License is distributed on an  *
144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * KIND, either express or implied.  See the License for the    *
164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * specific language governing permissions and limitations      *
174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * under the License.                                           *
184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy ****************************************************************/
194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedypackage org.apache.james.mime4j.field.address;
214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.util.ArrayList;
234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport java.util.Iterator;
244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.decoder.DecoderUtil;
264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTaddr_spec;
274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTaddress;
284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTaddress_list;
294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTangle_addr;
304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTdomain;
314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTgroup_body;
324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTlocal_part;
334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTmailbox;
344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTname_addr;
354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTphrase;
364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.ASTroute;
374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.Node;
384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.SimpleNode;
394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyimport org.apache.james.mime4j.field.address.parser.Token;
404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy/**
424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * Transforms the JJTree-generated abstract syntax tree
434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy * into a graph of org.apache.james.mime4j.field.address objects.
444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy *
464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy */
474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedyclass Builder {
484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private static Builder singleton = new Builder();
504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	public static Builder getInstance() {
524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		return singleton;
534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	public AddressList buildAddressList(ASTaddress_list node) {
584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ArrayList<Address> list = new ArrayList<Address>();
594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);
614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			Address address = buildAddress(childNode);
624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			list.add(address);
634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		return new AddressList(list, true);
654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private Address buildAddress(ASTaddress node) {
684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ChildNodeIterator it = new ChildNodeIterator(node);
694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		Node n = it.nextNode();
704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		if (n instanceof ASTaddr_spec) {
714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return buildAddrSpec((ASTaddr_spec)n);
724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else if (n instanceof ASTangle_addr) {
744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return buildAngleAddr((ASTangle_addr)n);
754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else if (n instanceof ASTphrase) {
774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			String name = buildString((ASTphrase)n, false);
784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			Node n2 = it.nextNode();
794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			if (n2 instanceof ASTgroup_body) {
804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				return new Group(name, buildGroupBody((ASTgroup_body)n2));
814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			}
824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			else if (n2 instanceof ASTangle_addr) {
834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy                name = DecoderUtil.decodeEncodedWords(name);
844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2));
854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			}
864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			else {
874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				throw new IllegalStateException();
884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			}
894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else {
914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			throw new IllegalStateException();
924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private MailboxList buildGroupBody(ASTgroup_body node) {
984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ArrayList<Address> results = new ArrayList<Address>();
994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ChildNodeIterator it = new ChildNodeIterator(node);
1004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		while (it.hasNext()) {
1014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			Node n = it.nextNode();
1024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			if (n instanceof ASTmailbox)
1034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				results.add(buildMailbox((ASTmailbox)n));
1044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			else
1054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				throw new IllegalStateException();
1064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		return new MailboxList(results, true);
1084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
1094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private Mailbox buildMailbox(ASTmailbox node) {
1114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ChildNodeIterator it = new ChildNodeIterator(node);
1124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		Node n = it.nextNode();
1134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		if (n instanceof ASTaddr_spec) {
1144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return buildAddrSpec((ASTaddr_spec)n);
1154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else if (n instanceof ASTangle_addr) {
1174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return buildAngleAddr((ASTangle_addr)n);
1184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else if (n instanceof ASTname_addr) {
1204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return buildNameAddr((ASTname_addr)n);
1214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else {
1234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			throw new IllegalStateException();
1244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
1264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private NamedMailbox buildNameAddr(ASTname_addr node) {
1284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ChildNodeIterator it = new ChildNodeIterator(node);
1294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		Node n = it.nextNode();
1304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		String name;
1314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		if (n instanceof ASTphrase) {
1324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			name = buildString((ASTphrase)n, false);
1334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else {
1354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			throw new IllegalStateException();
1364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		n = it.nextNode();
1394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		if (n instanceof ASTangle_addr) {
1404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy            name = DecoderUtil.decodeEncodedWords(name);
1414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n));
1424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else {
1444fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			throw new IllegalStateException();
1454fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1464fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
1474fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1484fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private Mailbox buildAngleAddr(ASTangle_addr node) {
1494fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ChildNodeIterator it = new ChildNodeIterator(node);
1504fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		DomainList route = null;
1514fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		Node n = it.nextNode();
1524fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		if (n instanceof ASTroute) {
1534fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			route = buildRoute((ASTroute)n);
1544fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			n = it.nextNode();
1554fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1564fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else if (n instanceof ASTaddr_spec)
1574fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			; // do nothing
1584fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else
1594fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			throw new IllegalStateException();
1604fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1614fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		if (n instanceof ASTaddr_spec)
1624fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return buildAddrSpec(route, (ASTaddr_spec)n);
1634fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		else
1644fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			throw new IllegalStateException();
1654fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
1664fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1674fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private DomainList buildRoute(ASTroute node) {
1684fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ArrayList<String> results = new ArrayList<String>(node.jjtGetNumChildren());
1694fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ChildNodeIterator it = new ChildNodeIterator(node);
1704fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		while (it.hasNext()) {
1714fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			Node n = it.nextNode();
1724fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			if (n instanceof ASTdomain)
1734fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				results.add(buildString((ASTdomain)n, true));
1744fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			else
1754fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				throw new IllegalStateException();
1764fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
1774fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		return new DomainList(results, true);
1784fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
1794fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1804fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private Mailbox buildAddrSpec(ASTaddr_spec node) {
1814fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		return buildAddrSpec(null, node);
1824fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
1834fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {
1844fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		ChildNodeIterator it = new ChildNodeIterator(node);
1854fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		String localPart = buildString((ASTlocal_part)it.nextNode(), true);
1864fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		String domain = buildString((ASTdomain)it.nextNode(), true);
1874fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		return new Mailbox(route, localPart, domain);
1884fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
1894fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1904fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1914fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private String buildString(SimpleNode node, boolean stripSpaces) {
1924fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		Token head = node.firstToken;
1934fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		Token tail = node.lastToken;
1944fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		StringBuffer out = new StringBuffer();
1954fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
1964fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		while (head != tail) {
1974fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			out.append(head.image);
1984fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			head = head.next;
1994fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			if (!stripSpaces)
2004fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy				addSpecials(out, head.specialToken);
2014fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
2024fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		out.append(tail.image);
2034fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2044fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		return out.toString();
2054fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
2064fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2074fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private void addSpecials(StringBuffer out, Token specialToken) {
2084fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		if (specialToken != null) {
2094fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			addSpecials(out, specialToken.specialToken);
2104fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			out.append(specialToken.image);
2114fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
2124fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
2134fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2144fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	private static class ChildNodeIterator implements Iterator<Node> {
2154fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2164fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		private SimpleNode simpleNode;
2174fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		private int index;
2184fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		private int len;
2194fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2204fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		public ChildNodeIterator(SimpleNode simpleNode) {
2214fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			this.simpleNode = simpleNode;
2224fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			this.len = simpleNode.jjtGetNumChildren();
2234fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			this.index = 0;
2244fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
2254fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2264fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		public void remove() {
2274fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			throw new UnsupportedOperationException();
2284fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
2294fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2304fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		public boolean hasNext() {
2314fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return index < len;
2324fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
2334fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2344fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		public Node next() {
2354fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return nextNode();
2364fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
2374fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2384fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		public Node nextNode() {
2394fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy			return simpleNode.jjtGetChild(index++);
2404fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy		}
2414fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy
2424fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy	}
2434fa0a3295bcacbdcd6a9e7709cf17aa5adb90356Scott Kennedy}
244