/* * 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 net.hydromatic.optiq.runtime; import com.google.common.base.Function; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * Collection of hooks that can be set by observers and are executed at various * parts of the query preparation process. * * <p>For testing and debugging rather than for end-users.</p> */ public enum Hook { /** Called to get the current time. Use this to return a predictable time * in tests. */ CURRENT_TIME, /** Called with the SQL string and parse tree, in an array. */ PARSE_TREE, /** Called with the generated Java plan, just before it is compiled by * Janino. */ JAVA_PLAN, /** Called with the output of sql-to-rel-converter. */ CONVERTED, /** Called after de-correlation and field trimming, but before * optimization. */ TRIMMED, /** Called by the planner after substituting a materialization. */ SUB, /** Called when a constant expression is being reduced. */ EXPRESSION_REDUCER, /** Called to create a Program to optimize the statement. */ PROGRAM, /** Called when materialization is created. */ CREATE_MATERIALIZATION, /** Called with a query that has been generated to send to a back-end system. * The query might be a SQL string (for the JDBC adapter), a list of Mongo * pipeline expressions (for the MongoDB adapter), et cetera. */ QUERY_PLAN; private final List<Function<Object, Object>> handlers = new CopyOnWriteArrayList<Function<Object, Object>>(); private final ThreadLocal<List<Function<Object, Object>>> threadHandlers = new ThreadLocal<List<Function<Object, Object>>>() { protected List<Function<Object, Object>> initialValue() { return new ArrayList<Function<Object, Object>>(); } }; /** Adds a handler for this Hook. * * <p>Returns a {@link Hook.Closeable} so that you can use the following * try-finally pattern to prevent leaks:</p> * * <blockquote><pre> * final Hook.Closeable closeable = Hook.FOO.add(HANDLER); * try { * ... * } finally { * closeable.close(); * }</pre> * </blockquote> */ public <T, R> Closeable add(final Function<T, R> handler) { //noinspection unchecked handlers.add((Function<Object, Object>) handler); return new Closeable() { public void close() { remove(handler); } }; } /** Removes a handler from this Hook. */ private boolean remove(Function handler) { return handlers.remove(handler); } /** Adds a handler for this thread. */ public <T, R> Closeable addThread(final Function<T, R> handler) { //noinspection unchecked threadHandlers.get().add((Function<Object, Object>) handler); return new Closeable() { public void close() { removeThread(handler); } }; } /** Removes a thread handler from this Hook. */ private boolean removeThread(Function handler) { return threadHandlers.get().remove(handler); } /** Runs all handlers registered for this Hook, with the given argument. */ public void run(Object arg) { for (Function<Object, Object> handler : handlers) { handler.apply(arg); } for (Function<Object, Object> handler : threadHandlers.get()) { handler.apply(arg); } } /** Removes a Hook after use. * * <p>Note: Although it would be convenient, this interface cannot extend * {@code AutoCloseable} while Calcite maintains compatibility with * JDK 1.6.</p> */ public interface Closeable /*extends AutoCloseable*/ { /** Closeable that does nothing. */ Closeable EMPTY = new Closeable() { public void close() {} }; void close(); // override, removing "throws" } } // End Hook.java