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 }