summaryrefslogtreecommitdiff
path: root/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java
blob: 2ebbfeb73486fa44ff8fcd6438542d041fe75096 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 *
 * 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.qpid.server.logging.actors;

import org.apache.qpid.server.logging.LogActor;

import java.util.EmptyStackException;
import java.util.Stack;

/**
 * The CurrentActor is a ThreadLocal wrapper that allows threads in the broker
 * to retrieve an actor to perform logging. This approach is used so for two
 * reasons:
 * 1) We do not have to pass a logging actor around the system
 * 2) We can set new actors at the point we have enough information. i.e.
 * - Set a low level ConnectionActor when processing bytes from the wire.
 * - Set a ChannelActor when we are processing the frame
 * - Set a SubscriptionActor when we are handling the subscription.
 * <p/>
 * The code performing the logging need not worry about what type of actor is
 * currently set so can perform its logging. The resulting log entry though will
 * contain customised details from the the currently set Actor.
 * <p/>
 * The Actor model also allows the pre-creation of fixed messages so the
 * performance impact of the additional logging data is minimised.
 * <p/>
 * This class does not perform any checks to ensure that there is an Actor set
 * when calling remove or get. As a result the application developer must ensure
 * that they have called set before they attempt to use the actor via get or
 * remove the set actor.
 * <p/>
 * The checking of the return via get should not be done as the logging is
 * desired. It is preferable to cause the NullPointerException to highlight the
 * programming error rather than miss a log message.
 * <p/>
 * The same is true for the remove. A NPE will occur if no set has been called
 * highlighting the programming error.
 */
public class CurrentActor
{
    /** The ThreadLocal variable with initialiser */
    private static final ThreadLocal<Stack<LogActor>> _currentActor = new ThreadLocal<Stack<LogActor>>()
    {
        // Initialise the CurrentActor to be an empty List
        protected Stack<LogActor> initialValue()
        {
            return new Stack<LogActor>();
        }
    };

    private static LogActor _defaultActor;

    /**
     * Set a new {@link LogActor} to be the Current Actor
     * <p/>
     * This pushes the Actor in to the LIFO Queue
     *
     * @param actor The new LogActor
     */
    public static void set(LogActor actor)
    {
        Stack<LogActor> stack = _currentActor.get();
        stack.push(actor);
    }

    /**
     * Remove all {@link LogActor}s
     */
    public static void removeAll()
    {
        Stack<LogActor> stack = _currentActor.get();
        stack.clear();
    }

    /**
     * Remove the current {@link LogActor}.
     * <p/>
     * Calling remove without calling set will result in an EmptyStackException.
     */
    public static void remove()
    {
        Stack<LogActor> stack = _currentActor.get();
        stack.pop();
    }

    /**
     * Return the current head of the list of {@link LogActor}s.
     *
     * @return Current LogActor
     */
    public static LogActor get()
    {
        try
        {
            return _currentActor.get().peek();
        }
        catch (EmptyStackException ese)
        {
            return _defaultActor;
        }
    }

    public static void setDefault(LogActor defaultActor)
    {
        _defaultActor = defaultActor;
    }
}