View Javadoc

1   /**
2    * Licensed to jclouds, Inc. (jclouds) under one or more
3    * contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  jclouds 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  package org.jclouds.rest;
20  
21  import static com.google.common.base.Preconditions.checkNotNull;
22  
23  import java.lang.annotation.Annotation;
24  import java.lang.reflect.Method;
25  import java.util.Arrays;
26  import java.util.List;
27  
28  import javax.inject.Inject;
29  
30  import org.jclouds.predicates.Validator;
31  import org.jclouds.rest.annotations.ParamValidators;
32  
33  import com.google.common.collect.Iterables;
34  import com.google.common.collect.Lists;
35  import com.google.inject.Injector;
36  
37  /**
38   * Validates method parameters.
39   *
40   * Checks the {@link ParamValidators} annotation for validators. There can be method-level
41   * validators that apply to all parameters, and parameter-level validators. When validation on at
42   * least one parameter doesn't pass, throws {@link IllegalStateException}.
43   *
44   * @author Oleksiy Yarmula
45   */
46  public class InputParamValidator {
47  
48      private final Injector injector;
49  
50      @Inject
51      public InputParamValidator(Injector injector) {
52          this.injector = injector;
53      }
54  
55      public InputParamValidator() {
56          injector = null;
57      }
58  
59      /**
60       * Validates that method parameters are correct, according to {@link ParamValidators}.
61       *
62       * @param method
63       *           method with optionally set {@link ParamValidators}
64       * @param args
65       *           method arguments with optionally set {@link ParamValidators}
66       * @see ParamValidators
67       * @see Validator
68       *
69       * @throws IllegalStateException
70       *            if validation failed
71       */
72      public void validateMethodParametersOrThrow(Method method, Object... args) {
73  
74          try {
75              performMethodValidation(method, args);
76              performParameterValidation(method.getParameterAnnotations(), args);
77          } catch(IllegalArgumentException e) {
78              String argsString = Iterables.toString(Arrays.asList(args));
79              throw new IllegalArgumentException(String.format("Validation on '%s#%s' didn't pass for arguments: " +
80                      "%s. %n Reason: %s.", method.getDeclaringClass().getName(), method.getName(), argsString,
81                      e.getMessage()));
82          }
83      }
84  
85      /**
86       * Returns if all the method parameters passed all of the method-level
87       * validators or throws an {@link IllegalArgumentException}.
88       * @param method
89       *           method with optionally set {@link ParamValidators}. This can not be null.
90       * @param args
91       *           method's parameters
92       */
93      private void performMethodValidation(Method method, Object... args) {
94          ParamValidators paramValidatorsAnnotation = checkNotNull(method).getAnnotation(
95                  ParamValidators.class);
96          if (paramValidatorsAnnotation == null)
97              return; // by contract
98  
99          List<Validator<?>> methodValidators = getValidatorsFromAnnotation(paramValidatorsAnnotation);
100 
101         runPredicatesAgainstArgs(methodValidators, args);
102     }
103 
104     /**
105      * Returns if all the method parameters passed all of their corresponding
106      * validators or throws an {@link IllegalArgumentException}.
107      *
108      * @param annotations
109      *           annotations for method's arguments
110      * @param args
111      *           arguments that correspond to the array of annotations
112      */
113     private void performParameterValidation(Annotation[][] annotations, Object... args) {
114         for (int currentParameterIndex = 0; currentParameterIndex < annotations.length; currentParameterIndex++) {
115             ParamValidators annotation = findParamValidatorsAnnotationOrReturnNull(annotations[currentParameterIndex]);
116             if (annotation == null)
117                 continue;
118             List<Validator<?>> parameterValidators = getValidatorsFromAnnotation(annotation);
119             runPredicatesAgainstArgs(parameterValidators,
120                     args[currentParameterIndex]);
121         }
122     }
123 
124     private List<Validator<?>> getValidatorsFromAnnotation(ParamValidators paramValidatorsAnnotation) {
125         List<Validator<?>> validators = Lists.newArrayList();
126         for (Class<? extends Validator<?>> validator : paramValidatorsAnnotation.value()) {
127             validators.add(checkNotNull(injector.getInstance(validator)));
128         }
129         return validators;
130     }
131 
132     @SuppressWarnings("unchecked")
133     private void runPredicatesAgainstArgs(List<Validator<?>> predicates, Object... args) {
134         for (@SuppressWarnings("rawtypes") Validator validator : predicates) {
135             Iterables.all(Arrays.asList(args), validator);
136         }
137     }
138 
139     private ParamValidators findParamValidatorsAnnotationOrReturnNull(
140             Annotation[] parameterAnnotations) {
141         for (Annotation annotation : parameterAnnotations) {
142             if (annotation instanceof ParamValidators)
143                 return (ParamValidators) annotation;
144         }
145         return null;
146     }
147 
148 }