Package xbird.engine.backend

Source Code of xbird.engine.backend.QueryProcessor$RedirectableChecker

/*
* @(#)$Id: QueryProcessor.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.engine.backend;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore;

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

import xbird.engine.Request;
import xbird.engine.RequestContext;
import xbird.engine.ResponseListener;
import xbird.engine.Request.ReturnType;
import xbird.engine.Request.Signature;
import xbird.engine.remote.RemoteSequence;
import xbird.engine.remote.RemoteSequenceProxy;
import xbird.engine.remote.RunnableRemoteSequenceProxy;
import xbird.engine.remote.ThrottedRemoteSequenceProxy;
import xbird.engine.request.QueryRequest;
import xbird.util.concurrent.ExecutorFactory;
import xbird.util.concurrent.collections.ConcurrentIdentityHashMap;
import xbird.util.net.TimeoutSocketProdiver;
import xbird.xquery.XQueryException;
import xbird.xquery.XQueryModule;
import xbird.xquery.XQueryProcessor;
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.XQExpression;
import xbird.xquery.expr.ext.BDQExpr;
import xbird.xquery.expr.func.DirectFunctionCall;
import xbird.xquery.expr.opt.ShippedVariable;
import xbird.xquery.expr.var.Variable;
import xbird.xquery.func.doc.Doc;
import xbird.xquery.func.doc.DocAvailable;
import xbird.xquery.func.doc.FnCollection;
import xbird.xquery.meta.DynamicContext;
import xbird.xquery.meta.XQueryContext;
import xbird.xquery.misc.QNameTable.QualifiedName;
import xbird.xquery.parser.visitor.AbstractXQueryParserVisitor;

/**
*
* <DIV lang="en"></DIV>
* <DIV lang="ja"></DIV>
*
* @author Makoto YUI (yuin405 AT gmail.com)
*/
public class QueryProcessor extends BackendProcessor {
    private static final Log LOG = LogFactory.getLog(QueryProcessor.class);

    protected final Semaphore _throttle;
    protected final Map<RequestContext, Thread> _runningThreads = new ConcurrentIdentityHashMap<RequestContext, Thread>(12);
    protected final ExecutorService _executors = ExecutorFactory.newCachedThreadPool(60L, "ParallelQP");

    public QueryProcessor(ResponseListener handler) {
        super(handler);
        this._throttle = new Semaphore(ThrottedRemoteSequenceProxy.NUM_THROTTLE);
    }

    public Signature associatedWith() {
        return Signature.QUERY;
    }

    public void fire(RequestContext rc) throws RemoteException {
        rc.setFired(System.currentTimeMillis());

        final Request request = rc.getRequest();
        final Signature rsig = request.getSignature();
        if(rsig != Signature.QUERY) {
            throw new IllegalStateException("Illegal command is passed to QueryProcessor: " + rsig);
        }
        final QueryRequest queryRequest = (QueryRequest) request;
        final String query = queryRequest.getQuery();
        if(query == null) {
            throw new IllegalStateException("query was null for: " + queryRequest);
        }

        // load shipped variables
        final XQueryModule module = new XQueryModule();
        final ShippedVariable[] vars = queryRequest.getShippedVariables();
        if(vars != null) {
            for(ShippedVariable var : vars) {
                try {
                    module.putVariable(var.getVarName(), var);
                } catch (XQueryException e) {
                    throw new RemoteException("failed to declare shipped variable: " + var, e);
                }
            }
        }

        final XQueryProcessor proccessor = new XQueryProcessor(module);
        try {
            proccessor.parse(query, queryRequest.getBaseUri());
        } catch (XQueryException e) {
            LOG.error("parse failed: \n" + query, e);
            rc.setFault(e);
            _resHandler.onResponse(rc);
            return;
        }
        final Sequence<? extends Item> resultSeq;
        _runningThreads.put(rc, Thread.currentThread());
        final DynamicContext dynEnv = new DynamicContext(proccessor.getStaticContext());
        try {
            resultSeq = proccessor.execute(module, dynEnv);
        } catch (Exception e) {
            LOG.error("execute failed: \n" + query, e);
            rc.setFault(e);
            _resHandler.onResponse(rc);
            return;
        } finally {
            _runningThreads.remove(rc);
        }
        final Serializable result = wrapResult(resultSeq, module.getExpression(), queryRequest, dynEnv);
        rc.setResult(result);

        try {
            _resHandler.onResponse(rc);
        } catch (RemoteException re) {
            LOG.error("The respond for the request '" + rc.getRequest().getIdentifier()
                    + "' is failed", re);
        }
    }

