View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2013, 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  
18  import java.util.HashMap;
19  import java.util.Map;
20  import java.util.concurrent.ExecutorService;
21  
22  import ch.qos.logback.core.spi.LifeCycle;
23  import ch.qos.logback.core.spi.LogbackLock;
24  import ch.qos.logback.core.status.StatusManager;
25  import ch.qos.logback.core.util.ExecutorServiceUtil;
26  
27  public class ContextBase implements Context, LifeCycle {
28  
29    private long birthTime = System.currentTimeMillis();
30  
31    private String name;
32    private StatusManager sm = new BasicStatusManager();
33    // TODO propertyMap should be observable so that we can be notified
34    // when it changes so that a new instance of propertyMap can be
35    // serialized. For the time being, we ignore this shortcoming.
36    Map<String, String> propertyMap = new HashMap<String, String>();
37    Map<String, Object> objectMap = new HashMap<String, Object>();
38  
39    LogbackLock configurationLock = new LogbackLock();
40  
41    private volatile ExecutorService executorService;
42    private LifeCycleManager lifeCycleManager;
43    private boolean started;
44    
45    public StatusManager getStatusManager() {
46      return sm;
47    }
48  
49    /**
50     * Set the {@link StatusManager} for this context. Note that by default this
51     * context is initialized with a {@link BasicStatusManager}. A null value for
52     * the 'statusManager' argument is not allowed.
53     * <p/>
54     * <p> A malicious attacker can set the status manager to a dummy instance,
55     * disabling internal error reporting.
56     *
57     * @param statusManager the new status manager
58     */
59    public void setStatusManager(StatusManager statusManager) {
60      // this method was added in response to http://jira.qos.ch/browse/LBCORE-35
61      if (statusManager == null) {
62        throw new IllegalArgumentException("null StatusManager not allowed");
63      }
64      this.sm = statusManager;
65    }
66  
67    public Map<String, String> getCopyOfPropertyMap() {
68      return new HashMap<String, String>(propertyMap);
69    }
70  
71    public void putProperty(String key, String val) {
72      this.propertyMap.put(key, val);
73    }
74  
75    /**
76     * Given a key, return the corresponding property value. If invoked with
77     * the special key "CONTEXT_NAME", the name of the context is returned.
78     *
79     * @param key
80     * @return
81     */
82    public String getProperty(String key) {
83      if (CONTEXT_NAME_KEY.equals(key))
84        return getName();
85  
86      return (String) this.propertyMap.get(key);
87    }
88  
89    public Object getObject(String key) {
90      return objectMap.get(key);
91    }
92  
93    public void putObject(String key, Object value) {
94      objectMap.put(key, value);
95    }
96  
97    public String getName() {
98      return name;
99    }
100 
101   public void start() {
102     // We'd like to create the executor service here, but we can't;
103     // ContextBase has not always implemented LifeCycle and there are *many*
104     // uses (mostly in tests) that would need to be modified.
105     started = true;
106   }
107   
108   public void stop() {
109     // We don't check "started" here, because the executor service uses
110     // lazy initialization, rather than being created in the start method
111     stopExecutorService();
112     started = false;
113   }
114 
115   public boolean isStarted() {
116     return started;
117   }
118 
119   /**
120    * Clear the internal objectMap and all properties.
121    */
122   public void reset() {
123     getLifeCycleManager().reset();
124     propertyMap.clear();
125     objectMap.clear();
126   }
127 
128   /**
129    * The context name can be set only if it is not already set, or if the
130    * current name is the default context name, namely "default", or if the
131    * current name and the old name are the same.
132    *
133    * @throws IllegalStateException if the context already has a name, other than "default".
134    */
135   public void setName(String name) throws IllegalStateException {
136     if (name != null && name.equals(this.name)) {
137       return; // idempotent naming
138     }
139     if (this.name == null
140             || CoreConstants.DEFAULT_CONTEXT_NAME.equals(this.name)) {
141       this.name = name;
142     } else {
143       throw new IllegalStateException("Context has been already given a name");
144     }
145   }
146 
147   public long getBirthTime() {
148     return birthTime;
149   }
150 
151   public Object getConfigurationLock() {
152     return configurationLock;
153   }
154 
155   public ExecutorService getExecutorService() {
156     if (executorService == null) {
157       synchronized (this) {
158         if (executorService == null) {
159           executorService = ExecutorServiceUtil.newExecutorService();
160         }
161       }
162     }
163     return executorService; 
164   }
165 
166   private synchronized void stopExecutorService() {
167     if (executorService != null) {
168       ExecutorServiceUtil.shutdown(executorService);
169       executorService = null;
170     }
171   }
172   
173   public void register(LifeCycle component) {
174     getLifeCycleManager().register(component);
175   }
176 
177   /**
178    * Gets the life cycle manager for this context.
179    * <p>
180    * The default implementation lazily initializes an instance of
181    * {@link LifeCycleManager}.  Subclasses may override to provide a custom 
182    * manager implementation, but must take care to return the same manager
183    * object for each call to this method.
184    * <p>
185    * This is exposed primarily to support instrumentation for unit testing.
186    * 
187    * @return manager object 
188    */
189   synchronized LifeCycleManager getLifeCycleManager() {
190     if (lifeCycleManager == null) {
191       lifeCycleManager = new LifeCycleManager();
192     }
193     return lifeCycleManager;
194   }
195   
196   @Override
197   public String toString() {
198     return name;
199   }
200 
201 }