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 }