Author: shawkins
Date: 2012-08-28 15:41:34 -0400 (Tue, 28 Aug 2012)
New Revision: 4378
Added:
trunk/engine/src/main/java/org/teiid/query/eval/TeiidScriptEngine.java
Modified:
trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java
trunk/engine/src/main/java/org/teiid/query/metadata/TransformationMetadata.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/ObjectTableNode.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/ObjectTable.java
trunk/engine/src/main/resources/org/teiid/query/i18n.properties
trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-2141 adding teiid_script
Modified: trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java 2012-08-28 18:31:49 UTC
(rev 4377)
+++ trunk/engine/src/main/java/org/teiid/query/QueryPlugin.java 2012-08-28 19:41:34 UTC
(rev 4378)
@@ -528,5 +528,6 @@
TEIID31108, //datasource not available
TEIID31109, //invalid scripting language
TEIID31110, //invalid script
+ TEIID31111, //invalid teiid script
}
}
Added: trunk/engine/src/main/java/org/teiid/query/eval/TeiidScriptEngine.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/TeiidScriptEngine.java
(rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/eval/TeiidScriptEngine.java 2012-08-28
19:41:34 UTC (rev 4378)
@@ -0,0 +1,191 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.query.eval;
+
+import java.beans.BeanInfo;
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.MethodDescriptor;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.regex.Pattern;
+
+import javax.script.AbstractScriptEngine;
+import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+
+import org.teiid.core.util.LRUCache;
+import org.teiid.core.util.ObjectConverterUtil;
+import org.teiid.query.QueryPlugin;
+
+/**
+ * A simplistic script engine that supports root variable access and 0-ary methods on the
subsequent objects.
+ */
+public final class TeiidScriptEngine extends AbstractScriptEngine implements Compilable
{
+ private static Map<ClassLoader, Map<Class<?>, Map<String,
Method>>> properties = new WeakHashMap<ClassLoader, Map<Class<?>,
Map<String, Method>>>(100);
+ private static Pattern splitter = Pattern.compile("\\."); //$NON-NLS-1$
+
+ @Override
+ public Bindings createBindings() {
+ return new SimpleBindings();
+ }
+
+ @Override
+ public CompiledScript compile(String script) throws ScriptException {
+ final String[] parts = splitter.split(script);
+ for (int i = 1; i < parts.length; i++) {
+ String string = parts[i];
+ for (int j = 0; j < string.length(); j++) {
+ if (!Character.isJavaIdentifierPart(string.charAt(j))) {
+ throw new ScriptException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30431,string,
string.charAt(j)));
+ }
+ }
+ }
+ return new CompiledScript() {
+
+ @Override
+ public ScriptEngine getEngine() {
+ return TeiidScriptEngine.this;
+ }
+
+ @Override
+ public Object eval(ScriptContext sc) throws ScriptException {
+ if (sc == null) {
+ throw new NullPointerException();
+ }
+ Object obj = null;
+ if (parts.length > 0) {
+ obj = sc.getAttribute(parts[0]);
+ }
+ if (obj == null) {
+ return null;
+ }
+ for (int i = 1; i < parts.length; i++) {
+ String part = parts[i];
+ Map<String, Method> methodMap = getMethodMap(obj.getClass());
+ Method m = methodMap.get(part);
+ if (m == null) {
+ throw new ScriptException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31111, part,
obj.getClass()));
+ }
+ try {
+ obj = m.invoke(obj);
+ } catch (IllegalAccessException e) {
+ throw new ScriptException(e);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof Exception) {
+ throw new ScriptException((Exception) e.getCause());
+ }
+ throw new ScriptException(e);
+ }
+ }
+ return obj;
+ }
+ };
+ }
+
+ private Map<String, Method> getMethodMap(Class<?> clazz) throws
ScriptException {
+ Map<Class<?>, Map<String, Method>> clazzMaps = null;
+ synchronized (properties) {
+ clazzMaps = properties.get(clazz.getClassLoader());
+ if (clazzMaps == null) {
+ clazzMaps = Collections.synchronizedMap(new LRUCache<Class<?>,
Map<String, Method>>(100));
+ properties.put(clazz.getClassLoader(), clazzMaps);
+ }
+ }
+ Map<String, Method> methodMap = clazzMaps.get(clazz);
+ if (methodMap == null) {
+ try {
+ BeanInfo info = Introspector.getBeanInfo(clazz);
+ PropertyDescriptor[] pds = info.getPropertyDescriptors();
+ methodMap = new HashMap<String, Method>();
+ if (pds != null) {
+ for (int j = 0; j < pds.length; j++) {
+ PropertyDescriptor pd = pds[j];
+ if (pd.getReadMethod() == null || pd instanceof IndexedPropertyDescriptor) {
+ continue;
+ }
+ String name = pd.getName();
+ Method m = pd.getReadMethod();
+ methodMap.put(name, m);
+ }
+ }
+ MethodDescriptor[] mds = info.getMethodDescriptors();
+ if (pds != null) {
+ for (int j = 0; j < mds.length; j++) {
+ MethodDescriptor md = mds[j];
+ if (md.getMethod() == null || md.getMethod().getParameterTypes().length > 0 ||
md.getMethod().getReturnType() == Void.class) {
+ continue;
+ }
+ String name = md.getName();
+ Method m = md.getMethod();
+ methodMap.put(name, m);
+ }
+ }
+ clazzMaps.put(clazz, methodMap);
+ } catch (IntrospectionException e) {
+ throw new ScriptException(e);
+ }
+ }
+ return methodMap;
+ }
+
+ @Override
+ public CompiledScript compile(Reader script) throws ScriptException {
+ try {
+ return compile(ObjectConverterUtil.convertToString(script));
+ } catch (IOException e) {
+ throw new ScriptException(e);
+ }
+ }
+
+ @Override
+ public ScriptEngineFactory getFactory() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object eval(Reader reader, ScriptContext sc)
+ throws ScriptException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object eval(String script, ScriptContext sc)
+ throws ScriptException {
+ throw new UnsupportedOperationException();
+ }
+
+}
\ No newline at end of file
Property changes on:
trunk/engine/src/main/java/org/teiid/query/eval/TeiidScriptEngine.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified: trunk/engine/src/main/java/org/teiid/query/metadata/TransformationMetadata.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/metadata/TransformationMetadata.java 2012-08-28
18:31:49 UTC (rev 4377)
+++
trunk/engine/src/main/java/org/teiid/query/metadata/TransformationMetadata.java 2012-08-28
19:41:34 UTC (rev 4378)
@@ -60,6 +60,7 @@
import org.teiid.metadata.Column.SearchType;
import org.teiid.metadata.ProcedureParameter.Type;
import org.teiid.query.QueryPlugin;
+import org.teiid.query.eval.TeiidScriptEngine;
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.function.FunctionTree;
import org.teiid.query.mapping.relational.QueryNode;
@@ -1119,8 +1120,8 @@
if (this.scriptEngineManager == null) {
this.scriptEngineManager = new ScriptEngineManager();
}
- if (language == null) {
- language = ObjectTable.DEFAULT_LANGUAGE;
+ if (language == null || ObjectTable.DEFAULT_LANGUAGE.equals(language)) {
+ return new TeiidScriptEngine();
}
ScriptEngine engine = null;
if (allowedLanguages == null || allowedLanguages.contains(language)) {
@@ -1147,6 +1148,7 @@
if (allowedLanguages != null) {
names.retainAll(allowedLanguages);
}
+ names.add(ObjectTable.DEFAULT_LANGUAGE);
throw new TeiidProcessingException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31109,
language, names));
}
this.scriptEngineFactories.put(language, engine.getFactory());
Modified:
trunk/engine/src/main/java/org/teiid/query/processor/relational/ObjectTableNode.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/processor/relational/ObjectTableNode.java 2012-08-28
18:31:49 UTC (rev 4377)
+++
trunk/engine/src/main/java/org/teiid/query/processor/relational/ObjectTableNode.java 2012-08-28
19:41:34 UTC (rev 4378)
@@ -22,6 +22,7 @@
package org.teiid.query.processor.relational;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -36,15 +37,18 @@
import org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.common.buffer.BlockedException;
+import org.teiid.common.buffer.BufferManager;
import org.teiid.common.buffer.TupleBatch;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.query.QueryPlugin;
import org.teiid.query.eval.Evaluator;
import org.teiid.query.function.FunctionDescriptor;
+import org.teiid.query.processor.ProcessorDataManager;
import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.lang.ObjectTable;
import org.teiid.query.sql.lang.ObjectTable.ObjectColumn;
+import org.teiid.query.util.CommandContext;
/**
* Handles object table processing.
@@ -69,17 +73,33 @@
}
@Override
+ public void initialize(CommandContext context, BufferManager bufferManager,
+ ProcessorDataManager dataMgr) {
+ super.initialize(context, bufferManager, dataMgr);
+ this.scriptContext = new SimpleScriptContext();
+ }
+
+ @Override
public void open() throws TeiidComponentException, TeiidProcessingException {
super.open();
if (table.getScriptEngine() == null) {
table.setScriptEngine(getContext().getMetadata().getScriptEngine(table.getScriptingLanguage()));
}
- scriptContext = new SimpleScriptContext();
this.scriptContext.setAttribute(TEIID_CONTEXT, this.getContext(),
ScriptContext.ENGINE_SCOPE);
}
@Override
public synchronized void closeDirect() {
+ if (this.scriptContext != null) {
+ try {
+ this.scriptContext.getErrorWriter().flush();
+ } catch (IOException e) {
+ }
+ try {
+ this.scriptContext.getWriter().flush();
+ } catch (IOException e) {
+ }
+ }
super.closeDirect();
reset();
}
@@ -90,7 +110,9 @@
item = null;
result = null;
rowCount = 0;
- this.scriptContext = null;
+ if (this.scriptContext != null) {
+ this.scriptContext.getBindings(ScriptContext.ENGINE_SCOPE).clear();
+ }
}
public void setTable(ObjectTable table) {
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/ObjectTable.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/ObjectTable.java 2012-08-28
18:31:49 UTC (rev 4377)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/ObjectTable.java 2012-08-28
19:41:34 UTC (rev 4378)
@@ -35,7 +35,7 @@
public class ObjectTable extends TableFunctionReference {
- public static final String DEFAULT_LANGUAGE = "javascript"; //$NON-NLS-1$
+ public static final String DEFAULT_LANGUAGE = "teiid_script"; //$NON-NLS-1$
public static class ObjectColumn extends ProjectedColumn {
private String path;
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2012-08-28 18:31:49
UTC (rev 4377)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2012-08-28 19:41:34
UTC (rev 4378)
@@ -40,7 +40,7 @@
TEIID30011=The function "{0}" will not be added because a function with the
same name and signature already exists.
TEIID30389=Unexpected exception while loading "{1}.{2}" for UDF
"{0}"
TEIID30387=Could not load UDF "{0}", since its invocation class "{1}"
could not be found.
-TEIID30388=UDF "{0}" could not loaded, since no method on class "{1}"
with name "{2}" has a matching type signature.
+TEIID30388=UDF "{0}" could not be loaded, since no method on class
"{1}" with name "{2}" has a matching type signature.
TEIID30424=Unable to represent average value from {0} / {1}
TEIID30425=Unable to compute aggregate function {0} on data of type {1}
TEIID30429={0} must be non-null.
@@ -1025,7 +1025,8 @@
TEIID31106=Duplicate parameter {1} defined on {0}
TEIID31107=Procedure {0} can only have 1 RESULT/return value
TEIID31109=Invalid language {0}. Supported and allowed language names are {1}.
-TEIID31110=Invalid script {0}. Scrpting engine reported: {1}.
+TEIID31110=Invalid script {0}. Scrpting engine reported: {1}
+TEIID31111=No such accessible property/method {0} on {1}.
SQLParser.proc_type_conflict=Result type {1} conflicts with return type {2} for procedure
{0}
SQLParser.param_out=Procedure {0} RESULT param {1} must be of type OUT.
Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2012-08-28
18:31:49 UTC (rev 4377)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2012-08-28
19:41:34 UTC (rev 4378)
@@ -1603,7 +1603,7 @@
}
@Test public void testObjectTableScript() {
- helpValidate("select * from objecttable('this is not valid' columns c
integer 'row') as x", new String[] {"OBJECTTABLE('this is not
valid' COLUMNS c integer 'row') AS x"},
RealMetadataFactory.example1Cached());
+ helpValidate("select * from objecttable('this. is not valid' columns c
integer 'row') as x", new String[] {"OBJECTTABLE('this is not
valid' COLUMNS c integer 'row') AS x"},
RealMetadataFactory.example1Cached());
}
@Test public void testXMLQueryPassingContextType() {