001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.scxml2; 018 019import java.util.Map; 020import java.util.concurrent.ConcurrentHashMap; 021 022import org.apache.commons.scxml2.env.groovy.GroovyEvaluator; 023import org.apache.commons.scxml2.env.javascript.JSEvaluator; 024import org.apache.commons.scxml2.env.jexl.JexlEvaluator; 025import org.apache.commons.scxml2.env.minimal.MinimalEvaluator; 026import org.apache.commons.scxml2.env.xpath.XPathEvaluator; 027import org.apache.commons.scxml2.model.ModelException; 028import org.apache.commons.scxml2.model.SCXML; 029import static org.apache.commons.scxml2.Evaluator.DEFAULT_DATA_MODEL; 030 031/** 032 * A static singleton factory for {@link EvaluatorProvider}s by supported SCXML datamodel type. 033 * <p> 034 * The EvaluatorFactory is used to automatically create an {@link Evaluator} instance for an SCXML 035 * statemachine when none has been pre-defined and configured for the {@link SCXMLExecutor}. 036 * </p> 037 * <p> 038 * The builtin supported providers are: 039 * <ul> 040 * <li>no or empty datamodel (default) or datamodel="jexl": {@link JexlEvaluator.JexlEvaluatorProvider}</li> 041 * <li>datamodel="ecmascript": {@link JSEvaluator.JSEvaluatorProvider}</li> 042 * <li>datamodel="groovy": {@link GroovyEvaluator.GroovyEvaluatorProvider}</li> 043 * <li>datamodel="xpath": {@link XPathEvaluator.XPathEvaluatorProvider}</li> 044 * <li>datamodel="null": {@link MinimalEvaluator.MinimalEvaluatorProvider}</li> 045 * </ul> 046 * </p> 047 * <p> 048 * For adding additional or overriding the builtin Evaluator implementations use 049 * {@link #registerEvaluatorProvider(EvaluatorProvider)} or {@link #unregisterEvaluatorProvider(String)}. 050 * </p> 051 * <p> 052 * The default provider can be overridden using the {@link #setDefaultProvider(EvaluatorProvider)} which will 053 * register the provider under the {@link Evaluator#DEFAULT_DATA_MODEL} ("") value for the datamodel.<br/> 054 * Note: this is <em>not</em> the same as datamodel="null"! 055 * </p> 056 */ 057public class EvaluatorFactory { 058 059 private static EvaluatorFactory INSTANCE = new EvaluatorFactory(); 060 061 private final Map<String, EvaluatorProvider> providers = new ConcurrentHashMap<String, EvaluatorProvider>(); 062 063 private EvaluatorFactory() { 064 providers.put(XPathEvaluator.SUPPORTED_DATA_MODEL, new XPathEvaluator.XPathEvaluatorProvider()); 065 providers.put(JSEvaluator.SUPPORTED_DATA_MODEL, new JSEvaluator.JSEvaluatorProvider()); 066 providers.put(GroovyEvaluator.SUPPORTED_DATA_MODEL, new GroovyEvaluator.GroovyEvaluatorProvider()); 067 providers.put(JexlEvaluator.SUPPORTED_DATA_MODEL, new JexlEvaluator.JexlEvaluatorProvider()); 068 providers.put(MinimalEvaluator.SUPPORTED_DATA_MODEL, new MinimalEvaluator.MinimalEvaluatorProvider()); 069 providers.put(DEFAULT_DATA_MODEL, providers.get(JexlEvaluator.SUPPORTED_DATA_MODEL)); 070 } 071 072 public static void setDefaultProvider(EvaluatorProvider defaultProvider) { 073 INSTANCE.providers.put(DEFAULT_DATA_MODEL, defaultProvider); 074 } 075 076 @SuppressWarnings("unused") 077 public static EvaluatorProvider getDefaultProvider() { 078 return INSTANCE.providers.get(DEFAULT_DATA_MODEL); 079 } 080 081 @SuppressWarnings("unused") 082 public static EvaluatorProvider getEvaluatorProvider(String datamodelName) { 083 return INSTANCE.providers.get(datamodelName == null ? DEFAULT_DATA_MODEL : datamodelName); 084 } 085 086 @SuppressWarnings("unused") 087 public static void registerEvaluatorProvider(EvaluatorProvider provider) { 088 INSTANCE.providers.put(provider.getSupportedDatamodel(), provider); 089 } 090 091 @SuppressWarnings("unused") 092 public static void unregisterEvaluatorProvider(String datamodelName) { 093 INSTANCE.providers.remove(datamodelName == null ? DEFAULT_DATA_MODEL : datamodelName); 094 } 095 096 /** 097 * Returns a dedicated Evaluator instance for a specific SCXML document its documentmodel. 098 * <p>If no SCXML document is provided a default Evaluator will be returned.</p> 099 * @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}