/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.tuscany.sca.core.invocation.impl; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.apache.tuscany.sca.interfacedef.Operation; import org.apache.tuscany.sca.invocation.DataExchangeSemantics; import org.apache.tuscany.sca.invocation.Interceptor; import org.apache.tuscany.sca.invocation.InvocationChain; import org.apache.tuscany.sca.invocation.Invoker; import org.apache.tuscany.sca.invocation.Phase; import org.apache.tuscany.sca.invocation.PhasedInterceptor; /** * Default implementation of an invocation chain * * @version $Rev$ $Date$ */ public class InvocationChainImpl implements InvocationChain { private Operation sourceOperation; private Operation targetOperation; private List<Node> nodes = new ArrayList<Node>(); private final PhaseManager phaseManager; private boolean forReference; private boolean allowsPassByReference; public InvocationChainImpl(Operation sourceOperation, Operation targetOperation, boolean forReference, PhaseManager phaseManager) { this.targetOperation = targetOperation; this.sourceOperation = sourceOperation; this.forReference = forReference; this.phaseManager = phaseManager; } public Operation getTargetOperation() { return targetOperation; } public void setTargetOperation(Operation operation) { this.targetOperation = operation; } public void addInterceptor(Interceptor interceptor) { if (interceptor instanceof PhasedInterceptor) { PhasedInterceptor pi = (PhasedInterceptor)interceptor; if (pi.getPhase() != null) { addInvoker(pi.getPhase(), pi); return; } } String phase = forReference ? Phase.REFERENCE : Phase.SERVICE; addInterceptor(phase, interceptor); } public void addInvoker(Invoker invoker) { if (invoker instanceof PhasedInterceptor) { PhasedInterceptor pi = (PhasedInterceptor)invoker; if (pi.getPhase() != null) { addInvoker(pi.getPhase(), pi); return; } } String phase = forReference ? Phase.REFERENCE_BINDING : Phase.IMPLEMENTATION; addInvoker(phase, invoker); } public Invoker getHeadInvoker() { return nodes.isEmpty() ? null : nodes.get(0).getInvoker(); } public Invoker getHeadInvoker(String phase) { int index = phaseManager.getAllPhases().indexOf(phase); if (index == -1) { throw new IllegalArgumentException("Invalid phase name: " + phase); } for (Node node : nodes) { if (index <= node.getPhaseIndex()) { return node.getInvoker(); } } return null; } /** * @return the sourceOperation */ public Operation getSourceOperation() { return sourceOperation; } /** * @param sourceOperation the sourceOperation to set */ public void setSourceOperation(Operation sourceOperation) { this.sourceOperation = sourceOperation; } public void addInterceptor(String phase, Interceptor interceptor) { addInvoker(phase, interceptor); } private void addInvoker(String phase, Invoker invoker) { int index = phaseManager.getAllPhases().indexOf(phase); if (index == -1) { throw new IllegalArgumentException("Invalid phase name: " + phase); } Node node = new Node(index, invoker); ListIterator<Node> li = nodes.listIterator(); Node before = null, after = null; boolean found = false; while (li.hasNext()) { before = after; after = li.next(); if (after.getPhaseIndex() > index) { // Move back li.previous(); li.add(node); found = true; break; } } if (!found) { // Add to the end nodes.add(node); before = after; after = null; } // Relink the interceptors if (before != null) { if (before.getInvoker() instanceof Interceptor) { ((Interceptor)before.getInvoker()).setNext(invoker); } } if (after != null) { if (invoker instanceof Interceptor) { ((Interceptor)invoker).setNext(after.getInvoker()); } } } public boolean allowsPassByReference() { if (allowsPassByReference) { // No need to check the invokers return true; } // Check if any of the invokers allows pass-by-reference boolean allowsPBR = false; for (Node i : nodes) { if (i.getInvoker() instanceof DataExchangeSemantics) { if (((DataExchangeSemantics)i.getInvoker()).allowsPassByReference()) { allowsPBR = true; break; } } } return allowsPBR; } public void setAllowsPassByReference(boolean allowsPBR) { this.allowsPassByReference = allowsPBR; } private static class Node { private int phaseIndex; private Invoker invoker; public Node(int phaseIndex, Invoker invoker) { super(); this.phaseIndex = phaseIndex; this.invoker = invoker; } public int getPhaseIndex() { return phaseIndex; } public Invoker getInvoker() { return invoker; } @Override public String toString() { return "(" + phaseIndex + ")" + invoker; } } }