    public void cancel(RequestContext rc) {
        final Thread thread = _runningThreads.remove(rc);
        if(thread != null) {
            thread.interrupt();
            try {
                thread.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        _executors.shutdown();
    }

    protected final Serializable wrapResult(final Sequence result, final XQExpression queryExpr, final QueryRequest request, final DynamicContext dynEnv) {
        assert (dynEnv != null);
        final ReturnType returnType = request.getReturnType();
        final Serializable ret;
        switch(returnType) {
            case SEQUENCE:
                final List<Item> materialized = result.materialize();
                ret = new ValueSequence(materialized, dynEnv);
                break;
            case MARSHALLED_SEQUENCE:
                ret = new MarshalledSequence(result, dynEnv);
                break;
            case AUTO:
            case REDIRECTABLE_MARSHALLED_SEQUENCE:
            case REMOTE_PADED_SEQUENCE: {
                final RedirectableChecker check = new RedirectableChecker();
                try {
                    check.visit(queryExpr, null);
                } catch (XQueryException e) {
                    throw new IllegalStateException(e);
                }
                if(check.isRedirectable()) {
                    MarshalledSequence seq = new MarshalledSequence(result, dynEnv);
                    seq.setRedirectable(true);
                    ret = seq;
                } else if(returnType == ReturnType.REMOTE_PADED_SEQUENCE) {
                    MarshalledSequence seq = new MarshalledSequence(result, dynEnv);
                    seq.setRemotePaging(true);
                    ret = seq;
                } else if(returnType == ReturnType.AUTO) {// treat as THROTTLED_ASYNC_REMOTE_SEQUENCE
                    final ThrottedRemoteSequenceProxy remote = new ThrottedRemoteSequenceProxy(_throttle, result, request);
                    try {
                        UnicastRemoteObject.exportObject(remote, 0, TimeoutSocketProdiver.createClientSocketFactory(), TimeoutSocketProdiver.createServerSocketFactory());
                    } catch (RemoteException e) {
                        throw new IllegalStateException("failed exporting result sequence", e);
                    }
                    ret = new RemoteSequence(remote, result.getType());
                    _executors.execute(remote);
                } else {
                    assert (returnType == ReturnType.REDIRECTABLE_MARSHALLED_SEQUENCE) : returnType;
                    ret = new MarshalledSequence(result, dynEnv);
                }
                break;
            }
            case REMOTE_SEQUENCE: {
                final RemoteSequenceProxy remote = new RemoteSequenceProxy(result, request);
                try {
                    UnicastRemoteObject.exportObject(remote, 0, TimeoutSocketProdiver.createClientSocketFactory(), TimeoutSocketProdiver.createServerSocketFactory());
                } catch (RemoteException e) {
                    throw new IllegalStateException("failed exporting result sequence", e);
                }
                ret = new RemoteSequence(remote, result.getType());
                break;
            }
            case ASYNC_REMOTE_SEQUENCE: {
                final RunnableRemoteSequenceProxy remote = new RunnableRemoteSequenceProxy(result, request);
                try {
                    UnicastRemoteObject.exportObject(remote, 0, TimeoutSocketProdiver.createClientSocketFactory(), TimeoutSocketProdiver.createServerSocketFactory());
                } catch (RemoteException e) {
                    throw new IllegalStateException("failed exporting result sequence", e);
                }
                ret = new RemoteSequence(remote, result.getType());
                _executors.execute(remote);
                break;
            }
            case THROTTLED_ASYNC_REMOTE_SEQUENCE: {
                final ThrottedRemoteSequenceProxy remote = new ThrottedRemoteSequenceProxy(_throttle, result, request);
                try {
                    UnicastRemoteObject.exportObject(remote, 0, TimeoutSocketProdiver.createClientSocketFactory(), TimeoutSocketProdiver.createServerSocketFactory());
                } catch (RemoteException e) {
                    throw new IllegalStateException("failed exporting result sequence", e);
                }
                ret = new RemoteSequence(remote, result.getType());
                _executors.execute(remote);
                break;
            }
            case STRING:
                ret = result.toString();
                break;
            default:
                throw new IllegalStateException("Unexpected return type: " + returnType);
        }
        return ret;
    }

    private static final class RedirectableChecker extends AbstractXQueryParserVisitor {

        private boolean _redirectable = false;

        public RedirectableChecker() {
            super();
        }

        public boolean isRedirectable() {
            return _redirectable;
        }

        @Override
        public XQExpression visit(DirectFunctionCall call, XQueryContext ctxt)
                throws XQueryException {
            if(!_redirectable) {
                final QualifiedName funcName = call.getFuncName();
                assert (funcName != null);
                if(Doc.FUNC_NAME.equals(funcName) || DocAvailable.FUNC_NAME.equals(funcName)
                        || FnCollection.FUNC_NAME.equals(funcName)) {
                    this._redirectable = false;
                } else {
                    return super.visit(call, ctxt);
                }
            }
            return call;
        }

        @Override
        public XQExpression visit(BDQExpr expr, XQueryContext ctxt) throws XQueryException {
            if(!_redirectable) {
                this._redirectable = true;
            }
            return expr;
        }

        @Override
        public XQExpression visit(Variable variable, XQueryContext ctxt) throws XQueryException {
            XQExpression expr = variable.getValue();
            if(expr != null) {
                expr.visit(this, ctxt);
            }
            return variable;
        }

    }

}
TOP

Related Classes of xbird.engine.backend.QueryProcessor$RedirectableChecker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.