View Javadoc

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 }