/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * 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 org.jkiss.dbeaver.runtime.qm; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.qm.QMController; import org.jkiss.dbeaver.model.qm.QMExecutionHandler; import org.jkiss.dbeaver.model.qm.QMMetaEvent; import org.jkiss.dbeaver.model.qm.QMMetaListener; import org.jkiss.dbeaver.model.qm.QMMCollector; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; /** * QMController default implementation */ public class QMControllerImpl implements QMController { private static final Log log = Log.getLog(QMControllerImpl.class); private QMExecutionHandler defaultHandler; private QMMCollectorImpl metaHandler; private final List<QMExecutionHandler> handlers = new ArrayList<>(); public QMControllerImpl() { defaultHandler = (QMExecutionHandler) Proxy.newProxyInstance( getClass().getClassLoader(), new Class[]{ QMExecutionHandler.class }, new NotifyInvocationHandler()); metaHandler = new QMMCollectorImpl(); registerHandler(metaHandler); } public void dispose() { if (metaHandler != null) { unregisterHandler(metaHandler); metaHandler.dispose(); metaHandler = null; } synchronized (handlers) { if (!handlers.isEmpty()) { log.warn("Some QM handlers are still registered: " + handlers); handlers.clear(); } } defaultHandler = null; } @Override public QMMCollector getMetaCollector() { return metaHandler; } @Override public QMExecutionHandler getDefaultHandler() { return defaultHandler; } @Override public void registerHandler(QMExecutionHandler handler) { synchronized (handlers) { handlers.add(handler); } } @Override public void unregisterHandler(QMExecutionHandler handler) { synchronized (handlers) { if (!handlers.remove(handler)) { log.warn("QM handler '" + handler + "' isn't registered within QM controller"); } } } @Override public void registerMetaListener(QMMetaListener metaListener) { metaHandler.addListener(metaListener); } @Override public void unregisterMetaListener(QMMetaListener metaListener) { metaHandler.removeListener(metaListener); } @Override public List<QMMetaEvent> getPastMetaEvents() { return metaHandler.getPastEvents(); } List<QMExecutionHandler> getHandlers() { synchronized (handlers) { return handlers; } } private class NotifyInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) { try { if (method.getReturnType() == Void.TYPE && method.getName().startsWith("handle")) { QMExecutionHandler[] handlersCopy; synchronized (handlers) { handlersCopy = handlers.toArray(new QMExecutionHandler[handlers.size()]); } for (QMExecutionHandler handler : handlersCopy) { try { method.invoke(handler, args); } catch (InvocationTargetException e) { log.debug("Error notifying QM handler '" + handler.getHandlerName() + "'", e.getTargetException()); } } return null; } else if (method.getName().equals("getHandlerName")) { return "Default"; } else { return method.invoke(this, args); } } catch (Throwable e) { // just ignore it log.debug("Error executing QM method " + method, e); return null; } } } }