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.jsieve.parser.address;
21  
22  import java.io.Reader;
23  import java.io.StringReader;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.Collections;
27  
28  import org.apache.jsieve.mail.MailAdapter;
29  import org.apache.jsieve.mail.MailAdapter.Address;
30  import org.apache.jsieve.parser.generated.address.ASTaddr_spec;
31  import org.apache.jsieve.parser.generated.address.ASTaddress_list;
32  import org.apache.jsieve.parser.generated.address.ASTdomain;
33  import org.apache.jsieve.parser.generated.address.ASTlocal_part;
34  import org.apache.jsieve.parser.generated.address.AddressListParser;
35  import org.apache.jsieve.parser.generated.address.ParseException;
36  import org.apache.jsieve.parser.generated.address.Token;
37  
38  /**
39   * Builds <code>MailAdapter.Address</code> from address lists. Note that
40   * implementators of {@link MailAdapter} are recommended to use a fully featured
41   * and maintained parser such as <a href='http://james.apache.org/mime4j'>Apache
42   * Mime4J</a>. This implementation is based on Mime4J code but is intended only
43   * for internal and demonstration purposes. It is not actively maintained.
44   */
45  public class SieveAddressBuilder {
46  
47      private static final Address[] EMPTY_ADDRESSES = {};
48  
49      private final Collection<Address> addresses;
50  
51      private final Worker worker;
52  
53      public SieveAddressBuilder() {
54          addresses = Collections.synchronizedCollection(new ArrayList<Address>());
55          worker = new Worker();
56      }
57  
58      /**
59       * Clears the addresses currently accumulated.
60       */
61      public void reset() {
62          addresses.clear();
63      }
64  
65      /**
66       * Adds addresses in the given list.
67       * 
68       * @param addressList
69       *            RFC822 address list
70       * @throws ParseException
71       */
72      public void addAddresses(String addressList) throws ParseException {
73          final StringReader reader = new StringReader(addressList);
74          worker.addAddressses(reader, addresses);
75      }
76  
77      /**
78       * Gets addresses currently accumulated by calls to
79       * {@link #addAddresses(String)} since the last call to {@link #reset}.
80       * 
81       * @return addresses, not null
82       */
83      public Address[] getAddresses() {
84          final Address[] results = (Address[]) addresses.toArray(EMPTY_ADDRESSES);
85          return results;
86      }
87  
88      /**
89       * Performs the actual work. Factored into an inner class so that the build
90       * interface is clean.
91       */
92      private final class Worker extends BaseAddressListVisitor {
93  
94          public void addAddressses(final Reader reader, final Collection results)
95                  throws ParseException {
96              AddressListParser parser = new AddressListParser(reader);
97              ASTaddress_list root = parser.parse();
98              root.childrenAccept(this, results);
99          }
100 
101         @SuppressWarnings("unchecked")
102         public Object visit(ASTaddr_spec node, Object data) {
103             final AddressBean address = new AddressBean();
104             node.childrenAccept(this, address);
105             if (data instanceof Collection) {
106                 final Collection collection = (Collection) data;
107                 collection.add(address);
108             }
109             return data;
110         }
111 
112         public Object visit(final ASTdomain node, final Object data) {
113             if (data instanceof AddressBean) {
114                 final AddressBean address = (AddressBean) data;
115                 final String domain = contents(node);
116                 address.setDomain(domain);
117             }
118             return data;
119         }
120 
121         public Object visit(ASTlocal_part node, Object data) {
122             if (data instanceof AddressBean) {
123                 final AddressBean address = (AddressBean) data;
124                 final String localPart = contents(node);
125                 address.setLocalPart(localPart);
126             }
127             return data;
128         }
129 
130         private String contents(AddressNode node) {
131             StringBuffer buffer = new StringBuffer(32);
132             Token last = node.lastToken;
133             Token next = node.firstToken;
134             while (next != last) {
135                 buffer.append(next.image);
136                 next = next.next;
137             }
138             buffer.append(last.image);
139             return buffer.toString();
140         }
141     }
142 
143     /**
144      * Bean based address implementation.
145      */
146     private final class AddressBean implements Address {
147         private String localPart;
148 
149         private String domain;
150 
151         public AddressBean() {
152             localPart = "";
153             domain = "";
154         }
155 
156         public String getDomain() {
157             return domain;
158         }
159 
160         public void setDomain(String domain) {
161             this.domain = domain;
162         }
163 
164         public String getLocalPart() {
165             return localPart;
166         }
167 
168         public void setLocalPart(String localPart) {
169             this.localPart = localPart;
170         }
171     }
172 }