View Javadoc

1   /*
2    * Copyright 2009, Josh Devins, Jitr.org.
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  
17  package org.jitr;
18  
19  import java.io.IOException;
20  import java.lang.annotation.Annotation;
21  import java.lang.reflect.Field;
22  import java.net.ServerSocket;
23  import java.util.Collection;
24  import java.util.LinkedList;
25  
26  import org.apache.commons.lang.Validate;
27  import org.jitr.core.JitrException;
28  
29  /**
30   * Provides various simple utility methods.
31   * 
32   * @author Josh Devins (info@joshdevins.net)
33   */
34  public final class JitrUtils {
35  
36      private JitrUtils() {
37          // non-instantiable class
38      }
39  
40      /**
41       * Finds any declared fields in the given class with the given annotation.
42       */
43      public static Collection<Field> getAnnotatedDeclaredFields(final Class<?> clazz,
44              final Class<? extends Annotation> annotationClass) {
45  
46          validateClassesNotNull(clazz, annotationClass);
47  
48          final Field[] fields = clazz.getDeclaredFields();
49          final Collection<Field> foundFields = new LinkedList<Field>();
50  
51          for (Field field : fields) {
52  
53              if (field.getAnnotation(annotationClass) != null) {
54                  foundFields.add(field);
55              }
56          }
57  
58          return foundFields;
59      }
60  
61      /**
62       * Finds an annotated field amongst a hierarchy of classes. Should multiple classes in the
63       * hierarchy have a field with the same annotation, the field from the most specific or lowest
64       * subclass is used.
65       * 
66       * @throws JitrException
67       *             When multiple annotated fields are found in any one class.
68       */
69      public static Field getMostSpecificAnnotatedDeclaredField(final Class<?> clazz,
70              final Class<? extends Annotation> annotationClass) {
71  
72          validateClassesNotNull(clazz, annotationClass);
73  
74          // if this is the top of the hierarchy, end here
75          if (Object.class.equals(clazz)) {
76              return null;
77          }
78  
79          // first look in this class
80          final Collection<Field> fields = getAnnotatedDeclaredFields(clazz, annotationClass);
81          if (fields.size() > 1) {
82              throw new JitrException("One field was expected, but multiple fields in "
83                      + clazz.getSimpleName() + " were annotated with "
84                      + annotationClass.getSimpleName());
85          }
86  
87          // nothing found, recurse and try the next class
88          if (fields.isEmpty()) {
89              return getMostSpecificAnnotatedDeclaredField(clazz.getSuperclass(), annotationClass);
90          }
91  
92          // only found one, continue with that
93          return fields.iterator().next();
94      }
95  
96      /**
97       * Provides a quick way to get a random, unused port by opening a {@link ServerSocket} and
98       * getting the locally assigned port for the server socket.
99       * 
100      * @return A random, unused port.
101      * 
102      * @throws JitrException
103      *             Thrown if any {@link IOException}s are thrown by the underlying calls to
104      *             {@link ServerSocket}.
105      */
106     public static int getRandomUnusedPort() throws JitrException {
107 
108         final int port;
109         ServerSocket socket = null;
110         try {
111             socket = new ServerSocket(0);
112             port = socket.getLocalPort();
113         } catch (final Exception e) {
114             throw new JitrException("Failure picking a random, unused port.", e);
115         } finally {
116             if (socket != null) {
117                 try {
118                     socket.close();
119                 } catch (final IOException ioe) {
120                     throw new JitrException("Failure closing temporary socket.", ioe);
121                 }
122             }
123         }
124 
125         return port;
126     }
127 
128     private static void validateClassesNotNull(final Class<?> clazz,
129             final Class<? extends Annotation> annotationClass) {
130 
131         Validate.notNull(clazz, "Class is required.");
132         Validate.notNull(annotationClass, "Annotation class is required.");
133     }
134 }