001/*
002 * JPPF.
003 * Copyright (C) 2005-2018 JPPF Team.
004 * http://www.jppf.org
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * 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.jppf.node.policy;
020
021import java.io.*;
022import java.util.*;
023
024import org.jppf.JPPFException;
025import org.jppf.scripting.*;
026import org.jppf.utils.*;
027import org.slf4j.*;
028
029/**
030 * A policy which executes an aribtrary script in its {@code accepts()} method.
031 * @author Laurent Cohen
032 */
033public class ScriptedPolicy extends ExecutionPolicy {
034  /**
035   * Explicit serialVersionUID.
036   */
037  private static final long serialVersionUID = 1L;
038  /**
039   * Logger for this class.
040   */
041  private static Logger log = LoggerFactory.getLogger(ScriptedPolicy.class);
042  /**
043   * The script specification.
044   */
045  protected final ScriptDefinition spec;
046  /**
047   * Flag set if an error is raised while executing the script,
048   * to avoid evaluating the script again.
049   */
050  protected boolean evaluationError = false;
051
052  /**
053   * Initialize this policy with a script language and a script.
054   * @param language the script language to use.
055   * @param script the script to execute.
056   */
057  public ScriptedPolicy(final String language, final String script) {
058    this.spec = new ScriptDefinition(language, script);
059  }
060
061  /**
062   * Initialize this policy with a script language and a script read from a reader.
063   * @param language the script language to use.
064   * @param scriptReader a reader from which to read the script to execute.
065   * @throws IOException if any error occurs while reading the script from the reader.
066   */
067  public ScriptedPolicy(final String language, final Reader scriptReader) throws IOException {
068    this.spec = new ScriptDefinition(language, scriptReader);
069  }
070
071  /**
072   * Initialize this policy with a script language and a script read from a file.
073   * @param language the script language to use.
074   * @param scriptFile the file containing the script to execute.
075   * @throws IOException if any error occurs while reading the script from the reader.
076   */
077  public ScriptedPolicy(final String language, final File scriptFile) throws IOException {
078    this.spec = new ScriptDefinition(language, scriptFile);
079  }
080
081  @Override
082  public boolean accepts(final PropertiesCollection<String> info) {
083    if (evaluationError) return false;
084    final Map<String, Object> variables = new HashMap<>();
085    variables.put("jppfSystemInfo", info);
086    final PolicyContext ctx = getContext();
087    if (ctx != null) {
088      variables.put("jppfSla", ctx.getSLA());
089      variables.put("jppfClientSla", ctx.getClientSLA());
090      variables.put("jppfMetadata", ctx.getMetadata());
091      variables.put("jppfDispatches", ctx.getJobDispatches());
092      variables.put("jppfStats", ctx.getStats());
093    }
094    try {
095      final Object result = spec.evaluate(variables);
096      if (!(result instanceof Boolean)) throw new JPPFException("result of scripted policy should be a boolean but instead is " + result);
097      return (Boolean) result;
098    } catch (final Exception|NoClassDefFoundError e) {
099      evaluationError = true;
100      log.error("exception occurred evaluating scripted policy: {}\npolicy is\n{}", ExceptionUtils.getStackTrace(e), this);
101    }
102    return false;
103  }
104
105  @Override
106  public String toString(final int n) {
107    final StringBuilder sb = new StringBuilder(indent(n)).append("<Script language=\"").append(spec.getLanguage()).append("\"><![CDATA[\n");
108    sb.append(spec.getScript()).append('\n');
109    return sb.append(indent(n)).append("]]></Script>\n").toString();
110  }
111}