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.joran.conditional;
15
16 import java.util.List;
17 import java.util.Stack;
18
19 import ch.qos.logback.core.CoreConstants;
20 import ch.qos.logback.core.util.EnvUtil;
21 import org.xml.sax.Attributes;
22
23 import ch.qos.logback.core.joran.action.Action;
24 import ch.qos.logback.core.joran.event.SaxEvent;
25 import ch.qos.logback.core.joran.spi.ActionException;
26 import ch.qos.logback.core.joran.spi.InterpretationContext;
27 import ch.qos.logback.core.joran.spi.Interpreter;
28 import ch.qos.logback.core.util.OptionHelper;
29
30 public class IfAction extends Action {
31     private static final String CONDITION_ATTR = "condition";
32
33     public static final String MISSING_JANINO_MSG = "Could not find Janino library on the class path. Skipping conditional processing.";
34     public static final String MISSING_JANINO_SEE = "See also " + CoreConstants.CODES_URL + "#ifJanino";
35
36     Stack<IfState> stack = new Stack<IfState>();
37
38     @Override
39     public void begin(InterpretationContext ic, String name, Attributes attributes) throws ActionException {
40
41         IfState state = new IfState();
42         boolean emptyStack = stack.isEmpty();
43         stack.push(state);
44
45         if (!emptyStack) {
46             return;
47         }
48
49         ic.pushObject(this);
50         if (!EnvUtil.isJaninoAvailable()) {
51             addError(MISSING_JANINO_MSG);
52             addError(MISSING_JANINO_SEE);
53             return;
54         }
55
56         state.active = true;
57         Condition condition = null;
58         String conditionAttribute = attributes.getValue(CONDITION_ATTR);
59
60         if (!OptionHelper.isEmpty(conditionAttribute)) {
61             conditionAttribute = OptionHelper.substVars(conditionAttribute, ic, context);
62             PropertyEvalScriptBuilder pesb = new PropertyEvalScriptBuilder(ic);
63             pesb.setContext(context);
64             try {
65                 condition = pesb.build(conditionAttribute);
66             } catch (Exception e) {
67                 addError("Failed to parse condition [" + conditionAttribute + "]", e);
68             }
69
70             if (condition != null) {
71                 state.boolResult = condition.evaluate();
72             }
73
74         }
75     }
76
77     @Override
78     public void end(InterpretationContext ic, String name) throws ActionException {
79
80         IfState state = stack.pop();
81         if (!state.active) {
82             return;
83         }
84
85         Object o = ic.peekObject();
86         if (o == null) {
87             throw new IllegalStateException("Unexpected null object on stack");
88         }
89         if (!(o instanceof IfAction)) {
90             throw new IllegalStateException("Unexpected object of type [" + o.getClass() + "] on stack");
91         }
92
93         if (o != this) {
94             throw new IllegalStateException("IfAction different then current one on stack");
95         }
96         ic.popObject();
97
98         if (state.boolResult == null) {
99             addError("Failed to determine \"if then else\" result");
100             return;
101         }
102
103         Interpreter interpreter = ic.getJoranInterpreter();
104         List<SaxEvent> listToPlay = state.thenSaxEventList;
105         if (!state.boolResult) {
106             listToPlay = state.elseSaxEventList;
107         }
108
109         // if boolResult==false & missing else, listToPlay may be null
110         if (listToPlay != null) {
111             // insert past this event
112             interpreter.getEventPlayer().addEventsDynamically(listToPlay, 1);
113         }
114
115     }
116
117     public void setThenSaxEventList(List<SaxEvent> thenSaxEventList) {
118         IfState state = stack.firstElement();
119         if (state.active) {
120             state.thenSaxEventList = thenSaxEventList;
121         } else {
122             throw new IllegalStateException("setThenSaxEventList() invoked on inactive IfAction");
123         }
124     }
125
126     public void setElseSaxEventList(List<SaxEvent> elseSaxEventList) {
127         IfState state = stack.firstElement();
128         if (state.active) {
129             state.elseSaxEventList = elseSaxEventList;
130         } else {
131             throw new IllegalStateException("setElseSaxEventList() invoked on inactive IfAction");
132         }
133
134     }
135
136     public boolean isActive() {
137         if (stack == null)
138             return false;
139         if (stack.isEmpty())
140             return false;
141         return stack.peek().active;
142     }
143 }
144
145 class IfState {
146     Boolean boolResult;
147     List<SaxEvent> thenSaxEventList;
148     List<SaxEvent> elseSaxEventList;
149     boolean active;
150 }
151