blob: 5644ab679fb6dc7998df29c12b9602f1ba06380d [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* 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.apache.xmlbeans.impl.store;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.common.DefaultClassLoaderResourceLoader;
import org.apache.xmlbeans.impl.common.XPath;
import org.w3c.dom.*;
import javax.xml.namespace.QName;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Date;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
public abstract class Query
{
public static final String QUERY_DELEGATE_INTERFACE = "QUERY_DELEGATE_INTERFACE";
public static String _useDelegateForXQuery = "use delegate for xquery";
public static String _useXdkForXQuery = "use xdk for xquery";
private static String _delIntfName;
//private static HashMap _delegateQueryCache = new HashMap();
private static HashMap _xdkQueryCache = new HashMap();
private static Method _xdkCompileQuery;
private static boolean _xdkAvailable = true; // at the beginning assume is available
private static HashMap _xqrlQueryCache = new HashMap(); //todo check for memory leaks
private static Method _xqrlCompileQuery;
private static boolean _xqrlAvailable = true; // at the beginning assume is available
private static HashMap _xqrl2002QueryCache = new HashMap();
private static Method _xqrl2002CompileQuery;
private static boolean _xqrl2002Available = true; // at the beginning assume is available
static
{
String id = "META-INF/services/org.apache.xmlbeans.impl.store.QueryDelegate.QueryInterface";
InputStream in = new DefaultClassLoaderResourceLoader().getResourceAsStream(id);
try
{
BufferedReader br = new BufferedReader(new InputStreamReader(in));
_delIntfName = br.readLine().trim();
br.close();
}
catch (Exception e)
{
_delIntfName = null;
}
}
abstract XmlObject[] objectExecute(Cur c, XmlOptions options);
abstract XmlCursor cursorExecute(Cur c, XmlOptions options);
//
// Xqrl store specific implementation of compiled path/query
//
static XmlObject[] objectExecQuery(Cur c, String queryExpr, XmlOptions options)
{
return getCompiledQuery(queryExpr, options).objectExecute(c, options);
}
static XmlCursor cursorExecQuery(Cur c, String queryExpr, XmlOptions options)
{
return getCompiledQuery(queryExpr, options).cursorExecute(c, options);
}
public static synchronized Query getCompiledQuery(String queryExpr, XmlOptions options)
{
return getCompiledQuery(queryExpr, Path.getCurrentNodeVar(options), options);
}
static synchronized Query getCompiledQuery(String queryExpr, String currentVar, XmlOptions options)
{
assert queryExpr != null;
options = XmlOptions.maskNull(options);
Query query;
if (options.hasOption(Path._forceXqrl2002ForXpathXQuery))
{
query = (Query)_xqrl2002QueryCache.get(queryExpr);
if (query!=null)
return query;
query = getXqrl2002CompiledQuery(queryExpr, currentVar);
if (query!=null)
{
_xqrl2002QueryCache.put(queryExpr, query);
return query;
}
throw new RuntimeException("No 2002 query engine found.");
}
//Parse the query via XBeans: need to figure out end of prolog
//in order to bind $this...not good but...
Map boundary = new HashMap();
int boundaryVal = 0;
try
{
XPath.compileXPath(queryExpr, currentVar, boundary);
}
catch (XPath.XPathCompileException e)
{
//don't care if it fails, just care about boundary
}
finally
{
boundaryVal = boundary.get(XPath._NS_BOUNDARY) == null ? 0 :
((Integer) boundary.get(XPath._NS_BOUNDARY)).intValue();
}
if (options.hasOption(_useXdkForXQuery))
{
//try XDK
query = (Query) _xdkQueryCache.get(queryExpr);
if (query != null)
return query;
query = createXdkCompiledQuery(queryExpr, currentVar);
if (query != null)
{
_xdkQueryCache.put(queryExpr, query);
return query;
}
}
if (!options.hasOption(_useDelegateForXQuery))
{
//try XQRL
query = (Query) _xqrlQueryCache.get(queryExpr);
if (query != null)
return query;
query = createXqrlCompiledQuery(queryExpr, currentVar);
if (query != null)
{
_xqrlQueryCache.put(queryExpr, query);
return query;
}
}
//otherwise (if _useDelegateForXQuery option is set),
//or if xqrl is not found, try delegate
//query = (Query) _delegateQueryCache.get(queryExpr);
//if (query != null)
// return query;
String delIntfName =
options.hasOption(QUERY_DELEGATE_INTERFACE) ?
(String)options.get(QUERY_DELEGATE_INTERFACE) : _delIntfName;
query = DelegateQueryImpl.createDelegateCompiledQuery(delIntfName, queryExpr, currentVar, boundaryVal, options);
if (query != null)
{
//_delegateQueryCache.put(queryExpr, query);
return query;
}
throw new RuntimeException("No query engine found");
}
public static synchronized String compileQuery(String queryExpr, XmlOptions options)
{
getCompiledQuery(queryExpr, options);
return queryExpr;
}
private static Query createXdkCompiledQuery(String queryExpr, String currentVar)
{
//if the XDK engine has been determined unavailable, return null
if ( !_xdkAvailable ) return null;
if ( _xdkCompileQuery == null)
{
try
{
Class xdkImpl = Class.forName("org.apache.xmlbeans.impl.store.OXQXBXqrlImpl");
_xdkCompileQuery =
xdkImpl.getDeclaredMethod("compileQuery",
new Class[]{String.class, String.class, Boolean.class});
}
catch (ClassNotFoundException e)
{
_xdkAvailable = false;
return null;
}
catch (Exception e)
{
_xdkAvailable = false;
throw new RuntimeException(e.getMessage(), e);
}
}
Object[] args = new Object[]{queryExpr, currentVar, new Boolean(true)};
try
{
return (Query) _xdkCompileQuery.invoke(null, args);
}
catch (InvocationTargetException e)
{
Throwable t = e.getCause();
throw new RuntimeException(t.getMessage(), t);
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
private static Query createXqrlCompiledQuery(String queryExpr, String currentVar)
{
//if the XQRL engine has been determined unavailable, return null
if ( !_xqrlAvailable ) return null;
if ( _xqrlCompileQuery == null)
{
try
{
Class xqrlImpl = Class.forName("org.apache.xmlbeans.impl.store.XqrlImpl");
_xqrlCompileQuery =
xqrlImpl.getDeclaredMethod("compileQuery",
new Class[]{String.class, String.class, Boolean.class});
}
catch (ClassNotFoundException e)
{
_xqrlAvailable = false;
return null;
}
catch (Exception e)
{
_xqrlAvailable = false;
throw new RuntimeException(e.getMessage(), e);
}
}
Object[] args = new Object[]{queryExpr, currentVar, new Boolean(true)};
try
{
return (Query) _xqrlCompileQuery.invoke(null, args);
}
catch (InvocationTargetException e)
{
Throwable t = e.getCause();
throw new RuntimeException(t.getMessage(), t);
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
private static Query getXqrl2002CompiledQuery(String queryExpr, String currentVar)
{
if (_xqrl2002Available && _xqrl2002CompileQuery == null)
{
try
{
Class xqrlImpl = Class.forName("org.apache.xmlbeans.impl.store.Xqrl2002Impl");
_xqrl2002CompileQuery =
xqrlImpl.getDeclaredMethod("compileQuery",
new Class[]{String.class, String.class, Boolean.class});
}
catch (ClassNotFoundException e)
{
_xqrl2002Available = false;
return null;
}
catch (Exception e)
{
_xqrl2002Available = false;
throw new RuntimeException(e.getMessage(), e);
}
}
Object[] args = new Object[]{queryExpr, currentVar, new Boolean(true)};
try
{
return (Query) _xqrl2002CompileQuery.invoke(null, args);
}
catch (InvocationTargetException e)
{
Throwable t = e.getCause();
throw new RuntimeException(t.getMessage(), t);
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
private static final class DelegateQueryImpl extends Query
{
private DelegateQueryImpl(QueryDelegate.QueryInterface xqueryImpl)
{
_xqueryImpl = xqueryImpl;
}
static Query createDelegateCompiledQuery(String delIntfName,
String queryExpr,
String currentVar,
int boundary,
XmlOptions xmlOptions)
{
assert !(currentVar.startsWith(".") || currentVar.startsWith(".."));
QueryDelegate.QueryInterface impl =
QueryDelegate.createInstance(delIntfName, queryExpr,
currentVar, boundary, xmlOptions);
if (impl == null)
return null;
return new DelegateQueryImpl(impl);
}
XmlObject[] objectExecute(Cur c, XmlOptions options)
{
return new DelegateQueryEngine(_xqueryImpl, c, options).objectExecute();
}
XmlCursor cursorExecute(Cur c, XmlOptions options)
{
return new DelegateQueryEngine(_xqueryImpl, c, options).cursorExecute();
}
private static class DelegateQueryEngine
{
public DelegateQueryEngine(QueryDelegate.QueryInterface xqImpl,
Cur c, XmlOptions opt)
{
_engine = xqImpl;
_version = c._locale.version();
_cur = c.weakCur(this);
_options = opt;
}
public XmlObject[] objectExecute()
{
if (_cur != null && _version != _cur._locale.version())
//throw new ConcurrentModificationException
// ("Document changed during select")
;
Map bindings = (Map) XmlOptions.maskNull(_options).
get(XmlOptions.XQUERY_VARIABLE_MAP);
List resultsList;
resultsList = _engine.execQuery(_cur.getDom(), bindings);
assert resultsList.size() > -1;
XmlObject[] result = new XmlObject[resultsList.size()];
int i;
for (i = 0; i < resultsList.size(); i++) {
//copy objects into the locale
Locale l = Locale.getLocale(_cur._locale._schemaTypeLoader,
_options);
l.enter();
Object node = resultsList.get(i);
Cur res = null;
try {
//typed function results of XQuery
if (!(node instanceof Node)) {
//TODO: exact same code as Path.java
//make a common super-class and pull this--what to name that
//superclass???
res = l.load("<xml-fragment/>").tempCur();
res.setValue(node.toString());
SchemaType type=getType(node);
Locale.autoTypeDocument(res, type, null);
result[i] = res.getObject();
}
else
res = loadNode(l, (Node) node);
result[i] = res.getObject();
}
catch (XmlException e) {
throw new RuntimeException(e);
}
finally {
l.exit();
}
res.release();
}
release();
_engine = null;
return result;
}
private SchemaType getType(Object node)
{
SchemaType type;
if (node instanceof Integer)
type = XmlInteger.type;
else if (node instanceof Double)
type = XmlDouble.type;
else if (node instanceof Long)
type = XmlLong.type;
else if (node instanceof Float)
type = XmlFloat.type;
else if (node instanceof BigDecimal)
type = XmlDecimal.type;
else if (node instanceof Boolean)
type = XmlBoolean.type;
else if (node instanceof String)
type = XmlString.type;
else if (node instanceof Date)
type = XmlDate.type;
else
type = XmlAnySimpleType.type;
return type;
}
public XmlCursor cursorExecute()
{
if (_cur != null && _version != _cur._locale.version())
//throw new ConcurrentModificationException
// ("Document changed during select")
;
Map bindings = (Map) XmlOptions.maskNull(_options).
get(XmlOptions.XQUERY_VARIABLE_MAP);
List resultsList;
resultsList = _engine.execQuery(_cur.getDom(), bindings);
assert resultsList.size() > -1;
int i;
_engine = null;
Locale locale = Locale.getLocale(_cur._locale._schemaTypeLoader, _options);
locale.enter();
Locale.LoadContext _context = new Cur.CurLoadContext(locale, _options);
Cursor resultCur = null;
try {
for (i = 0; i < resultsList.size(); i++) {
loadNodeHelper(locale, (Node) resultsList.get(i), _context);
}
Cur c = _context.finish();
Locale.associateSourceName(c, _options);
Locale.autoTypeDocument(c, null, _options);
resultCur = new Cursor(c);
}
catch (Exception e) {
}
finally {
locale.exit();
}
release();
return resultCur;
}
public void release()
{
if (_cur != null) {
_cur.release();
_cur = null;
}
}
private Cur loadNode(Locale locale, Node node)
{
Locale.LoadContext context = new Cur.CurLoadContext(locale, _options);
try {
loadNodeHelper(locale, node, context);
Cur c = context.finish();
Locale.associateSourceName(c, _options);
Locale.autoTypeDocument(c, null, _options);
return c;
}
catch (Exception e) {
throw new XmlRuntimeException(e.getMessage(), e);
}
}
private void loadNodeHelper(Locale locale, Node node, Locale.LoadContext context)
{
if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
QName attName = new QName(node.getNamespaceURI(),
node.getLocalName(),
node.getPrefix());
context.attr(attName, node.getNodeValue());
}
else
locale.loadNode(node, context);
}
private Cur _cur;
private QueryDelegate.QueryInterface _engine;
private long _version;
private XmlOptions _options;
}
private QueryDelegate.QueryInterface _xqueryImpl;
}
}