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;
21  
22  import static org.apache.jsieve.Constants.COMPARATOR_ASCII_CASEMAP_NAME;
23  import static org.apache.jsieve.Constants.COMPARATOR_OCTET_NAME;
24  
25  import java.util.concurrent.ConcurrentMap;
26  import java.util.concurrent.CopyOnWriteArraySet;
27  
28  import org.apache.jsieve.comparators.Comparator;
29  import org.apache.jsieve.exception.LookupException;
30  
31  /**
32   * <p>Maps Comparator names to configured Comparator implementation classes.</p>
33   * <h4>Thread Safety</h4>
34   * <p>
35   * Instances may safely be accessed concurrently by multiple threads.
36   * </p>
37   */
38  public class ComparatorManagerImpl implements ComparatorManager {
39  
40      /** 
41       * Constructs a set containing the names of those comparisons for which <code>require</code> 
42       * is not necessary before usage, according to RFC5228.
43       * See <a href='http://tools.ietf.org/html/rfc5228#section-2.7.3'>RFC5228, 2.7.3 Comparators</a>. 
44       */
45      public static CopyOnWriteArraySet<String> standardDefinedComparators() {
46          final CopyOnWriteArraySet<String> results = new CopyOnWriteArraySet<String>();
47          results.add(COMPARATOR_OCTET_NAME);
48          results.add(COMPARATOR_ASCII_CASEMAP_NAME);
49          return results;
50      }
51      
52      private final ConcurrentMap<String, String> classNameMap;
53      /** 
54       * The names of those comparisons for which <code>require</code> is not necessary before usage.
55       * See <a href='http://tools.ietf.org/html/rfc5228#section-2.7.3'>RFC5228, 2.7.3 Comparators</a>. 
56       */
57      private final CopyOnWriteArraySet<String> implicitlyDeclared;
58  
59      /**
60       * Constructs a manager with the standard comparators implicitly defined.
61       * @param classNameMap not null
62       */
63      public ComparatorManagerImpl(final ConcurrentMap<String, String> classNameMap) {
64          this(classNameMap, standardDefinedComparators());
65      }
66      
67      /**
68       * Constructor for ComparatorManager.
69       * @param classNameMap indexes names of implementation classes against logical names, not null
70       * @param implicitlyDeclared names of those comparisons for which <code>require</code> is not necessary before usage
71       */
72      public ComparatorManagerImpl(final ConcurrentMap<String, String> classNameMap, final CopyOnWriteArraySet<String> implicitlyDeclared) {
73          super();
74          this.classNameMap = classNameMap;
75          this.implicitlyDeclared = implicitlyDeclared;
76      }
77      
78      /**
79       * Is an explicit declaration in a <code>require</code> statement
80       * unnecessary for this comparator?
81       * @param comparatorName not null
82       * @return true when this comparator need not be declared by <core>require</code>,
83       * false when any usage of this comparator must be declared in a <code>require</code> statement
84       */
85      public boolean isImplicitlyDeclared(final String comparatorName) {
86          return implicitlyDeclared.contains(comparatorName);
87      }
88  
89      /**
90       * <p>
91       * Method lookup answers the class to which a Comparator name is mapped.
92       * </p>
93       * 
94       * @param name -
95       *            The name of the Comparator
96       * @return Class - The class of the Comparator
97       * @throws LookupException
98       */
99      public Class lookup(String name) throws LookupException {
100         Class comparatorClass = null;
101         try {
102             comparatorClass = getClass().getClassLoader().loadClass(
103                     getClassName(name));
104         } catch (ClassNotFoundException e) {
105             throw new LookupException("Comparator named '" + name
106                     + "' not found.");
107         }
108         if (!Comparator.class.isAssignableFrom(comparatorClass))
109             throw new LookupException("Class " + comparatorClass.getName()
110                     + " must implement " + Comparator.class.getName());
111         return comparatorClass;
112     }
113 
114     /**
115      * <p>
116      * Method newInstance answers an instance of the class to which a Comparator
117      * name is mapped.
118      * </p>
119      * 
120      * @param name -
121      *            The name of the Comparator
122      * @return Class - The class of the Comparator
123      * @throws LookupException
124      */
125     public Comparator getComparator(String name) throws LookupException {
126         try {
127             return (Comparator) lookup(name).newInstance();
128         } catch (InstantiationException e) {
129             throw new LookupException(e.getMessage());
130         } catch (IllegalAccessException e) {
131             throw new LookupException(e.getMessage());
132         }
133     }
134 
135     /**
136      * <p>
137      * Method getClassName answers the name of the class to which a Comparator
138      * name is mapped.
139      * </p>
140      * 
141      * @param name -
142      *            The name of the Comparator
143      * @return String - The name of the class
144      * @throws LookupException
145      */
146     private String getClassName(String name) throws LookupException {
147         String className = classNameMap.get(name.toLowerCase());
148         if (null == className)
149             throw new LookupException("Comparator named '" + name
150                     + "' not mapped.");
151         return className;
152     }
153 
154     /**
155      * @see ComparatorManager#isSupported(String)
156      */
157     public boolean isSupported(String name) {
158         try {
159             getComparator(name);
160             return true;
161         } catch (LookupException e) {
162             return false;
163         }
164     }
165 }