1 /*
2  * Hibernate Validator, declare and validate application constraints
3  *
4  * License: Apache License, Version 2.0
5  * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
6  */

7 package org.hibernate.validator.internal.engine.scripting;
8
9 import java.lang.invoke.MethodHandles;
10 import java.security.AccessController;
11 import java.security.PrivilegedAction;
12
13 import javax.script.ScriptEngine;
14 import javax.script.ScriptEngineManager;
15
16 import org.hibernate.validator.internal.util.logging.Log;
17 import org.hibernate.validator.internal.util.logging.LoggerFactory;
18 import org.hibernate.validator.internal.util.privilegedactions.GetClassLoader;
19 import org.hibernate.validator.spi.scripting.AbstractCachingScriptEvaluatorFactory;
20 import org.hibernate.validator.spi.scripting.ScriptEngineScriptEvaluator;
21 import org.hibernate.validator.spi.scripting.ScriptEvaluationException;
22 import org.hibernate.validator.spi.scripting.ScriptEvaluator;
23
24 /**
25  * Factory responsible for the creation of JSR 223 based {@link ScriptEngineScriptEvaluator}s. This
26  * class is thread-safe.
27  *
28  * @author Gunnar Morling
29  * @author Kevin Pollet &lt;kevin.pollet@serli.com&gt; (C) 2011 SERLI
30  * @author Marko Bekhta
31  * @author Guillaume Smet
32  */

33 public class DefaultScriptEvaluatorFactory extends AbstractCachingScriptEvaluatorFactory {
34
35     private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
36
37     private ClassLoader classLoader;
38
39     private volatile ScriptEngineManager scriptEngineManager;
40
41     private volatile ScriptEngineManager threadContextClassLoaderScriptEngineManager;
42
43     public DefaultScriptEvaluatorFactory(ClassLoader externalClassLoader) {
44         classLoader = externalClassLoader == null ? DefaultScriptEvaluatorFactory.class.getClassLoader() : externalClassLoader;
45     }
46
47     @Override
48     public void clear() {
49         super.clear();
50
51         classLoader = null;
52         scriptEngineManager = null;
53         threadContextClassLoaderScriptEngineManager = null;
54     }
55
56     @Override
57     protected ScriptEvaluator createNewScriptEvaluator(String languageName) throws ScriptEvaluationException {
58         ScriptEngine engine = getScriptEngineManager().getEngineByName( languageName );
59
60         // fall back to the TCCL
61         if ( engine == null ) {
62             engine = getThreadContextClassLoaderScriptEngineManager().getEngineByName( languageName );
63         }
64
65         if ( engine == null ) {
66             throw LOG.getUnableToFindScriptEngineException( languageName );
67         }
68
69         return new ScriptEngineScriptEvaluator( engine );
70     }
71
72     private ScriptEngineManager getScriptEngineManager() {
73         if ( scriptEngineManager == null ) {
74             synchronized ( this ) {
75                 if ( scriptEngineManager == null ) {
76                     scriptEngineManager = new ScriptEngineManager( classLoader );
77                 }
78             }
79         }
80         return scriptEngineManager;
81     }
82
83     private ScriptEngineManager getThreadContextClassLoaderScriptEngineManager() {
84         if ( threadContextClassLoaderScriptEngineManager == null ) {
85             synchronized ( this ) {
86                 if ( threadContextClassLoaderScriptEngineManager == null ) {
87                     threadContextClassLoaderScriptEngineManager = new ScriptEngineManager( run( GetClassLoader.fromContext() ) );
88                 }
89             }
90         }
91         return threadContextClassLoaderScriptEngineManager;
92     }
93
94     /**
95      * Runs the given privileged action, using a privileged block if required.
96      * <p>
97      * <b>NOTE:</b> This must never be changed into a publicly available method to avoid execution of arbitrary
98      * privileged actions within HV's protection domain.
99      */

100     private static <T> T run(PrivilegedAction<T> action) {
101         return System.getSecurityManager() != null ? AccessController.doPrivileged( action ) : action.run();
102     }
103 }
104