001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.pipeline.validation; 019 020 import org.apache.commons.pipeline.Stage; 021 022 /** 023 * A collection of utility methods used by the validation system. 024 * 025 */ 026 public class ValidationUtils { 027 028 /** Prevent instantiation */ 029 private ValidationUtils() { } 030 031 /** 032 * Tests whether the specified downstream stage can succeed the specified 033 * upstream stage. 034 * @return true or false on definitive identification of compatibility or 035 * null if unable to determine compatibility due to missing metadata. 036 * @param upstream the upstream stage 037 * @param downstream the stage consuming data produced by the upstream stage 038 */ 039 public static final Boolean canSucceed(Stage upstream, Stage downstream) { 040 if (upstream.getClass().isAnnotationPresent(ProducedTypes.class) && 041 downstream.getClass().isAnnotationPresent(ConsumedTypes.class)) { 042 ProducedTypes p = upstream.getClass().getAnnotation(ProducedTypes.class); 043 ConsumedTypes c = downstream.getClass().getAnnotation(ConsumedTypes.class); 044 return compatible(p.value(), c.value()); 045 } 046 047 return null; 048 } 049 050 /** 051 * Tests whether the specified downstream stage can succeed the specified 052 * upstream stage on a branch pipeline identified by the given branch key. 053 * @return true or false on definitive identification of compatibility or 054 * null if unable to determine compatibility due to missing metadata. 055 * @param upstream the upstream stage 056 * @param downstreamBranchKey the key identifying the branch receiving data from the upstream stage 057 * @param downstream the stage consuming data produced by the upstream stage 058 */ 059 public static final Boolean canSucceedOnBranch(Stage upstream, String downstreamBranchKey, Stage downstream) { 060 if (downstream.getClass().isAnnotationPresent(ConsumedTypes.class)) { 061 ConsumedTypes c = downstream.getClass().getAnnotation(ConsumedTypes.class); 062 if (upstream.getClass().isAnnotationPresent(ProductionOnBranch.class)) { 063 ProductionOnBranch pob = upstream.getClass().getAnnotation(ProductionOnBranch.class); 064 065 if (!downstreamBranchKey.equals(pob.branchKey())) { 066 return false; 067 } else { 068 return compatible(pob.producedTypes(), c.value()); 069 } 070 } else if (upstream.getClass().isAnnotationPresent(Branches.class)) { 071 Branches branches = upstream.getClass().getAnnotation(Branches.class); 072 for (ProductionOnBranch pob : branches.productionOnBranches()) { 073 if (downstreamBranchKey.equals(pob.branchKey())) { 074 return compatible(pob.producedTypes(), c.value()); 075 } 076 } 077 078 return false; 079 } 080 } 081 082 return null; 083 } 084 085 /** 086 * Check if the specified production is compatible with the specified consumption. 087 */ 088 private static Boolean compatible(Class<?>[] producedTypes, Class<?>[] consumedTypes) { 089 for (Class<?> consumed : consumedTypes) { 090 for (Class<?> produced : producedTypes) { //usually just one type 091 if (consumed.isAssignableFrom(produced)) return true; 092 } 093 } 094 095 //none of what is produced can be consumed 096 return false; 097 } 098 }