View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core;
15  
16  import static ch.qos.logback.core.CoreConstants.CONTEXT_NAME_KEY;
17  import static ch.qos.logback.core.CoreConstants.FA_FILENAME_COLLISION_MAP;
18  import static ch.qos.logback.core.CoreConstants.RFA_FILENAME_PATTERN_COLLISION_MAP;
19  
20  import java.util.ArrayList;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.ExecutorService;
25  import java.util.concurrent.ScheduledExecutorService;
26  import java.util.concurrent.ScheduledFuture;
27  
28  import ch.qos.logback.core.spi.LifeCycle;
29  import ch.qos.logback.core.spi.LogbackLock;
30  import ch.qos.logback.core.status.StatusManager;
31  import ch.qos.logback.core.util.ExecutorServiceUtil;
32  
33  public class ContextBase implements Context, LifeCycle {
34  
35      private long birthTime = System.currentTimeMillis();
36  
37      private String name;
38      private StatusManager sm = new BasicStatusManager();
39      // TODO propertyMap should be observable so that we can be notified
40      // when it changes so that a new instance of propertyMap can be
41      // serialized. For the time being, we ignore this shortcoming.
42      Map<String, String> propertyMap = new HashMap<String, String>();
43      Map<String, Object> objectMap = new HashMap<String, Object>();
44  
45      LogbackLock configurationLock = new LogbackLock();
46  
47      private ExecutorService executorService;
48      private ScheduledExecutorService scheduledExecutorService;
49      protected List<ScheduledFuture<?>> scheduledFutures = new ArrayList<ScheduledFuture<?>>(1);
50      private LifeCycleManager lifeCycleManager;
51      private boolean started;
52  
53      public ContextBase() {
54          initCollisionMaps();
55      }
56  
57      public StatusManager getStatusManager() {
58          return sm;
59      }
60  
61      /**
62       * Set the {@link StatusManager} for this context. Note that by default this
63       * context is initialized with a {@link BasicStatusManager}. A null value for
64       * the 'statusManager' argument is not allowed.
65       * <p/>
66       * <p> A malicious attacker can set the status manager to a dummy instance,
67       * disabling internal error reporting.
68       *
69       * @param statusManager the new status manager
70       */
71      public void setStatusManager(StatusManager statusManager) {
72          // this method was added in response to http://jira.qos.ch/browse/LBCORE-35
73          if (statusManager == null) {
74              throw new IllegalArgumentException("null StatusManager not allowed");
75          }
76          this.sm = statusManager;
77      }
78  
79      public Map<String, String> getCopyOfPropertyMap() {
80          return new HashMap<String, String>(propertyMap);
81      }
82  
83      public void putProperty(String key, String val) {
84          this.propertyMap.put(key, val);
85      }
86  
87      protected void initCollisionMaps() {
88          putObject(FA_FILENAME_COLLISION_MAP, new HashMap<String, String>());
89          putObject(RFA_FILENAME_PATTERN_COLLISION_MAP, new HashMap<String, String>());
90      }
91  
92      /**
93       * Given a key, return the corresponding property value. If invoked with
94       * the special key "CONTEXT_NAME", the name of the context is returned.
95       *
96       * @param key
97       * @return
98       */
99      public String getProperty(String key) {
100         if (CONTEXT_NAME_KEY.equals(key))
101             return getName();
102 
103         return (String) this.propertyMap.get(key);
104     }
105 
106     public Object getObject(String key) {
107         return objectMap.get(key);
108     }
109 
110     public void putObject(String key, Object value) {
111         objectMap.put(key, value);
112     }
113 
114     public void removeObject(String key) {
115         objectMap.remove(key);
116     }
117 
118     public String getName() {
119         return name;
120     }
121 
122     public void start() {
123         // We'd like to create the executor service here, but we can't;
124         // ContextBase has not always implemented LifeCycle and there are *many*
125         // uses (mostly in tests) that would need to be modified.
126         started = true;
127     }
128 
129     public void stop() {
130         // We don't check "started" here, because the executor service uses
131         // lazy initialization, rather than being created in the start method
132         stopExecutorServices();
133         started = false;
134     }
135 
136     public boolean isStarted() {
137         return started;
138     }
139 
140     /**
141      * Clear the internal objectMap and all properties. Removes registered
142      * shutdown hook
143      */
144     public void reset() {
145         removeShutdownHook();
146         getLifeCycleManager().reset();
147         propertyMap.clear();
148         objectMap.clear();
149     }
150 
151     /**
152      * The context name can be set only if it is not already set, or if the
153      * current name is the default context name, namely "default", or if the
154      * current name and the old name are the same.
155      *
156      * @throws IllegalStateException if the context already has a name, other than "default".
157      */
158     public void setName(String name) throws IllegalStateException {
159         if (name != null && name.equals(this.name)) {
160             return; // idempotent naming
161         }
162         if (this.name == null || CoreConstants.DEFAULT_CONTEXT_NAME.equals(this.name)) {
163             this.name = name;
164         } else {
165             throw new IllegalStateException("Context has been already given a name");
166         }
167     }
168 
169     public long getBirthTime() {
170         return birthTime;
171     }
172 
173     public Object getConfigurationLock() {
174         return configurationLock;
175     }
176 
177     @Override
178     /**
179      * @deprecated
180      */
181     public synchronized ExecutorService getExecutorService() {
182         return getScheduledExecutorService();
183     }
184 
185     @Override
186     public synchronized ScheduledExecutorService getScheduledExecutorService() {
187         if (scheduledExecutorService == null) {
188             scheduledExecutorService = ExecutorServiceUtil.newScheduledExecutorService();
189         }
190         return scheduledExecutorService;
191     }
192 
193     private synchronized void stopExecutorServices() {
194         if (executorService != null) {
195             ExecutorServiceUtil.shutdown(executorService);
196             executorService = null;
197         }
198         if (scheduledExecutorService != null) {
199             ExecutorServiceUtil.shutdown(scheduledExecutorService);
200             scheduledExecutorService = null;
201         }
202     }
203 
204     private void removeShutdownHook() {
205         Thread hook = (Thread) getObject(CoreConstants.SHUTDOWN_HOOK_THREAD);
206         if (hook != null) {
207             removeObject(CoreConstants.SHUTDOWN_HOOK_THREAD);
208             try {
209                 Runtime.getRuntime().removeShutdownHook(hook);
210             } catch (IllegalStateException e) {
211                 // if JVM is already shutting down, ISE is thrown
212                 // no need to do anything else
213             }
214         }
215     }
216 
217     public void register(LifeCycle component) {
218         getLifeCycleManager().register(component);
219     }
220 
221     /**
222      * Gets the life cycle manager for this context.
223      * <p>
224      * The default implementation lazily initializes an instance of
225      * {@link LifeCycleManager}.  Subclasses may override to provide a custom 
226      * manager implementation, but must take care to return the same manager
227      * object for each call to this method.
228      * <p>
229      * This is exposed primarily to support instrumentation for unit testing.
230      * 
231      * @return manager object 
232      */
233     synchronized LifeCycleManager getLifeCycleManager() {
234         if (lifeCycleManager == null) {
235             lifeCycleManager = new LifeCycleManager();
236         }
237         return lifeCycleManager;
238     }
239 
240     @Override
241     public String toString() {
242         return name;
243     }
244 
245     @Override
246     public void addScheduledFuture(ScheduledFuture<?> scheduledFuture) {
247         scheduledFutures.add(scheduledFuture);
248     }
249 
250     public List<ScheduledFuture<?>> getScheduledFutures() {
251         return new ArrayList<ScheduledFuture<?>>(scheduledFutures);
252     }
253     
254     
255 
256 }