xbird.xquery.func.ext.RemoteEval.java Source code

Java tutorial

Introduction

Here is the source code for xbird.xquery.func.ext.RemoteEval.java

Source

/*
 * @(#)$Id: RemoteEval.java 3619 2008-03-26 07:23:03Z yui $
 *
 * Copyright 2006-2008 Makoto YUI
 *
 * 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.
 * 
 * Contributors:
 *     Makoto YUI - initial implementation
 */
package xbird.xquery.func.ext;

import java.net.URI;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import xbird.config.Settings;
import xbird.engine.Request;
import xbird.engine.XQEngineClient;
import xbird.engine.Request.ReturnType;
import xbird.engine.remote.RemoteSequence;
import xbird.engine.remote.RemoteSequenceProxy;
import xbird.engine.request.QueryRequest;
import xbird.util.net.TimeoutSocketProdiver;
import xbird.xquery.XQueryException;
import xbird.xquery.dm.value.Item;
import xbird.xquery.dm.value.Sequence;
import xbird.xquery.dm.value.sequence.MarshalledSequence;
import xbird.xquery.dm.value.sequence.ValueSequence;
import xbird.xquery.expr.Evaluable;
import xbird.xquery.expr.XQExpression;
import xbird.xquery.expr.opt.ShippedVariable;
import xbird.xquery.expr.seq.SequenceExpression;
import xbird.xquery.expr.var.VarRef;
import xbird.xquery.expr.var.Variable;
import xbird.xquery.func.BuiltInFunction;
import xbird.xquery.func.Function;
import xbird.xquery.func.FunctionSignature;
import xbird.xquery.meta.DynamicContext;
import xbird.xquery.meta.StaticContext;
import xbird.xquery.misc.QNameTable.QualifiedName;
import xbird.xquery.type.SequenceType;
import xbird.xquery.type.Type;
import xbird.xquery.type.xs.StringType;

/**
 * ext:remote-eval($remoteEndpoint as xs:string, $queryStr as xs:string, $varsToShip?) as item()*.
 * <DIV lang="en"></DIV>
 * <DIV lang="ja"></DIV>
 * 
 * @author Makoto YUI (yuin405+xbird@gmail.com)
 */
public final class RemoteEval extends BuiltInFunction implements Evaluable {
    private static final long serialVersionUID = 1839282676743361557L;
    private static final Log LOG = LogFactory.getLog(RemoteEval.class);

    public static final boolean ENV_NOWRAP_VARSHIP = System.getProperty("xbird.remote.nowrap_var") != null;
    public static final String SYMBOL = EXT_NSPREFIX + ':' + "remote-eval";
    public static final ReturnType RETURN_TYPE;
    static {
        String type = Settings.get("xbird.remote.returntype", "AUTO");
        RETURN_TYPE = Request.resolveReturnType(type);
    }

    private XQExpression thirdParam = null;

    public RemoteEval() {
        super(SYMBOL, SequenceType.ANY_ITEMS);
        this._evalPocily = EvaluationPolicy.threaded;
    }

    @Override
    protected FunctionSignature[] signatures() {
        final FunctionSignature[] s = new FunctionSignature[2];
        s[0] = new FunctionSignature(getName(), new Type[] { StringType.STRING, StringType.STRING });
        s[1] = new FunctionSignature(getName(),
                new Type[] { StringType.STRING, StringType.STRING, SequenceType.ANY_ITEMS });
        return s;
    }

    @Override
    public boolean isReusable() {
        return false;
    }

    @Override
    public Function staticAnalysis(StaticContext context, List<? extends XQExpression> params)
            throws XQueryException {
        final int psize = params.size();
        if (psize == 3) {
            this.thirdParam = params.get(2);
        }
        return this;
    }

    public Sequence eval(Sequence<? extends Item> contextSeq, ValueSequence argv, DynamicContext dynEnv)
            throws XQueryException {
        String endpoint = argv.getItem(0).stringValue();
        String query = argv.getItem(1).stringValue();

        if (LOG.isInfoEnabled()) {
            LOG.info("Invoking remote query at [" + endpoint + "]:\n " + query);
        }

        XQEngineClient client = new XQEngineClient(endpoint);
        QueryRequest request = new QueryRequest(query, RETURN_TYPE);
        StaticContext statEnv = dynEnv.getStaticContext();
        URI baseUri = statEnv.getBaseURI();
        if (baseUri == null) {
            baseUri = statEnv.getSystemBaseURI();
        }
        request.setBaseUri(baseUri);
        prepareVariablesToShip(request, argv, dynEnv);
        final Object result;
        try {
            result = client.execute(request);
        } catch (RemoteException e) {
            throw new XQueryException(e.getMessage(), e.getCause());
        } finally {
            try {
                client.close();
            } catch (RemoteException e) {
                LOG.warn("shutdown failed for `" + endpoint + '\'', e);
            }
        }
        Sequence resultSeq = (Sequence) result;
        return resultSeq;
    }

    private void prepareVariablesToShip(QueryRequest request, ValueSequence contextSeq, DynamicContext dynEnv)
            throws XQueryException {
        if (thirdParam != null) {
            final List<ShippedVariable> vars = new ArrayList<ShippedVariable>(4);
            if (thirdParam instanceof VarRef) {
                final ShippedVariable shiped = wrapVariableToShip(request, (VarRef) thirdParam, contextSeq, dynEnv);
                vars.add(shiped);
            } else if (thirdParam instanceof SequenceExpression) {
                final SequenceExpression seq = (SequenceExpression) thirdParam;
                final List<XQExpression> exprs = seq.getExpressions();
                for (XQExpression e : exprs) {
                    if (e instanceof VarRef) {
                        final ShippedVariable shiped = wrapVariableToShip(request, (VarRef) e, contextSeq, dynEnv);
                        vars.add(shiped);
                    }
                }
            }
            final int varsSize = vars.size();
            if (varsSize > 0) {
                final ShippedVariable[] varAry = vars.toArray(new ShippedVariable[varsSize]);
                request.setVariablesToShip(varAry);
            }
        }
    }

    private static ShippedVariable wrapVariableToShip(QueryRequest request, VarRef ref, ValueSequence contextSeq,
            DynamicContext dynEnv) throws XQueryException {
        QualifiedName varname = ref.getName();
        Variable var = ref.getValue();
        Sequence result = var.getResult();
        if (result == null) {
            result = var.eval(contextSeq, dynEnv);
        }
        ReturnType rettype = request.getReturnType();
        final ShippedVariable shiped;
        if (ENV_NOWRAP_VARSHIP || !rettype.isRemoteSequnece()) {
            shiped = new ShippedVariable(varname, new MarshalledSequence(result, dynEnv));
        } else {
            final RemoteSequenceProxy proxy = new RemoteSequenceProxy(result, request);
            try {
                UnicastRemoteObject.exportObject(proxy, 0, TimeoutSocketProdiver.createClientSocketFactory(),
                        TimeoutSocketProdiver.createServerSocketFactory());
            } catch (RemoteException e) {
                throw new XQueryException("failed exporting variable: " + varname, e);
            }
            RemoteSequence remote = new RemoteSequence(proxy, result.getType());
            shiped = new ShippedVariable(varname, remote);
        }
        return shiped;
    }

}