summaryrefslogtreecommitdiff
path: root/java/broker/src/main/java/org/apache/qpid/server/logging/actors/CurrentActor.java
blob: 97134515a0792b7c8c26aa0f616764fc20169ee0 (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 *
 * 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 java.util.EmptyStackException;
import java.util.Stack;

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

/**
 * 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;

    private CurrentActor()
    {
    }

    /**
     * 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;
    }

    public static void message(LogSubject subject, LogMessage message)
    {
        get().message(subject, message);
    }

    public static void message(LogMessage message)
    {
        get().message(message);
    }
}