9 changed files with 16 additions and 364 deletions
@ -1,65 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.script.api.mvel; |
|||
|
|||
import org.mvel2.compiler.Accessor; |
|||
import org.mvel2.compiler.ExecutableAccessor; |
|||
import org.mvel2.compiler.ExecutableStatement; |
|||
import org.mvel2.integration.VariableResolverFactory; |
|||
import org.mvel2.optimizers.impl.refl.collection.ExprValueAccessor; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
public class TbMapCreator implements Accessor { |
|||
private Accessor[] keys; |
|||
private Accessor[] vals; |
|||
private int size; |
|||
|
|||
public Object getValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory) { |
|||
Map map = new HashMap<>(size * 2); |
|||
for (int i = size - 1; i != -1; i--) { |
|||
//noinspection unchecked
|
|||
map.put(getKey(i, ctx, elCtx, variableFactory), vals[i].getValue(ctx, elCtx, variableFactory)); |
|||
} |
|||
return map; |
|||
} |
|||
|
|||
private Object getKey(int index, Object ctx, Object elCtx, VariableResolverFactory variableFactory) { |
|||
Accessor keyAccessor = keys[index]; |
|||
if (keyAccessor instanceof ExprValueAccessor) { |
|||
ExecutableStatement executableStatement = ((ExprValueAccessor) keyAccessor).stmt; |
|||
if (executableStatement instanceof ExecutableAccessor) { |
|||
return ((ExecutableAccessor) executableStatement).getNode().getName(); |
|||
} |
|||
} |
|||
return keys[index].getValue(ctx, elCtx, variableFactory); |
|||
} |
|||
|
|||
public TbMapCreator(Accessor[] keys, Accessor[] vals) { |
|||
this.size = (this.keys = keys).length; |
|||
this.vals = vals; |
|||
} |
|||
|
|||
public Object setValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory, Object value) { |
|||
// not implemented
|
|||
return null; |
|||
} |
|||
|
|||
public Class getKnownEgressType() { |
|||
return Map.class; |
|||
} |
|||
} |
|||
@ -1,92 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.script.api.mvel; |
|||
|
|||
import org.mvel2.compiler.AbstractParser; |
|||
|
|||
import java.net.URL; |
|||
import java.net.URLClassLoader; |
|||
import java.util.HashSet; |
|||
import java.util.Set; |
|||
|
|||
public class TbMvelClassLoader extends URLClassLoader { |
|||
|
|||
private static final Set<String> allowedClasses = new HashSet<>(); |
|||
private static final Set<String> allowedPackages = new HashSet<>(); |
|||
|
|||
static { |
|||
|
|||
AbstractParser.LITERALS.remove("System"); |
|||
AbstractParser.LITERALS.remove("Runtime"); |
|||
AbstractParser.LITERALS.remove("Class"); |
|||
AbstractParser.LITERALS.remove("ClassLoader"); |
|||
AbstractParser.LITERALS.remove("Thread"); |
|||
AbstractParser.LITERALS.remove("Compiler"); |
|||
AbstractParser.LITERALS.remove("ThreadLocal"); |
|||
AbstractParser.LITERALS.remove("SecurityManager"); |
|||
|
|||
AbstractParser.CLASS_LITERALS.remove("System"); |
|||
AbstractParser.CLASS_LITERALS.remove("Runtime"); |
|||
AbstractParser.CLASS_LITERALS.remove("Class"); |
|||
AbstractParser.CLASS_LITERALS.remove("ClassLoader"); |
|||
AbstractParser.CLASS_LITERALS.remove("Thread"); |
|||
AbstractParser.CLASS_LITERALS.remove("Compiler"); |
|||
AbstractParser.CLASS_LITERALS.remove("ThreadLocal"); |
|||
AbstractParser.CLASS_LITERALS.remove("SecurityManager"); |
|||
AbstractParser.CLASS_LITERALS.put("JSON", TbJson.class); |
|||
AbstractParser.LITERALS.put("JSON", TbJson.class); |
|||
|
|||
AbstractParser.CLASS_LITERALS.values().forEach(val -> allowedClasses.add(((Class) val).getName())); |
|||
} |
|||
|
|||
static { |
|||
allowedPackages.add("org.mvel2"); |
|||
allowedPackages.add("java.util"); |
|||
} |
|||
|
|||
public TbMvelClassLoader() { |
|||
super(new URL[0], Thread.currentThread().getContextClassLoader()); |
|||
} |
|||
|
|||
@Override |
|||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { |
|||
if (!classNameAllowed(name)) { |
|||
throw new ClassNotFoundException(); |
|||
} |
|||
return super.loadClass(name, resolve); |
|||
} |
|||
|
|||
@Override |
|||
public Class<?> loadClass(String name) throws ClassNotFoundException { |
|||
if (!classNameAllowed(name)) { |
|||
throw new ClassNotFoundException(); |
|||
} |
|||
return super.loadClass(name); |
|||
} |
|||
|
|||
private boolean classNameAllowed(String name) { |
|||
if (allowedClasses.contains(name)) { |
|||
return true; |
|||
} |
|||
for (String pkgName : allowedPackages) { |
|||
if (name.startsWith(pkgName)) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.script.api.mvel; |
|||
|
|||
import org.mvel2.ParserConfiguration; |
|||
import org.mvel2.integration.VariableResolverFactory; |
|||
|
|||
public class TbMvelParserConfiguration extends ParserConfiguration { |
|||
|
|||
private static final long serialVersionUID = 5558151976348875590L; |
|||
|
|||
TbMvelParserConfiguration() { |
|||
setClassLoader(new TbMvelClassLoader()); |
|||
} |
|||
|
|||
@Override |
|||
public VariableResolverFactory getVariableFactory(VariableResolverFactory factory) { |
|||
if (Thread.interrupted()) { |
|||
throw new RuntimeException("Thread is interrupted!"); |
|||
} |
|||
return new TbMvelResolverFactory(factory); |
|||
} |
|||
|
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.script.api.mvel; |
|||
|
|||
import org.mvel2.integration.VariableResolver; |
|||
import org.mvel2.integration.VariableResolverFactory; |
|||
import org.mvel2.integration.impl.StackResetResolverFactory; |
|||
|
|||
public class TbMvelResolverFactory extends StackResetResolverFactory { |
|||
|
|||
public TbMvelResolverFactory(VariableResolverFactory delegate) { |
|||
super(delegate); |
|||
} |
|||
|
|||
@Override |
|||
public VariableResolver getVariableResolver(String name) { |
|||
if (Thread.interrupted()) { |
|||
throw new RuntimeException("Thread is interrupted!"); |
|||
} |
|||
return super.getVariableResolver(name); |
|||
} |
|||
} |
|||
@ -1,120 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2022 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.script.api.mvel; |
|||
|
|||
import org.mvel2.ParserContext; |
|||
import org.mvel2.compiler.Accessor; |
|||
import org.mvel2.integration.VariableResolverFactory; |
|||
import org.mvel2.optimizers.impl.refl.ReflectiveAccessorOptimizer; |
|||
import org.mvel2.optimizers.impl.refl.collection.ArrayCreator; |
|||
import org.mvel2.optimizers.impl.refl.collection.ExprValueAccessor; |
|||
import org.mvel2.optimizers.impl.refl.collection.ListCreator; |
|||
import org.mvel2.optimizers.impl.refl.nodes.Union; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import static org.mvel2.util.CompilerTools.expectType; |
|||
import static org.mvel2.util.ParseTools.findClass; |
|||
import static org.mvel2.util.ParseTools.getBaseComponentType; |
|||
import static org.mvel2.util.ParseTools.getSubComponentType; |
|||
import static org.mvel2.util.ParseTools.repeatChar; |
|||
|
|||
public class TbReflectiveAccessorOptimizer extends ReflectiveAccessorOptimizer { |
|||
private Object ctx; |
|||
private Class returnType; |
|||
private VariableResolverFactory variableFactory; |
|||
|
|||
@Override |
|||
public Accessor optimizeCollection(ParserContext pCtx, Object o, Class type, char[] property, int start, int offset, |
|||
Object ctx, Object thisRef, VariableResolverFactory factory) { |
|||
this.start = this.cursor = start; |
|||
this.length = start + offset; |
|||
this.returnType = type; |
|||
this.ctx = ctx; |
|||
this.variableFactory = factory; |
|||
this.pCtx = pCtx; |
|||
|
|||
Accessor root = _getAccessor(o, returnType); |
|||
|
|||
if (property != null && length > start) { |
|||
return new Union(pCtx, root, property, cursor, offset); |
|||
} else { |
|||
return root; |
|||
} |
|||
} |
|||
|
|||
private Accessor _getAccessor(Object o, Class type) { |
|||
if (o instanceof List) { |
|||
Accessor[] a = new Accessor[((List) o).size()]; |
|||
int i = 0; |
|||
|
|||
for (Object item : (List) o) { |
|||
a[i++] = _getAccessor(item, type); |
|||
} |
|||
|
|||
returnType = List.class; |
|||
|
|||
return new ListCreator(a); |
|||
} else if (o instanceof Map) { |
|||
Accessor[] k = new Accessor[((Map) o).size()]; |
|||
Accessor[] v = new Accessor[k.length]; |
|||
int i = 0; |
|||
|
|||
for (Object item : ((Map) o).keySet()) { |
|||
k[i] = _getAccessor(item, type); // key
|
|||
v[i++] = _getAccessor(((Map) o).get(item), type); // value
|
|||
} |
|||
|
|||
returnType = Map.class; |
|||
|
|||
return new TbMapCreator(k, v); |
|||
} else if (o instanceof Object[]) { |
|||
Accessor[] a = new Accessor[((Object[]) o).length]; |
|||
int i = 0; |
|||
int dim = 0; |
|||
|
|||
if (type != null) { |
|||
String nm = type.getName(); |
|||
while (nm.charAt(dim) == '[') dim++; |
|||
} else { |
|||
type = Object[].class; |
|||
dim = 1; |
|||
} |
|||
|
|||
try { |
|||
Class base = getBaseComponentType(type); |
|||
Class cls = dim > 1 ? findClass(null, repeatChar('[', dim - 1) + "L" + base.getName() + ";", pCtx) |
|||
: type; |
|||
|
|||
for (Object item : (Object[]) o) { |
|||
expectType(pCtx, a[i++] = _getAccessor(item, cls), base, true); |
|||
} |
|||
|
|||
return new ArrayCreator(a, getSubComponentType(type)); |
|||
} catch (ClassNotFoundException e) { |
|||
throw new RuntimeException("this error should never throw:" + getBaseComponentType(type).getName(), e); |
|||
} |
|||
} else { |
|||
if (returnType == null) returnType = Object.class; |
|||
if (type.isArray()) { |
|||
return new ExprValueAccessor((String) o, type, ctx, variableFactory, pCtx); |
|||
} else { |
|||
return new ExprValueAccessor((String) o, Object.class, ctx, variableFactory, pCtx); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue