View Javadoc

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