001
014
015 package com.liferay.portal.scripting.javascript;
016
017 import com.liferay.portal.kernel.cache.PortalCache;
018 import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
019 import com.liferay.portal.kernel.scripting.BaseScriptingExecutor;
020 import com.liferay.portal.kernel.scripting.ScriptingException;
021 import com.liferay.portal.kernel.util.AggregateClassLoader;
022 import com.liferay.portal.kernel.util.ArrayUtil;
023 import com.liferay.portal.util.ClassLoaderUtil;
024
025 import java.util.HashMap;
026 import java.util.Map;
027 import java.util.Set;
028
029 import org.mozilla.javascript.Context;
030 import org.mozilla.javascript.Script;
031 import org.mozilla.javascript.Scriptable;
032 import org.mozilla.javascript.ScriptableObject;
033 import org.mozilla.javascript.Wrapper;
034
035
038 public class JavaScriptExecutor extends BaseScriptingExecutor {
039
040 @Override
041 public void clearCache() {
042 _portalCache.removeAll();
043 }
044
045 @Override
046 public Map<String, Object> eval(
047 Set<String> allowedClasses, Map<String, Object> inputObjects,
048 Set<String> outputNames, String script, ClassLoader... classLoaders)
049 throws ScriptingException {
050
051 Script compiledScript = getCompiledScript(script, classLoaders);
052
053 try {
054 Context context = Context.enter();
055
056 Scriptable scriptable = context.initStandardObjects();
057
058 if (ArrayUtil.isNotEmpty(classLoaders)) {
059 ClassLoader aggregateClassLoader =
060 AggregateClassLoader.getAggregateClassLoader(
061 ClassLoaderUtil.getPortalClassLoader(), classLoaders);
062
063 context.setApplicationClassLoader(aggregateClassLoader);
064 }
065
066 for (Map.Entry<String, Object> entry : inputObjects.entrySet()) {
067 String key = entry.getKey();
068 Object value = entry.getValue();
069
070 ScriptableObject.putProperty(
071 scriptable, key, Context.javaToJS(value, scriptable));
072 }
073
074 if (allowedClasses != null) {
075 context.setClassShutter(
076 new JavaScriptClassVisibilityChecker(allowedClasses));
077 }
078
079 compiledScript.exec(context, scriptable);
080
081 if (outputNames == null) {
082 return null;
083 }
084
085 Map<String, Object> outputObjects = new HashMap<String, Object>();
086
087 for (String outputName : outputNames) {
088 Object property = ScriptableObject.getProperty(
089 scriptable, outputName);
090
091 if (property instanceof Wrapper) {
092 Wrapper wrapper = (Wrapper)property;
093
094 property = wrapper.unwrap();
095 }
096
097 outputObjects.put(outputName, property);
098 }
099
100 return outputObjects;
101 }
102 catch (Exception e) {
103 throw new ScriptingException(e.getMessage() + "\n\n", e);
104 }
105 finally {
106 Context.exit();
107 }
108 }
109
110 @Override
111 public String getLanguage() {
112 return _LANGUAGE;
113 }
114
115 protected Script getCompiledScript(
116 String script, ClassLoader... classLoaders) {
117
118 String key = String.valueOf(script.hashCode());
119
120 Script compiledScript = _portalCache.get(key);
121
122 if (compiledScript != null) {
123 return compiledScript;
124 }
125
126 try {
127 Context context = Context.enter();
128
129 if (ArrayUtil.isNotEmpty(classLoaders)) {
130 ClassLoader aggregateClassLoader =
131 AggregateClassLoader.getAggregateClassLoader(
132 ClassLoaderUtil.getPortalClassLoader(), classLoaders);
133
134 context.setApplicationClassLoader(aggregateClassLoader);
135 }
136
137 compiledScript = context.compileString(script, "script", 0, null);
138 }
139 finally {
140 Context.exit();
141 }
142
143 _portalCache.put(key, compiledScript);
144
145 return compiledScript;
146 }
147
148 private static final String _CACHE_NAME =
149 JavaScriptExecutor.class.getName();
150
151 private static final String _LANGUAGE = "javascript";
152
153 private PortalCache<String, Script> _portalCache =
154 SingleVMPoolUtil.getCache(_CACHE_NAME);
155
156 }