Builder.java revision 8978aac1977408b05e386ae846c30920c7faa0a6
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.*;
27import org.apache.james.mime4j.field.address.parser.ASTaddr_spec;
28import org.apache.james.mime4j.field.address.parser.ASTaddress;
29import org.apache.james.mime4j.field.address.parser.ASTaddress_list;
30import org.apache.james.mime4j.field.address.parser.ASTangle_addr;
31import org.apache.james.mime4j.field.address.parser.ASTdomain;
32import org.apache.james.mime4j.field.address.parser.ASTgroup_body;
33import org.apache.james.mime4j.field.address.parser.ASTlocal_part;
34import org.apache.james.mime4j.field.address.parser.ASTmailbox;
35import org.apache.james.mime4j.field.address.parser.ASTname_addr;
36import org.apache.james.mime4j.field.address.parser.ASTphrase;
37import org.apache.james.mime4j.field.address.parser.ASTroute;
38import org.apache.james.mime4j.field.address.parser.Node;
39import org.apache.james.mime4j.field.address.parser.SimpleNode;
40import org.apache.james.mime4j.field.address.parser.Token;
41
42/**
43 * Transforms the JJTree-generated abstract syntax tree
44 * into a graph of org.apache.james.mime4j.field.address objects.
45 *
46 *
47 */
48class Builder {
49
50	private static Builder singleton = new Builder();
51
52	public static Builder getInstance() {
53		return singleton;
54	}
55
56
57
58	public AddressList buildAddressList(ASTaddress_list node) {
59		ArrayList list = new ArrayList();
60		for (int i = 0; i < node.jjtGetNumChildren(); i++) {
61			ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);
62			Address address = buildAddress(childNode);
63			list.add(address);
64		}
65		return new AddressList(list, true);
66	}
67
68	private Address buildAddress(ASTaddress node) {
69		ChildNodeIterator it = new ChildNodeIterator(node);
70		Node n = it.nextNode();
71		if (n instanceof ASTaddr_spec) {
72			return buildAddrSpec((ASTaddr_spec)n);
73		}
74		else if (n instanceof ASTangle_addr) {
75			return buildAngleAddr((ASTangle_addr)n);
76		}
77		else if (n instanceof ASTphrase) {
78			String name = buildString((ASTphrase)n, false);
79			Node n2 = it.nextNode();
80			if (n2 instanceof ASTgroup_body) {
81				return new Group(name, buildGroupBody((ASTgroup_body)n2));
82			}
83			else if (n2 instanceof ASTangle_addr) {
84                name = DecoderUtil.decodeEncodedWords(name);
85				return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2));
86			}
87			else {
88				throw new IllegalStateException();
89			}
90		}
91		else {
92			throw new IllegalStateException();
93		}
94	}
95
96
97
98	private MailboxList buildGroupBody(ASTgroup_body node) {
99		ArrayList results = new ArrayList();
100		ChildNodeIterator it = new ChildNodeIterator(node);
101		while (it.hasNext()) {
102			Node n = it.nextNode();
103			if (n instanceof ASTmailbox)
104				results.add(buildMailbox((ASTmailbox)n));
105			else
106				throw new IllegalStateException();
107		}
108		return new MailboxList(results, true);
109	}
110
111	private Mailbox buildMailbox(ASTmailbox node) {
112		ChildNodeIterator it = new ChildNodeIterator(node);
113		Node n = it.nextNode();
114		if (n instanceof ASTaddr_spec) {
115			return buildAddrSpec((ASTaddr_spec)n);
116		}
117		else if (n instanceof ASTangle_addr) {
118			return buildAngleAddr((ASTangle_addr)n);
119		}
120		else if (n instanceof ASTname_addr) {
121			return buildNameAddr((ASTname_addr)n);
122		}
123		else {
124			throw new IllegalStateException();
125		}
126	}
127
128	private NamedMailbox buildNameAddr(ASTname_addr node) {
129		ChildNodeIterator it = new ChildNodeIterator(node);
130		Node n = it.nextNode();
131		String name;
132		if (n instanceof ASTphrase) {
133			name = buildString((ASTphrase)n, false);
134		}
135		else {
136			throw new IllegalStateException();
137		}
138
139		n = it.nextNode();
140		if (n instanceof ASTangle_addr) {
141            name = DecoderUtil.decodeEncodedWords(name);
142			return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n));
143		}
144		else {
145			throw new IllegalStateException();
146		}
147	}
148
149	private Mailbox buildAngleAddr(ASTangle_addr node) {
150		ChildNodeIterator it = new ChildNodeIterator(node);
151		DomainList route = null;
152		Node n = it.nextNode();
153		if (n instanceof ASTroute) {
154			route = buildRoute((ASTroute)n);
155			n = it.nextNode();
156		}
157		else if (n instanceof ASTaddr_spec)
158			; // do nothing
159		else
160			throw new IllegalStateException();
161
162		if (n instanceof ASTaddr_spec)
163			return buildAddrSpec(route, (ASTaddr_spec)n);
164		else
165			throw new IllegalStateException();
166	}
167
168	private DomainList buildRoute(ASTroute node) {
169		ArrayList results = new ArrayList(node.jjtGetNumChildren());
170		ChildNodeIterator it = new ChildNodeIterator(node);
171		while (it.hasNext()) {
172			Node n = it.nextNode();
173			if (n instanceof ASTdomain)
174				results.add(buildString((ASTdomain)n, true));
175			else
176				throw new IllegalStateException();
177		}
178		return new DomainList(results, true);
179	}
180
181	private Mailbox buildAddrSpec(ASTaddr_spec node) {
182		return buildAddrSpec(null, node);
183	}
184	private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {
185		ChildNodeIterator it = new ChildNodeIterator(node);
186		String localPart = buildString((ASTlocal_part)it.nextNode(), true);
187		String domain = buildString((ASTdomain)it.nextNode(), true);
188		return new Mailbox(route, localPart, domain);
189	}
190
191
192	private String buildString(SimpleNode node, boolean stripSpaces) {
193		Token head = node.firstToken;
194		Token tail = node.lastToken;
195		StringBuffer out = new StringBuffer();
196
197		while (head != tail) {
198			out.append(head.image);
199			head = head.next;
200			if (!stripSpaces)
201				addSpecials(out, head.specialToken);
202		}
203		out.append(tail.image);
204
205		return out.toString();
206	}
207
208	private void addSpecials(StringBuffer out, Token specialToken) {
209		if (specialToken != null) {
210			addSpecials(out, specialToken.specialToken);
211			out.append(specialToken.image);
212		}
213	}
214
215	private static class ChildNodeIterator implements Iterator {
216
217		private SimpleNode simpleNode;
218		private int index;
219		private int len;
220
221		public ChildNodeIterator(SimpleNode simpleNode) {
222			this.simpleNode = simpleNode;
223			this.len = simpleNode.jjtGetNumChildren();
224			this.index = 0;
225		}
226
227		public void remove() {
228			throw new UnsupportedOperationException();
229		}
230
231		public boolean hasNext() {
232			return index < len;
233		}
234
235		public Object next() {
236			return nextNode();
237		}
238
239		public Node nextNode() {
240			return simpleNode.jjtGetChild(index++);
241		}
242
243	}
244}
245