001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *      http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.oozie.coord.input.logic;
020
021import java.util.Date;
022
023import org.apache.commons.jexl2.Expression;
024import org.apache.commons.jexl2.JexlContext;
025import org.apache.commons.jexl2.JexlEngine;
026import org.apache.commons.jexl2.NamespaceResolver;
027import org.apache.commons.lang.StringUtils;
028import org.apache.oozie.CoordinatorActionBean;
029import org.apache.oozie.ErrorCode;
030import org.apache.oozie.command.CommandException;
031import org.apache.oozie.coord.CoordUtils;
032import org.apache.oozie.coord.SyncCoordAction;
033import org.apache.oozie.coord.input.dependency.CoordPullInputDependency;
034import org.apache.oozie.coord.input.dependency.CoordPushInputDependency;
035import org.apache.oozie.util.ELEvaluator;
036import org.apache.oozie.util.LogUtils;
037import org.apache.oozie.util.XLog;
038import org.apache.oozie.util.XmlUtils;
039import org.jdom.Element;
040import org.jdom.JDOMException;
041
042public class CoordInputLogicEvaluatorUtil {
043
044    private CoordinatorActionBean coordAction = null;
045    private XLog log = XLog.getLog(getClass());
046
047    public CoordInputLogicEvaluatorUtil(CoordinatorActionBean coordAction) {
048        this.coordAction = coordAction;
049        LogUtils.setLogInfo(coordAction);
050
051    }
052
053    public CoordInputLogicEvaluatorUtil() {
054    }
055
056    /**
057     * Check pull missing dependencies.
058     *
059     * @return true, if successful
060     * @throws JDOMException the JDOM exception
061     */
062    public boolean checkPullMissingDependencies() throws JDOMException {
063        JexlEngine jexl = new OozieJexlEngine();
064
065        String expression = CoordUtils.getInputLogic(coordAction.getActionXml().toString());
066        if (StringUtils.isEmpty(expression)) {
067            return true;
068        }
069        Expression e = jexl.createExpression(expression);
070
071        JexlContext jc = new OozieJexlParser(jexl, new CoordInputLogicBuilder(new CoordInputLogicEvaluatorPhaseOne(
072                coordAction, coordAction.getPullInputDependencies())));
073        CoordInputLogicEvaluatorResult result = (CoordInputLogicEvaluatorResult) e.evaluate(jc);
074        log.debug("Input logic expression for [{0}] and evaluate result is [{1}]", expression, result.getStatus());
075
076        if (result.isWaiting()) {
077            return false;
078        }
079        return result.isTrue();
080    }
081
082    /**
083     * Validate input logic.
084     *
085     * @throws JDOMException the JDOM exception
086     * @throws CommandException
087     */
088    public void validateInputLogic() throws JDOMException, CommandException {
089        JexlEngine jexl = new OozieJexlEngine();
090        String expression = CoordUtils.getInputLogic(coordAction.getActionXml().toString());
091        if (StringUtils.isEmpty(expression)) {
092            return;
093        }
094        Expression e = jexl.createExpression(expression);
095        JexlContext jc = new OozieJexlParser(jexl, new CoordInputLogicBuilder(
096                new CoordInputLogicEvaluatorPhaseValidate(coordAction)));
097        try {
098            Object result = e.evaluate(jc);
099            log.debug("Input logic expression is [{0}] and evaluate result is [{1}]", expression, result);
100
101        }
102        catch (RuntimeException re) {
103            throw new CommandException(ErrorCode.E1028, re.getCause().getMessage());
104        }
105
106    }
107
108    /**
109     * Get input dependencies.
110     *
111     * @param name the name
112     * @param syncCoordAction the sync coord action
113     * @return the string
114     * @throws JDOMException the JDOM exception
115     */
116    public String getInputDependencies(String name, SyncCoordAction syncCoordAction) throws JDOMException {
117        JexlEngine jexl = new OozieJexlEngine();
118
119        CoordinatorActionBean coordAction = new CoordinatorActionBean();
120        ELEvaluator eval = ELEvaluator.getCurrent();
121        coordAction.setId(syncCoordAction.getActionId());
122        Element eJob = XmlUtils.parseXml(eval.getVariable(".actionInputLogic").toString());
123        String expression = new InputLogicParser().parseWithName(eJob, name);
124
125        Expression e = jexl.createExpression(expression);
126
127        CoordPullInputDependency pull = (CoordPullInputDependency) syncCoordAction.getPullDependencies();
128        CoordPushInputDependency push = (CoordPushInputDependency) syncCoordAction.getPushDependencies();
129
130        coordAction.setPushInputDependencies(push);
131
132        coordAction.setPullInputDependencies(pull);
133
134        JexlContext jc = new OozieJexlParser(jexl, new CoordInputLogicBuilder(new CoordInputLogicEvaluatorPhaseThree(
135                coordAction, eval)));
136        CoordInputLogicEvaluatorResult result = (CoordInputLogicEvaluatorResult) e.evaluate(jc);
137
138        if (result == null || !result.isTrue()) {
139            log.debug("Input logic expression for [{0}] is [{1}] and it is not resolved", name, expression);
140            return "${coord:dataIn('" + name + "')}";
141        }
142        else {
143            log.debug("Input logic expression for [{0}] is [{1}] and evaluate result is [{2}]", name, expression,
144                    result.getStatus());
145            return result.getDataSets();
146        }
147
148    }
149
150    /**
151     * Check push dependencies.
152     *
153     * @return true, if successful
154     * @throws JDOMException the JDOM exception
155     */
156    public boolean checkPushDependencies() throws JDOMException {
157        JexlEngine jexl = new OozieJexlEngine();
158
159        String expression = CoordUtils.getInputLogic(coordAction.getActionXml().toString());
160        if (StringUtils.isEmpty(expression)) {
161            return true;
162        }
163
164        Expression e = jexl.createExpression(expression);
165        JexlContext jc = new OozieJexlParser(jexl, new CoordInputLogicBuilder(new CoordInputLogicEvaluatorPhaseOne(
166                coordAction, coordAction.getPushInputDependencies())));
167        CoordInputLogicEvaluatorResult result = (CoordInputLogicEvaluatorResult) e.evaluate(jc);
168        log.debug("Input logic expression for [{0}] and evaluate result is [{1}]", expression, result.getStatus());
169
170        if (result.isWaiting()) {
171            return false;
172        }
173        return result.isTrue();
174    }
175
176    /**
177     * Check unresolved.
178     *
179     * @param actualTime the actual time
180     * @return true, if successful
181     * @throws JDOMException the JDOM exception
182     */
183    public boolean checkUnResolved(Date actualTime) throws JDOMException {
184        JexlEngine jexl = new OozieJexlEngine();
185
186        String expression = CoordUtils.getInputLogic(coordAction.getActionXml().toString());
187        if (StringUtils.isEmpty(expression)) {
188            return true;
189        }
190
191        Expression e = jexl.createExpression(expression);
192        JexlContext jc = new OozieJexlParser(jexl, new CoordInputLogicBuilder(new CoordInputLogicEvaluatorPhaseTwo(
193                coordAction, actualTime)));
194        CoordInputLogicEvaluatorResult result = (CoordInputLogicEvaluatorResult) e.evaluate(jc);
195        log.debug("Input logic expression for [{0}] and evaluate result is [{1}]", expression, result.getStatus());
196
197        if (result.isWaiting()) {
198            return false;
199        }
200        return result.isTrue();
201
202    }
203
204    public class OozieJexlParser implements JexlContext, NamespaceResolver {
205        private final JexlEngine jexl;
206        private final CoordInputLogicBuilder object;
207
208        @Override
209        public Object resolveNamespace(String name) {
210            return object;
211        }
212
213        public OozieJexlParser(JexlEngine engine, CoordInputLogicBuilder wrapped) {
214            this.jexl = engine;
215            this.object = wrapped;
216        }
217
218        public Object get(String name) {
219            return jexl.getProperty(object, name);
220        }
221
222        public void set(String name, Object value) {
223            jexl.setProperty(object, name, value);
224        }
225
226        public boolean has(String name) {
227            return jexl.getUberspect().getPropertyGet(object, name, null) != null;
228        }
229
230    }
231
232}