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.jspf.policies.local;
21  
22  import org.apache.james.jspf.core.Logger;
23  import org.apache.james.jspf.core.SPF1Record;
24  import org.apache.james.jspf.core.SPFRecordParser;
25  import org.apache.james.jspf.core.exceptions.NeutralException;
26  import org.apache.james.jspf.core.exceptions.NoneException;
27  import org.apache.james.jspf.core.exceptions.PermErrorException;
28  import org.apache.james.jspf.core.exceptions.SPFResultException;
29  import org.apache.james.jspf.core.exceptions.TempErrorException;
30  import org.apache.james.jspf.policies.PolicyPostFilter;
31  
32  import java.util.Collections;
33  import java.util.HashMap;
34  import java.util.Iterator;
35  import java.util.Map;
36  
37  /**
38   * Class to support Fallback feature
39   */
40  public class FallbackPolicy implements PolicyPostFilter {
41  
42      private Map entryMap;
43  
44      private SPFRecordParser parser;
45  
46      private Logger log;
47  
48      public FallbackPolicy(Logger log, SPFRecordParser parser) {
49          this.log = log;
50          entryMap = Collections.synchronizedMap(new HashMap());
51          this.parser = parser;
52      }
53  
54      /**
55       * Add a entry.
56       * 
57       * @param rawHost
58       *            the host or ipaddress for which the entry should be added.
59       * @param rawSpfRecord
60       *            the spfRecord to add
61       * @throws IllegalArgumentException
62       *             get thrown on invalid spfRecord
63       */
64      public void addEntry(String rawHost, String rawSpfRecord)
65              throws IllegalArgumentException {
66          String host;
67          try {
68              log.debug("Start parsing SPF-Record: " + rawSpfRecord);
69              SPF1Record spfRecord = parser.parse(rawSpfRecord);
70              if (rawHost.startsWith("*")) {
71                  host = rawHost.substring(1);
72                  log.debug("Convert host " + rawHost + " to " + host);
73              } else if (rawHost.endsWith("*")) {
74                  int length = rawHost.length();
75                  host = rawHost.substring(length - 1, length);
76                  log.debug("Convert host " + rawHost + " to " + host);
77              } else {
78                  host = rawHost;
79              }
80  
81              synchronized (entryMap) {
82                  entryMap.put(host, spfRecord);
83              }
84          } catch (SPFResultException e) {
85              throw new IllegalArgumentException("Invalid SPF-Record: "
86                      + rawSpfRecord);
87          }
88  
89      }
90  
91      /**
92       * Clear all entries
93       * 
94       */
95      public void clearEntrys() {
96          log.debug("Clear all entries");
97          synchronized (entryMap) {
98              entryMap.clear();
99          }
100     }
101 
102     /**
103      * Remove entry
104      * 
105      * @param host
106      *            The host
107      */
108     public void removeEntry(String host) {
109         log.debug("Remove fallback entry for host: " + host);
110         synchronized (entryMap) {
111             entryMap.remove(getRawEntry(host));
112         }
113     }
114 
115     /**
116      * @see org.apache.james.jspf.policies.PolicyPostFilter#getSPFRecord(java.lang.String, org.apache.james.jspf.core.SPF1Record)
117      */
118     public SPF1Record getSPFRecord(String currentDomain, SPF1Record res) throws PermErrorException, TempErrorException, NoneException, NeutralException {
119         if (res == null) {
120             return getMySPFRecord(currentDomain);
121         } else {
122             return res;
123         }
124     }
125     
126     /**
127      * Return the SPF1Record for the given host
128      * 
129      * @param host
130      *            the hostname or ipaddress
131      * @return the SPF1Record of null if no SPF1Record was found in fallback for
132      *         the given host
133      */
134     protected SPF1Record getMySPFRecord(String host) {
135         Object entry = null;
136 
137         synchronized (entryMap) {
138             entry = getRawEntry(host);
139         }
140 
141         if (entry != null) {
142             return (SPF1Record) entry;
143         } else {
144             return null;
145         }
146     }
147 
148     /**
149      * Return the Object stored in the map which match the given host. Keep in
150      * mind that this method should only called in a synchronized method or
151      * block
152      * 
153      * @param host
154      *            the host
155      * @return the stored object for the given host or null
156      */
157     private Object getRawEntry(String host) {
158         Iterator fallBackIt = entryMap.keySet().iterator();
159 
160         while (fallBackIt.hasNext()) {
161             String rawHost = fallBackIt.next().toString();
162 
163             if ((rawHost.startsWith(".") && host.startsWith(rawHost))
164                     || rawHost.endsWith(".") && host.endsWith(rawHost)) {
165                 return entryMap.get(rawHost);
166             }
167         }
168         return null;
169     }
170 
171 }