View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.pipeline.validation;
19  
20  import org.apache.commons.pipeline.Stage;
21  
22  /**
23   * A collection of utility methods used by the validation system.
24   *
25   */
26  public class ValidationUtils {
27      
28      /** Prevent instantiation */
29      private ValidationUtils() {  }
30      
31      /**
32       * Tests whether the specified downstream stage can succeed the specified
33       * upstream stage.
34       * @return true or false on definitive identification of compatibility or
35       * null if unable to determine compatibility due to missing metadata.
36       * @param upstream the upstream stage
37       * @param downstream the stage consuming data produced by the upstream stage
38       */
39      public static final Boolean canSucceed(Stage upstream, Stage downstream) {
40          if (upstream.getClass().isAnnotationPresent(ProducedTypes.class) &&
41                  downstream.getClass().isAnnotationPresent(ConsumedTypes.class)) {
42              ProducedTypes p = upstream.getClass().getAnnotation(ProducedTypes.class);
43              ConsumedTypes c = downstream.getClass().getAnnotation(ConsumedTypes.class);
44              return compatible(p.value(), c.value());
45          }
46          
47          return null;
48      }
49      
50      /**
51       * Tests whether the specified downstream stage can succeed the specified
52       * upstream stage on a branch pipeline identified by the given branch key.
53       * @return true or false on definitive identification of compatibility or
54       * null if unable to determine compatibility due to missing metadata.
55       * @param upstream the upstream stage
56       * @param downstreamBranchKey the key identifying the branch receiving data from the upstream stage
57       * @param downstream the stage consuming data produced by the upstream stage
58       */
59      public static final Boolean canSucceedOnBranch(Stage upstream, String downstreamBranchKey, Stage downstream) {
60          if (downstream.getClass().isAnnotationPresent(ConsumedTypes.class)) {
61              ConsumedTypes c = downstream.getClass().getAnnotation(ConsumedTypes.class);
62              if (upstream.getClass().isAnnotationPresent(ProductionOnBranch.class)) {
63                  ProductionOnBranch pob = upstream.getClass().getAnnotation(ProductionOnBranch.class);
64                  
65                  if (!downstreamBranchKey.equals(pob.branchKey())) {
66                      return false;
67                  } else {
68                      return compatible(pob.producedTypes(), c.value());
69                  }
70              } else if (upstream.getClass().isAnnotationPresent(Branches.class)) {
71                  Branches branches = upstream.getClass().getAnnotation(Branches.class);
72                  for (ProductionOnBranch pob : branches.productionOnBranches()) {
73                      if (downstreamBranchKey.equals(pob.branchKey())) {
74                          return compatible(pob.producedTypes(), c.value());
75                      }
76                  }
77                  
78                  return false;
79              }
80          }
81          
82          return null;
83      }
84      
85      /**
86       * Check if the specified production is compatible with the specified consumption.
87       */
88      private static Boolean compatible(Class<?>[] producedTypes, Class<?>[] consumedTypes) {
89          for (Class<?> consumed : consumedTypes) {
90              for (Class<?> produced : producedTypes) { //usually just one type
91                  if (consumed.isAssignableFrom(produced)) return true;
92              }
93          }
94          
95          //none of what is produced can be consumed
96          return false;
97      }    
98  }