1 /*
2 * Copyright 2007-2013 smartics, Kronseder & Reiner GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package de.smartics.maven.exceptions.util;
17
18 import org.apache.commons.lang.StringUtils;
19
20 import com.sun.javadoc.ClassDoc;
21 import com.sun.javadoc.Type;
22
23 /**
24 * Provides utilities for filtering on {@link com.sun.javadoc.Doc} elements.
25 */
26 public final class FilterUtils
27 {
28 // ********************************* Fields *********************************
29
30 // --- constants ------------------------------------------------------------
31
32 // --- members --------------------------------------------------------------
33
34 // ****************************** Initializer *******************************
35
36 // ****************************** Constructors ******************************
37
38 /**
39 * Utility class pattern.
40 */
41 private FilterUtils()
42 {
43 }
44
45 // ****************************** Inner Classes *****************************
46
47 // ********************************* Methods ********************************
48
49 // --- init -----------------------------------------------------------------
50
51 // --- get&set --------------------------------------------------------------
52
53 // --- business -------------------------------------------------------------
54
55 /**
56 * Checks if the given class is implementing the given interface type. It runs
57 * up the inheritance path to the root to see if any parent class implements
58 * the specified interface.
59 *
60 * @param classDoc the class that is tested on implementing the interface of
61 * the given type.
62 * @param type the type of the interface to test.
63 * @return <code>true</code> if the class implements the given type,
64 * <code>false</code> otherwise.
65 */
66 public static boolean isImplementing(
67 final ClassDoc classDoc,
68 final Class<?> type)
69 {
70 if (classDoc == null)
71 {
72 return false;
73 }
74
75 final boolean declared = isInterfaceDeclared(classDoc, type);
76 if (!declared)
77 {
78 final ClassDoc parentClassDoc = classDoc.superclass();
79 return isImplementing(parentClassDoc, type);
80 }
81 else
82 {
83 return true;
84 }
85 }
86
87 /**
88 * Checks if the given class is implementing the given interface type
89 * directly.
90 * <p>
91 * If the <code>classDoc</code> value is <code>null</code>, <code>false</code>
92 * is returned. This is to provide the same interface as in
93 * {@link #isImplementing(ClassDoc, Class)}.
94 * </p>
95 *
96 * @param classDoc the class that is tested on implementing the interface of
97 * the given type.
98 * @param type the type of the interface to test.
99 * @return <code>true</code> if the class declares the given type in its
100 * implements clause, <code>false</code> otherwise.
101 * @throws NullPointerException if the given interface <code>type</code> is
102 * <code>null</code>.
103 */
104 public static boolean isInterfaceDeclared(
105 final ClassDoc classDoc,
106 final Class<?> type) throws NullPointerException
107 {
108 if (classDoc == null)
109 {
110 return false;
111 }
112
113 final String typeName = type.getName();
114 final Type[] implementedTypes = classDoc.interfaceTypes();
115 for (Type implementedType : implementedTypes)
116 {
117 final String name = implementedType.qualifiedTypeName();
118 if (typeName.equals(name))
119 {
120 return true;
121 }
122 else
123 {
124 final boolean extending =
125 isInterfaceDeclaredInExtendingInterfaces(implementedType, typeName);
126 if (extending)
127 {
128 return true;
129 }
130 }
131 }
132 return false;
133 }
134
135 /**
136 * Checks if the the <code>typeName</code> matches with any type the given
137 * <code>implementedType</code> extends. The <code>implementedType</code>
138 * itself is not checked.
139 *
140 * @param implementedType type whose extended interfaces (the
141 * <code>implementedType</code> extends these interfaces) are
142 * checked.
143 * @param typeName the name of the type that has to be matched.
144 * @return <code>true</code> if the <code>typeName</code> matches any type
145 * that is extended by <code>implementedType</code> (depth first
146 * search), <code>false</code> otherwise.
147 */
148 private static boolean isInterfaceDeclaredInExtendingInterfaces(
149 final Type implementedType,
150 final String typeName)
151 {
152 final ClassDoc interfaceDoc = implementedType.asClassDoc();
153 final Type[] extendingInterfaces = interfaceDoc.interfaceTypes();
154 for (Type extendingInterface : extendingInterfaces)
155 {
156 final String name = extendingInterface.qualifiedTypeName();
157 if (typeName.equals(name))
158 {
159 return true;
160 }
161 else
162 {
163 final boolean extending =
164 isInterfaceDeclaredInExtendingInterfaces(extendingInterface,
165 typeName);
166 if (extending)
167 {
168 return true;
169 }
170 }
171 }
172 return false;
173 }
174
175 /**
176 * Checks if the given token is a valid Java identifier.
177 *
178 * @param token the token to check.
179 * @return <code>true</code> if the token is a valid Java identifier,
180 * <code>false</code> otherwise.
181 */
182 public static boolean isValidJavaIdentifier(final String token)
183 {
184 if (StringUtils.isBlank(token)
185 || !Character.isJavaIdentifierStart(token.charAt(0)))
186 {
187 return false;
188 }
189
190 for (int i = token.length() - 1; i >= 1; i--)
191 {
192 final char c = token.charAt(i);
193 if (!Character.isJavaIdentifierPart(c))
194 {
195 return false;
196 }
197 }
198 return true;
199 }
200
201 /**
202 * Checks that the path is a valid directory path for packages.
203 *
204 * @param path the path to check if it is valid.
205 * @return <code>true</code> if every directory name in the path is a valid
206 * Java package name, <code>false</code> otherwise.
207 */
208 public static boolean isValidJavaPackageDirPath(final String path)
209 {
210 if (StringUtils.isBlank(path))
211 {
212 return false;
213 }
214
215 final String normalized = path.replace('\\', '/');
216 final String[] parts = normalized.split("/");
217 if (parts.length == 0)
218 {
219 return false;
220 }
221 for (String part : parts)
222 {
223 if (!FilterUtils.isValidJavaIdentifier(part))
224 {
225 return false;
226 }
227 }
228 return true;
229 }
230
231 // --- object basics --------------------------------------------------------
232
233 }