Builder.java revision a07f2ae0b18964aa15e218e8b6be8be24e5c9f46
1/****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one   *
3 * or more contributor license agreements.  See the NOTICE file *
4 * distributed with this work for additional information        *
5 * regarding copyright ownership.  The ASF licenses this file   *
6 * to you under the Apache License, Version 2.0 (the            *
7 * "License"); you may not use this file except in compliance   *
8 * with the License.  You may obtain a copy of the License at   *
9 *                                                              *
10 *   http://www.apache.org/licenses/LICENSE-2.0                 *
11 *                                                              *
12 * Unless required by applicable law or agreed to in writing,   *
13 * software distributed under the License is distributed on an  *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15 * KIND, either express or implied.  See the License for the    *
16 * specific language governing permissions and limitations      *
17 * under the License.                                           *
18 ****************************************************************/
19
20package org.apache.james.mime4j.field.address;
21
22import java.util.ArrayList;
23import java.util.Iterator;
24
25import org.apache.james.mime4j.decoder.DecoderUtil;
26import org.apache.james.mime4j.field.address.parser.ASTaddr_spec;
27import org.apache.james.mime4j.field.address.parser.ASTaddress;
28import org.apache.james.mime4j.field.address.parser.ASTaddress_list;
29import org.apache.james.mime4j.field.address.parser.ASTangle_addr;
30import org.apache.james.mime4j.field.address.parser.ASTdomain;
31import org.apache.james.mime4j.field.address.parser.ASTgroup_body;
32import org.apache.james.mime4j.field.address.parser.ASTlocal_part;
33import org.apache.james.mime4j.field.address.parser.ASTmailbox;
34import org.apache.james.mime4j.field.address.parser.ASTname_addr;
35import org.apache.james.mime4j.field.address.parser.ASTphrase;
36import org.apache.james.mime4j.field.address.parser.ASTroute;
37import org.apache.james.mime4j.field.address.parser.Node;
38import org.apache.james.mime4j.field.address.parser.SimpleNode;
39import org.apache.james.mime4j.field.address.parser.Token;
40
41/**
42 * Transforms the JJTree-generated abstract syntax tree
43 * into a graph of org.apache.james.mime4j.field.address objects.
44 *
45 *
46 */
47class Builder {
48
49	private static Builder singleton = new Builder();
50
51	public static Builder getInstance() {
52		return singleton;
53	}
54
55
56
57	public AddressList buildAddressList(ASTaddress_list node) {
58		ArrayList<Address> list = new ArrayList<Address>();
59		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
60			ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);
61			Address address = buildAddress(childNode);
62			list.add(address);
63		}
64		return new AddressList(list, true);
65	}
66
67	private Address buildAddress(ASTaddress node) {
68		ChildNodeIterator it = new ChildNodeIterator(node);
69		Node n = it.nextNode();
70		if (n instanceof ASTaddr_spec) {
71			return buildAddrSpec((ASTaddr_spec)n);
72		}
73		else if (n instanceof ASTangle_addr) {
74			return buildAngleAddr((ASTangle_addr)n);
75		}
76		else if (n instanceof ASTphrase) {
77			String name = buildString((ASTphrase)n, false);
78			Node n2 = it.nextNode();
79			if (n2 instanceof ASTgroup_body) {
80				return new Group(name, buildGroupBody((ASTgroup_body)n2));
81			}
82			else if (n2 instanceof ASTangle_addr) {
83                name = DecoderUtil.decodeEncodedWords(name);
84				return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2));
85			}
86			else {
87				throw new IllegalStateException();
88			}
89		}
90		else {
91			throw new IllegalStateException();
92		}
93	}
94
95
96
97	private MailboxList buildGroupBody(ASTgroup_body node) {
98		ArrayList<Address> results = new ArrayList<Address>();
99		ChildNodeIterator it = new ChildNodeIterator(node);
100		while (it.hasNext()) {
101			Node n = it.nextNode();
102			if (n instanceof ASTmailbox)
103				results.add(buildMailbox((ASTmailbox)n));
104			else
105				throw new IllegalStateException();
106		}
107		return new MailboxList(results, true);
108	}
109
110	private Mailbox buildMailbox(ASTmailbox node) {
111		ChildNodeIterator it = new ChildNodeIterator(node);
112		Node n = it.nextNode();
113		if (n instanceof ASTaddr_spec) {
114			return buildAddrSpec((ASTaddr_spec)n);
115		}
116		else if (n instanceof ASTangle_addr) {
117			return buildAngleAddr((ASTangle_addr)n);
118		}
119		else if (n instanceof ASTname_addr) {
120			return buildNameAddr((ASTname_addr)n);
121		}
122		else {
123			throw new IllegalStateException();
124		}
125	}
126
127	private NamedMailbox buildNameAddr(ASTname_addr node) {
128		ChildNodeIterator it = new ChildNodeIterator(node);
129		Node n = it.nextNode();
130		String name;
131		if (n instanceof ASTphrase) {
132			name = buildString((ASTphrase)n, false);
133		}
134		else {
135			throw new IllegalStateException();
136		}
137
138		n = it.nextNode();
139		if (n instanceof ASTangle_addr) {
140            name = DecoderUtil.decodeEncodedWords(name);
141			return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n));
142		}
143		else {
144			throw new IllegalStateException();
145		}
146	}
147
148	private Mailbox buildAngleAddr(ASTangle_addr node) {
149		ChildNodeIterator it = new ChildNodeIterator(node);
150		DomainList route = null;
151		Node n = it.nextNode();
152		if (n instanceof ASTroute) {
153			route = buildRoute((ASTroute)n);
154			n = it.nextNode();
155		}
156		else if (n instanceof ASTaddr_spec)
157			; // do nothing
158		else
159			throw new IllegalStateException();
160
161		if (n instanceof ASTaddr_spec)
162			return buildAddrSpec(route, (ASTaddr_spec)n);
163		else
164			throw new IllegalStateException();
165	}
166
167	private DomainList buildRoute(ASTroute node) {
168		ArrayList<String> results = new ArrayList<String>(node.jjtGetNumChildren());
169		ChildNodeIterator it = new ChildNodeIterator(node);
170		while (it.hasNext()) {
171			Node n = it.nextNode();
172			if (n instanceof ASTdomain)
173				results.add(buildString((ASTdomain)n, true));
174			else
175				throw new IllegalStateException();
176		}
177		return new DomainList(results, true);
178	}
179
180	private Mailbox buildAddrSpec(ASTaddr_spec node) {
181		return buildAddrSpec(null, node);
182	}
183	private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {
184		ChildNodeIterator it = new ChildNodeIterator(node);
185		String localPart = buildString((ASTlocal_part)it.nextNode(), true);
186		String domain = buildString((ASTdomain)it.nextNode(), true);
187		return new Mailbox(route, localPart, domain);
188	}
189
190
191	private String buildString(SimpleNode node, boolean stripSpaces) {
192		Token head = node.firstToken;
193		Token tail = node.lastToken;
194		StringBuffer out = new StringBuffer();
195
196		while (head != tail) {
197			out.append(head.image);
198			head = head.next;
199			if (!stripSpaces)
200				addSpecials(out, head.specialToken);
201		}
202		out.append(tail.image);
203
204		return out.toString();
205	}
206
207	private void addSpecials(StringBuffer out, Token specialToken) {
208		if (specialToken != null) {
209			addSpecials(out, specialToken.specialToken);
210			out.append(specialToken.image);
211		}
212	}
213
214	private static class ChildNodeIterator implements Iterator<Node> {
215
216		private SimpleNode simpleNode;
217		private int index;
218		private int len;
219
220		public ChildNodeIterator(SimpleNode simpleNode) {
221			this.simpleNode = simpleNode;
222			this.len = simpleNode.jjtGetNumChildren();
223			this.index = 0;
224		}
225
226		public void remove() {
227			throw new UnsupportedOperationException();
228		}
229
230		public boolean hasNext() {
231			return index < len;
232		}
233
234		public Node next() {
235			return nextNode();
236		}
237
238		public Node nextNode() {
239			return simpleNode.jjtGetChild(index++);
240		}
241
242	}
243}
244