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 ScheduledExecutorService scheduledExecutorService;
48      protected List<ScheduledFuture<?>> scheduledFutures = new ArrayList<ScheduledFuture<?>>(1);
49      private LifeCycleManager lifeCycleManager;
50      private boolean started;
51  
52      public ContextBase() {
53          initCollisionMaps();
54      }
55  
56      public StatusManager getStatusManager() {
57          return sm;
58      }
59  
60      /**
61       * Set the {@link StatusManager} for this context. Note that by default this
62       * context is initialized with a {@link BasicStatusManager}. A null value for
63       * the 'statusManager' argument is not allowed.
64       * <p/>
65       * <p> A malicious attacker can set the status manager to a dummy instance,
66       * disabling internal error reporting.
67       *
68       * @param statusManager the new status manager
69       */
70      public void setStatusManager(StatusManager statusManager) {
71          // this method was added in response to http://jira.qos.ch/browse/LBCORE-35
72          if (statusManager == null) {
73              throw new IllegalArgumentException("null StatusManager not allowed");
74          }
75          this.sm = statusManager;
76      }
77  
78      public Map<String, String> getCopyOfPropertyMap() {
79          return new HashMap<String, String>(propertyMap);
80      }
81  
82      public void putProperty(String key, String val) {
83          this.propertyMap.put(key, val);
84      }
85  
86      protected void initCollisionMaps() {
87          putObject(FA_FILENAME_COLLISION_MAP, new HashMap<String, String>());
88          putObject(RFA_FILENAME_PATTERN_COLLISION_MAP, new HashMap<String, String>());
89      }
90  
91      /**
92       * Given a key, return the corresponding property value. If invoked with
93       * the special key "CONTEXT_NAME", the name of the context is returned.
94       *
95       * @param key
96       * @return
97       */
98      public String getProperty(String key) {
99          if (CONTEXT_NAME_KEY.equals(key))
100             return getName();
101 
102         return (String) this.propertyMap.get(key);
103     }
104 
105     public Object getObject(String key) {
106         return objectMap.get(key);
107     }
108 
109     public void putObject(String key, Object value) {
110         objectMap.put(key, value);
111     }
112 
113     public void removeObject(String key) {
114         objectMap.remove(key);
115     }
116 
117     public String getName() {
118         return name;
119     }
120 
121     public void start() {
122         // We'd like to create the executor service here, but we can't;
123         // ContextBase has not always implemented LifeCycle and there are *many*
124         // uses (mostly in tests) that would need to be modified.
125         started = true;
126     }
127 
128     public void stop() {
129         // We don't check "started" here, because the executor service uses
130         // lazy initialization, rather than being created in the start method
131         stopExecutorService();
132         
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         
146         removeShutdownHook();
147         getLifeCycleManager().reset();
148         propertyMap.clear();
149         objectMap.clear();
150     }
151 
152     /**
153      * The context name can be set only if it is not already set, or if the
154      * current name is the default context name, namely "default", or if the
155      * current name and the old name are the same.
156      *
157      * @throws IllegalStateException if the context already has a name, other than "default".
158      */
159     public void setName(String name) throws IllegalStateException {
160         if (name != null && name.equals(this.name)) {
161             return; // idempotent naming
162         }
163         if (this.name == null || CoreConstants.DEFAULT_CONTEXT_NAME.equals(this.name)) {
164             this.name = name;
165         } else {
166             throw new IllegalStateException("Context has been already given a name");
167         }
168     }
169 
170     public long getBirthTime() {
171         return birthTime;
172     }
173 
174     public Object getConfigurationLock() {
175         return configurationLock;
176     }
177 
178     @Override
179     /**
180      * @deprecated
181      */
182     public synchronized ExecutorService getExecutorService() {
183         return getScheduledExecutorService();
184     }
185 
186     @Override
187     public synchronized ScheduledExecutorService getScheduledExecutorService() {
188         if (scheduledExecutorService == null) {
189             scheduledExecutorService = ExecutorServiceUtil.newScheduledExecutorService();
190         }
191         return scheduledExecutorService;
192     }
193 
194     private synchronized void stopExecutorService() {
195         if (scheduledExecutorService != null) {
196             ExecutorServiceUtil.shutdown(scheduledExecutorService);
197             scheduledExecutorService = null;
198         }
199     }
200 
201     private void removeShutdownHook() {
202         Thread hook = (Thread) getObject(CoreConstants.SHUTDOWN_HOOK_THREAD);
203         if (hook != null) {
204             removeObject(CoreConstants.SHUTDOWN_HOOK_THREAD);
205             try {
206                 Runtime.getRuntime().removeShutdownHook(hook);
207             } catch (IllegalStateException e) {
208                 // if JVM is already shutting down, ISE is thrown
209                 // no need to do anything else
210             }
211         }
212     }
213 
214     public void register(LifeCycle component) {
215         getLifeCycleManager().register(component);
216     }
217 
218     /**
219      * Gets the life cycle manager for this context.
220      * <p>
221      * The default implementation lazily initializes an instance of
222      * {@link LifeCycleManager}.  Subclasses may override to provide a custom 
223      * manager implementation, but must take care to return the same manager
224      * object for each call to this method.
225      * <p>
226      * This is exposed primarily to support instrumentation for unit testing.
227      * 
228      * @return manager object 
229      */
230     synchronized LifeCycleManager getLifeCycleManager() {
231         if (lifeCycleManager == null) {
232             lifeCycleManager = new LifeCycleManager();
233         }
234         return lifeCycleManager;
235     }
236 
237     @Override
238     public String toString() {
239         return name;
240     }
241 
242     @Override
243     public void addScheduledFuture(ScheduledFuture<?> scheduledFuture) {
244         scheduledFutures.add(scheduledFuture);
245     }
246 
247     public List<ScheduledFuture<?>> getScheduledFutures() {
248         return new ArrayList<ScheduledFuture<?>>(scheduledFutures);
249     }
250     
251     
252 
253 }