View Javadoc

1   package ch.qos.logback.access.tomcat;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.List;
8   import java.util.Map;
9   
10  import javax.servlet.ServletContext;
11  import javax.servlet.ServletException;
12  
13  import org.apache.catalina.Lifecycle;
14  import org.apache.catalina.LifecycleListener;
15  import org.apache.catalina.connector.Request;
16  import org.apache.catalina.connector.Response;
17  import org.apache.catalina.valves.ValveBase;
18  
19  import ch.qos.logback.access.AccessConstants;
20  import ch.qos.logback.access.joran.JoranConfigurator;
21  import ch.qos.logback.access.spi.AccessEvent;
22  import ch.qos.logback.core.Appender;
23  import ch.qos.logback.core.BasicStatusManager;
24  import ch.qos.logback.core.Context;
25  import ch.qos.logback.core.CoreConstants;
26  import ch.qos.logback.core.filter.Filter;
27  import ch.qos.logback.core.joran.spi.JoranException;
28  import ch.qos.logback.core.spi.AppenderAttachable;
29  import ch.qos.logback.core.spi.AppenderAttachableImpl;
30  import ch.qos.logback.core.spi.FilterAttachable;
31  import ch.qos.logback.core.spi.FilterAttachableImpl;
32  import ch.qos.logback.core.spi.FilterReply;
33  import ch.qos.logback.core.status.InfoStatus;
34  import ch.qos.logback.core.status.StatusManager;
35  import ch.qos.logback.core.status.WarnStatus;
36  import ch.qos.logback.core.util.OptionHelper;
37  import ch.qos.logback.core.util.StatusPrinter;
38  
39  /**
40   * This class is an implementation of tomcat's Valve interface, by extending
41   * ValveBase.
42   * 
43   * <p>For more information on using LogbackValve please refer to the online
44   * documentation on <a
45   * href="http://logback.qos.ch/access.html#tomcat">logback-acces and tomcat</a>.
46   * 
47   * @author Ceki G&uuml;lc&uuml;
48   * @author S&eacute;bastien Pennec
49   */
50  public class LogbackValve extends ValveBase implements Lifecycle, Context,
51      AppenderAttachable<AccessEvent>, FilterAttachable<AccessEvent> {
52  
53    public final static String DEFAULT_CONFIG_FILE = "conf" + File.separatorChar
54        + "logback-access.xml";
55  
56    // Attributes from ContextBase:
57    private String name;
58    StatusManager sm = new BasicStatusManager();
59    // TODO propertyMap should be observable so that we can be notified
60    // when it changes so that a new instance of propertyMap can be
61    // serialized. For the time being, we ignore this shortcoming.
62    Map<String, String> propertyMap = new HashMap<String, String>();
63    Map<String, Object> objectMap = new HashMap<String, Object>();
64    private FilterAttachableImpl<AccessEvent> fai = new FilterAttachableImpl<AccessEvent>();
65  
66    AppenderAttachableImpl<AccessEvent> aai = new AppenderAttachableImpl<AccessEvent>();
67    String filename;
68    boolean quiet;
69    boolean started;
70    boolean alreadySetLogbackStatusManager = false;
71  
72    public LogbackValve() {
73      putObject(CoreConstants.EVALUATOR_MAP, new HashMap());
74    }
75  
76    public void start() {
77      if (filename == null) {
78        String tomcatHomeProperty = OptionHelper
79            .getSystemProperty("catalina.home");
80  
81        filename = tomcatHomeProperty + File.separatorChar + DEFAULT_CONFIG_FILE;
82        getStatusManager().add(
83            new InfoStatus("filename property not set. Assuming [" + filename
84                + "]", this));
85      }
86      File configFile = new File(filename);
87      if (configFile.exists()) {
88        try {
89          JoranConfigurator jc = new JoranConfigurator();
90          jc.setContext(this);
91          jc.doConfigure(filename);
92        } catch (JoranException e) {
93          // TODO can we do better than printing a stack trace on syserr?
94          e.printStackTrace();
95        }
96      } else {
97        getStatusManager().add(
98            new WarnStatus("[" + filename + "] does not exist", this));
99      }
100 
101     if (!quiet) {
102       StatusPrinter.print(getStatusManager());
103     }
104 
105     started = true;
106   }
107 
108   public String getFilename() {
109     return filename;
110   }
111 
112   public void setFilename(String filename) {
113     this.filename = filename;
114   }
115 
116   public boolean isQuiet() {
117     return quiet;
118   }
119 
120   public void setQuiet(boolean quiet) {
121     this.quiet = quiet;
122   }
123 
124   public void invoke(Request request, Response response) throws IOException,
125       ServletException {
126 
127     try {
128 
129       if (!alreadySetLogbackStatusManager) {
130         alreadySetLogbackStatusManager = true;
131         org.apache.catalina.Context tomcatContext = request.getContext();
132         if (tomcatContext != null) {
133           ServletContext sc = tomcatContext.getServletContext();
134           if (sc != null) {
135             sc.setAttribute(AccessConstants.LOGBACK_STATUS_MANAGER_KEY,
136                 getStatusManager());
137           }
138         }
139       }
140 
141       getNext().invoke(request, response);
142 
143       TomcatServerAdapter adapter = new TomcatServerAdapter(request, response);
144       AccessEvent accessEvent = new AccessEvent(request, response, adapter);
145 
146       if (getFilterChainDecision(accessEvent) == FilterReply.DENY) {
147         return;
148       }
149 
150       // TODO better exception handling
151       aai.appendLoopOnAppenders(accessEvent);
152     } finally {
153       request
154           .removeAttribute(AccessConstants.LOGBACK_STATUS_MANAGER_KEY);
155     }
156   }
157 
158   public void stop() {
159     started = false;
160   }
161 
162   public void addAppender(Appender<AccessEvent> newAppender) {
163     aai.addAppender(newAppender);
164   }
165 
166   public Iterator<Appender<AccessEvent>> iteratorForAppenders() {
167     return aai.iteratorForAppenders();
168   }
169 
170   public Appender<AccessEvent> getAppender(String name) {
171     return aai.getAppender(name);
172   }
173 
174   public boolean isAttached(Appender appender) {
175     return aai.isAttached(appender);
176   }
177 
178   public void detachAndStopAllAppenders() {
179     aai.detachAndStopAllAppenders();
180 
181   }
182 
183   public boolean detachAppender(Appender appender) {
184     return aai.detachAppender(appender);
185   }
186 
187   public boolean detachAppender(String name) {
188     return aai.detachAppender(name);
189   }
190 
191   public String getInfo() {
192     return "Logback's implementation of ValveBase";
193   }
194 
195   // Methods from ContextBase:
196   public StatusManager getStatusManager() {
197     return sm;
198   }
199 
200   public Map<String, String> getPropertyMap() {
201     return propertyMap;
202   }
203 
204   public void putProperty(String key, String val) {
205     this.propertyMap.put(key, val);
206   }
207 
208   public String getProperty(String key) {
209     return (String) this.propertyMap.get(key);
210   }
211 
212   public Object getObject(String key) {
213     return objectMap.get(key);
214   }
215 
216   public void putObject(String key, Object value) {
217     objectMap.put(key, value);
218   }
219 
220   public void addFilter(Filter<AccessEvent> newFilter) {
221     fai.addFilter(newFilter);
222   }
223 
224   public Filter getFirstFilter() {
225     return fai.getFirstFilter();
226   }
227 
228   public void clearAllFilters() {
229     fai.clearAllFilters();
230   }
231 
232   public List<Filter<AccessEvent>> getCopyOfAttachedFiltersList() {
233     return fai.getCopyOfAttachedFiltersList();
234   }
235   
236   public FilterReply getFilterChainDecision(AccessEvent event) {
237     return fai.getFilterChainDecision(event);
238   }
239 
240   public String getName() {
241     return name;
242   }
243 
244   public void setName(String name) {
245     if (this.name != null) {
246       throw new IllegalStateException(
247           "LogbackValve has been already given a name");
248     }
249     this.name = name;
250   }
251 
252   // ====== Methods from catalina Lifecycle =====
253 
254   public void addLifecycleListener(LifecycleListener arg0) {
255     // dummy NOP implementation
256   }
257 
258   public LifecycleListener[] findLifecycleListeners() {
259     return new LifecycleListener[0];
260   }
261 
262   public void removeLifecycleListener(LifecycleListener arg0) {
263     // dummy NOP implementation
264   }
265 
266 }