/* * Copyright 2009 Google Inc. * * 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.google.common.css.compiler.passes; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.css.compiler.ast.CssTreeVisitor; import com.google.common.reflect.Reflection; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; /** * Dispatches to multiple {@code CssTreeVisitor}s. All {@code enter*} methods are called in the * order provided to the constructor and all {@code leave*} methods are called in the opposite * order. * * <p>Because {@code enter*} methods' return value changes the visitor behavior, the value returned * by the <em>last</em> delegate is the one returned by the method. */ public class DelegatingVisitor { private DelegatingVisitor() {} /** * Creates a {@code DelegatingVisitor} from the given list of visitors. The list must have at * least one element. */ public static CssTreeVisitor from(List<CssTreeVisitor> originalVisitors) { Preconditions.checkArgument(originalVisitors.size() >= 1); if (originalVisitors.size() == 1) { return originalVisitors.get(0); } final ImmutableList<CssTreeVisitor> visitors = ImmutableList.copyOf(originalVisitors); final ImmutableList<CssTreeVisitor> reverseVisitors = visitors.reverse(); return Reflection.newProxy( CssTreeVisitor.class, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Object returnValue = null; Iterable<CssTreeVisitor> visitorsInOrderForMethod; if (method.getName().startsWith("enter")) { visitorsInOrderForMethod = visitors; } else { // assume it's a leave* method visitorsInOrderForMethod = reverseVisitors; } for (CssTreeVisitor visitor : visitorsInOrderForMethod) { returnValue = method.invoke(visitor, args); } return returnValue; } catch (InvocationTargetException e) { throw e.getTargetException(); } } }); } /** * Creates a {@code DelegatingVisitor} from the given array of visitors. Changes to the array will * not be reflected after construction. */ public static CssTreeVisitor from(CssTreeVisitor... visitors) { return from(ImmutableList.copyOf(visitors)); } }