View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.scxml2;
18  
19  import java.util.Map;
20  import java.util.concurrent.ConcurrentHashMap;
21  
22  import org.apache.commons.scxml2.env.groovy.GroovyEvaluator;
23  import org.apache.commons.scxml2.env.javascript.JSEvaluator;
24  import org.apache.commons.scxml2.env.jexl.JexlEvaluator;
25  import org.apache.commons.scxml2.env.minimal.MinimalEvaluator;
26  import org.apache.commons.scxml2.env.xpath.XPathEvaluator;
27  import org.apache.commons.scxml2.model.ModelException;
28  import org.apache.commons.scxml2.model.SCXML;
29  import static org.apache.commons.scxml2.Evaluator.DEFAULT_DATA_MODEL;
30  
31  /**
32   * A static singleton factory for {@link EvaluatorProvider}s by supported SCXML datamodel type.
33   * <p>
34   *  The EvaluatorFactory is used to automatically create an {@link Evaluator} instance for an SCXML
35   *  statemachine when none has been pre-defined and configured for the {@link SCXMLExecutor}.
36   * </p>
37   * <p>
38   *  The builtin supported providers are:
39   *  <ul>
40   *      <li>no or empty datamodel (default) or datamodel="jexl": {@link JexlEvaluator.JexlEvaluatorProvider}</li>
41   *      <li>datamodel="ecmascript": {@link JSEvaluator.JSEvaluatorProvider}</li>
42   *      <li>datamodel="groovy": {@link GroovyEvaluator.GroovyEvaluatorProvider}</li>
43   *      <li>datamodel="xpath": {@link XPathEvaluator.XPathEvaluatorProvider}</li>
44   *      <li>datamodel="null": {@link MinimalEvaluator.MinimalEvaluatorProvider}</li>
45   *  </ul>
46   *  </p>
47   *  <p>
48   *  For adding additional or overriding the builtin Evaluator implementations use
49   *  {@link #registerEvaluatorProvider(EvaluatorProvider)} or {@link #unregisterEvaluatorProvider(String)}.
50   *  </p>
51   *  <p>
52   *  The default provider can be overridden using the {@link #setDefaultProvider(EvaluatorProvider)} which will
53   *  register the provider under the {@link Evaluator#DEFAULT_DATA_MODEL} ("") value for the datamodel.<br/>
54   *  Note: this is <em>not</em> the same as datamodel="null"!
55   * </p>
56   */
57  public class EvaluatorFactory {
58  
59      private static EvaluatorFactory INSTANCE = new EvaluatorFactory();
60  
61      private final Map<String, EvaluatorProvider> providers = new ConcurrentHashMap<String, EvaluatorProvider>();
62  
63      private EvaluatorFactory() {
64          providers.put(XPathEvaluator.SUPPORTED_DATA_MODEL, new XPathEvaluator.XPathEvaluatorProvider());
65          providers.put(JSEvaluator.SUPPORTED_DATA_MODEL, new JSEvaluator.JSEvaluatorProvider());
66          providers.put(GroovyEvaluator.SUPPORTED_DATA_MODEL, new GroovyEvaluator.GroovyEvaluatorProvider());
67          providers.put(JexlEvaluator.SUPPORTED_DATA_MODEL, new JexlEvaluator.JexlEvaluatorProvider());
68          providers.put(MinimalEvaluator.SUPPORTED_DATA_MODEL, new MinimalEvaluator.MinimalEvaluatorProvider());
69          providers.put(DEFAULT_DATA_MODEL, providers.get(JexlEvaluator.SUPPORTED_DATA_MODEL));
70      }
71  
72      public static void setDefaultProvider(EvaluatorProvider defaultProvider) {
73          INSTANCE.providers.put(DEFAULT_DATA_MODEL, defaultProvider);
74      }
75  
76      @SuppressWarnings("unused")
77      public static EvaluatorProvider getDefaultProvider() {
78          return INSTANCE.providers.get(DEFAULT_DATA_MODEL);
79      }
80  
81      @SuppressWarnings("unused")
82      public static EvaluatorProvider getEvaluatorProvider(String datamodelName) {
83          return INSTANCE.providers.get(datamodelName == null ? DEFAULT_DATA_MODEL : datamodelName);
84      }
85  
86      @SuppressWarnings("unused")
87      public static void registerEvaluatorProvider(EvaluatorProvider provider) {
88          INSTANCE.providers.put(provider.getSupportedDatamodel(), provider);
89      }
90  
91      @SuppressWarnings("unused")
92      public static void unregisterEvaluatorProvider(String datamodelName) {
93          INSTANCE.providers.remove(datamodelName == null ? DEFAULT_DATA_MODEL : datamodelName);
94      }
95  
96      /**
97       * Returns a dedicated Evaluator instance for a specific SCXML document its documentmodel.
98       * <p>If no SCXML document is provided a default Evaluator will be returned.</p>
99       * @param document The document to return a dedicated Evaluator for. May be null to retrieve the default Evaluator.
100      * @return a new and not sharable Evaluator instance for the provided document, or a default Evaluator otherwise
101      * @throws ModelException If the SCXML document datamodel is not supported.
102      */
103     public static Evaluator getEvaluator(SCXML document) throws ModelException {
104         String datamodelName = document != null ? document.getDatamodelName() : null;
105         EvaluatorProvider provider = INSTANCE.providers.get(datamodelName == null ? DEFAULT_DATA_MODEL : datamodelName);
106         if (provider == null) {
107             throw new ModelException("Unsupported SCXML document datamodel \""+(datamodelName)+"\"");
108         }
109         return document != null ? provider.getEvaluator(document) : provider.getEvaluator();
110     }
111 }