Skip to contentMethod: removeLocalContext(Object)
1: /*
2: * *********************************************************************************************************************
3: *
4: * TheseFoolishThings: Miscellaneous utilities
5: * http://tidalwave.it/projects/thesefoolishthings
6: *
7: * Copyright (C) 2009 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
23: * git clone https://github.com/tidalwave-it/thesefoolishthings-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.role.spi;
28:
29: import javax.annotation.Nonnull;
30: import java.util.ArrayList;
31: import java.util.Collections;
32: import java.util.List;
33: import java.util.Stack;
34: import it.tidalwave.util.NotFoundException;
35: import it.tidalwave.role.ContextManager;
36: import lombok.extern.slf4j.Slf4j;
37: import static it.tidalwave.role.spi.impl.LogUtil.*;
38:
39: /***********************************************************************************************************************
40: *
41: * @author Fabrizio Giudici
42: *
43: **********************************************************************************************************************/
44: @Slf4j
45: public class DefaultContextManager implements ContextManager
46: {
47: /** Useful for troubleshooting in cases when multiple instances are erroneously created. */
48: private static final boolean DUMP_STACK_AT_CREATION = Boolean.getBoolean(
49: DefaultContextManager.class.getName() + ".dumpStackAtCreation");
50:
51: /** The list of global contexts, ordered by priority. */
52: private final List<Object> globalContexts = Collections.synchronizedList(new ArrayList<>());
53:
54: /** The list of local contexts, ordered by priority. */
55: private final ThreadLocal<Stack<Object>> localContexts = new ThreadLocal<Stack<Object>>()
56: {
57: @Override @Nonnull
58: protected Stack<Object> initialValue()
59: {
60: return new Stack<>();
61: }
62: };
63:
64: /*******************************************************************************************************************
65: *
66: *
67: *
68: ******************************************************************************************************************/
69: public DefaultContextManager()
70: {
71: if (DUMP_STACK_AT_CREATION)
72: {
73: try
74: {
75: throw new RuntimeException();
76: }
77: catch (Exception e)
78: {
79: log.trace(">>>> created context manager " + this, e);
80: }
81: }
82: }
83:
84: /*******************************************************************************************************************
85: *
86: * {@inheritDoc}
87: *
88: ******************************************************************************************************************/
89: @Override @Nonnull
90: public List<Object> getContexts()
91: {
92: final List<Object> contexts = new ArrayList<>(localContexts.get());
93: Collections.reverse(contexts);
94: contexts.addAll(0, globalContexts);
95: return contexts;
96: }
97:
98: /*******************************************************************************************************************
99: *
100: * {@inheritDoc}
101: *
102: ******************************************************************************************************************/
103: @Override @Nonnull
104: public <T> T findContextOfType (@Nonnull final Class<T> contextType)
105: throws NotFoundException
106: {
107: for (final Object context : getContexts())
108: {
109: if (contextType.isAssignableFrom(context.getClass()))
110: {
111: return contextType.cast(context);
112: }
113: }
114:
115: throw new NotFoundException("No current context of type " + contextType);
116: }
117:
118: /*******************************************************************************************************************
119: *
120: * {@inheritDoc}
121: *
122: ******************************************************************************************************************/
123: @Override
124: public void addGlobalContext (@Nonnull final Object context)
125: {
126: globalContexts.add(context);
127: }
128:
129: /*******************************************************************************************************************
130: *
131: * {@inheritDoc}
132: *
133: ******************************************************************************************************************/
134: @Override
135: public void removeGlobalContext (@Nonnull final Object context)
136: {
137: globalContexts.remove(context);
138: }
139:
140: /*******************************************************************************************************************
141: *
142: * {@inheritDoc}
143: *
144: ******************************************************************************************************************/
145: @Override
146: public void addLocalContext (@Nonnull final Object context)
147: {
148: localContexts.get().push(context);
149: }
150:
151: /*******************************************************************************************************************
152: *
153: * {@inheritDoc}
154: *
155: ******************************************************************************************************************/
156: @Override
157: public void removeLocalContext (@Nonnull final Object context)
158: {
159: localContexts.get().remove(context);
160: }
161:
162: /*******************************************************************************************************************
163: *
164: * {@inheritDoc}
165: *
166: ******************************************************************************************************************/
167: @Override @Nonnull
168: public <T, E extends Throwable> T runEWithContexts (@Nonnull final SupplierWithException<T, E> supplier,
169: @Nonnull final Object ... contexts)
170: throws E
171: {
172: log.trace("runWithContexts({}, {})", shortId(supplier), shortIds(contexts));
173:
174: try (final Binder __ = binder(contexts))
175: {
176: if (log.isTraceEnabled())
177: {
178: log.trace(">>>> contexts now: {} - {}", getContexts(), this);
179: }
180:
181: final T result = supplier.get();
182: log.trace(">>>> runWithContexts({}, {}) completed", shortId(supplier), shortIds(contexts));
183: return result;
184: }
185: }
186: }