001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2011-2013 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.server;
011
012import mondrian.olap.MondrianServer;
013import mondrian.rolap.RolapConnection;
014import mondrian.util.ArrayStack;
015
016/**
017 * Point of execution from which a service is invoked.
018 */
019public class Locus {
020    public final Execution execution;
021    public final String message;
022    public final String component;
023
024    private static final ThreadLocal<ArrayStack<Locus>> THREAD_LOCAL =
025        new ThreadLocal<ArrayStack<Locus>>() {
026            protected ArrayStack<Locus> initialValue() {
027                return new ArrayStack<Locus>();
028            }
029        };
030
031    /**
032     * Creates a Locus.
033     *
034     * @param execution Execution context
035     * @param component Description of a the component executing the query,
036     *   generally a method name, e.g. "SqlTupleReader.readTuples"
037     * @param message Description of the purpose of this statement, to be
038     *   printed if there is an error
039     */
040    public Locus(
041        Execution execution,
042        String component,
043        String message)
044    {
045        assert execution != null;
046        this.execution = execution;
047        this.component = component;
048        this.message = message;
049    }
050
051    public static void pop(Locus locus) {
052        final Locus pop = THREAD_LOCAL.get().pop();
053        assert locus == pop;
054    }
055
056    public static void push(Locus locus) {
057        THREAD_LOCAL.get().push(locus);
058    }
059
060    public static Locus peek() {
061        return THREAD_LOCAL.get().peek();
062    }
063
064    public static <T> T execute(
065        RolapConnection connection,
066        String component,
067        Action<T> action)
068    {
069        final Statement statement = connection.getInternalStatement();
070        final Execution execution = new Execution(statement, 0);
071        return execute(execution, component, action);
072    }
073
074    public static <T> T execute(
075        Execution execution,
076        String component,
077        Action<T> action)
078    {
079        final Locus locus =
080            new Locus(
081                execution,
082                component,
083                null);
084        Locus.push(locus);
085        try {
086            return action.execute();
087        } finally {
088            Locus.pop(locus);
089        }
090    }
091
092    public final MondrianServer getServer() {
093        return execution.statement.getMondrianConnection().getServer();
094    }
095
096    public interface Action<T> {
097        T execute();
098    }
099}
100
101// End Locus.java