/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.compiler.flow.external; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.asakusafw.compiler.common.Precondition; import com.asakusafw.compiler.flow.ExternalIoDescriptionProcessor; import com.asakusafw.compiler.flow.ExternalIoDescriptionProcessor.Repository; import com.asakusafw.compiler.flow.FlowCompilingEnvironment; import com.asakusafw.utils.collections.Sets; import com.asakusafw.utils.collections.Tuple2; import com.asakusafw.utils.collections.Tuples; import com.asakusafw.vocabulary.flow.graph.FlowGraph; import com.asakusafw.vocabulary.flow.graph.FlowIn; import com.asakusafw.vocabulary.flow.graph.FlowOut; import com.asakusafw.vocabulary.flow.graph.InputDescription; import com.asakusafw.vocabulary.flow.graph.OutputDescription; /** * Analyzes external I/O descriptions in each jobflow. */ public class ExternalIoAnalyzer { static final Logger LOG = LoggerFactory.getLogger(ExternalIoAnalyzer.class); private final FlowCompilingEnvironment environment; /** * Creates a new instance. * @param environment the current environment * @throws IllegalArgumentException if the parameter is {@code null} */ public ExternalIoAnalyzer(FlowCompilingEnvironment environment) { Precondition.checkMustNotBeNull(environment, "environment"); //$NON-NLS-1$ this.environment = environment; } /** * Returns whether the external I/O descriptions in the target flow graph are valid or not. * @param graph the target flow graph * @return {@code true} if the all external I/O descriptions are valid, otherwise {@code false} * @throws IllegalArgumentException if the parameter is {@code null} */ public boolean validate(FlowGraph graph) { Precondition.checkMustNotBeNull(graph, "graph"); //$NON-NLS-1$ LOG.debug("validating external I/O: {}", graph.getDescription().getName()); //$NON-NLS-1$ List<Tuple2<InputDescription, ExternalIoDescriptionProcessor>> inputs = new ArrayList<>(); List<Tuple2<OutputDescription, ExternalIoDescriptionProcessor>> outputs = new ArrayList<>(); if (collect(graph, inputs, outputs) == false) { return false; } boolean valid = true; Set<ExternalIoDescriptionProcessor> processors = getActiveProcessors(inputs, outputs); for (ExternalIoDescriptionProcessor proc : processors) { List<InputDescription> in = getOnly(inputs, proc); List<OutputDescription> out = getOnly(outputs, proc); valid &= proc.validate(in, out); } return valid; } private <T> List<T> getOnly( List<Tuple2<T, ExternalIoDescriptionProcessor>> inputs, ExternalIoDescriptionProcessor proc) { assert inputs != null; assert proc != null; List<T> results = new ArrayList<>(); for (Tuple2<T, ExternalIoDescriptionProcessor> tuple : inputs) { if (tuple.second.equals(proc)) { results.add(tuple.first); } } return results; } private Set<ExternalIoDescriptionProcessor> getActiveProcessors( List<Tuple2<InputDescription, ExternalIoDescriptionProcessor>> inputs, List<Tuple2<OutputDescription, ExternalIoDescriptionProcessor>> outputs) { assert inputs != null; assert outputs != null; Map<Class<?>, ExternalIoDescriptionProcessor> actives = new HashMap<>(); // collect for (Tuple2<InputDescription, ExternalIoDescriptionProcessor> tuple : inputs) { actives.put(tuple.second.getClass(), tuple.second); } for (Tuple2<OutputDescription, ExternalIoDescriptionProcessor> tuple : outputs) { actives.put(tuple.second.getClass(), tuple.second); } // normalize normalize(inputs, actives); normalize(outputs, actives); return Sets.from(actives.values()); } private <T> void normalize( List<Tuple2<T, ExternalIoDescriptionProcessor>> list, Map<Class<?>, ExternalIoDescriptionProcessor> actives) { assert list != null; assert actives != null; for (ListIterator<Tuple2<T, ExternalIoDescriptionProcessor>> iter = list.listIterator(); iter.hasNext();) { Tuple2<T, ExternalIoDescriptionProcessor> tuple = iter.next(); ExternalIoDescriptionProcessor normal = actives.get(tuple.second.getClass()); iter.set(Tuples.of(tuple.first, normal)); } } private boolean collect( FlowGraph graph, List<Tuple2<InputDescription, ExternalIoDescriptionProcessor>> inputs, List<Tuple2<OutputDescription, ExternalIoDescriptionProcessor>> outputs) { assert graph != null; assert inputs != null; assert outputs != null; boolean valid = true; Repository externals = environment.getExternals(); for (FlowIn<?> port : graph.getFlowInputs()) { InputDescription desc = port.getDescription(); ExternalIoDescriptionProcessor processor = externals.findProcessor(desc); if (processor != null) { inputs.add(Tuples.of(desc, processor)); } else { environment.error( Messages.getString("ExternalIoAnalyzer.errorMissingProcessor"), //$NON-NLS-1$ desc.getClass().getName()); valid = false; } } for (FlowOut<?> port : graph.getFlowOutputs()) { OutputDescription desc = port.getDescription(); ExternalIoDescriptionProcessor processor = externals.findProcessor(desc); if (processor != null) { outputs.add(Tuples.of(desc, processor)); } else { valid = false; } } return valid; } }