Package org.apache.ode.bpel.engine

Source Code of org.apache.ode.bpel.engine.PartnerLinkMyRoleImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.ode.bpel.engine;

import java.util.*;

import javax.wsdl.Operation;
import javax.wsdl.PortType;
import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.bpel.common.CorrelationKey;
import org.apache.ode.bpel.common.FaultException;
import org.apache.ode.bpel.common.InvalidMessageException;
import org.apache.ode.bpel.dao.CorrelatorDAO;
import org.apache.ode.bpel.dao.MessageExchangeDAO;
import org.apache.ode.bpel.dao.MessageRouteDAO;
import org.apache.ode.bpel.dao.ProcessDAO;
import org.apache.ode.bpel.dao.ProcessInstanceDAO;
import org.apache.ode.bpel.evt.CorrelationMatchEvent;
import org.apache.ode.bpel.evt.CorrelationNoMatchEvent;
import org.apache.ode.bpel.evt.NewProcessInstanceEvent;
import org.apache.ode.bpel.iapi.Endpoint;
import org.apache.ode.bpel.iapi.MessageExchange;
import org.apache.ode.bpel.iapi.MyRoleMessageExchange;
import org.apache.ode.bpel.iapi.ProcessState;
import org.apache.ode.bpel.iapi.MessageExchange.FailureType;
import org.apache.ode.bpel.iapi.MyRoleMessageExchange.CorrelationStatus;
import org.apache.ode.bpel.runtime.InvalidProcessException;
import org.apache.ode.bpel.rapi.PartnerLinkModel;
import org.apache.ode.bpel.rapi.CorrelationSetModel;
import org.apache.ode.bpel.rapi.PropertyAliasModel;
import org.apache.ode.bpel.rapi.PropertyExtractor;
import org.apache.ode.utils.CollectionUtils;
import org.apache.ode.utils.ObjectPrinter;
import org.apache.ode.utils.msg.MessageBundle;
import org.w3c.dom.Element;

/**
* @author Matthieu Riou <mriou at apache dot org>
*/
class PartnerLinkMyRoleImpl extends PartnerLinkRoleImpl {
    private static final Log __log = LogFactory.getLog(ODEProcess.class);

    private static final Messages __msgs = MessageBundle.getMessages(Messages.class);

    /** The local endpoint for this "myrole". */
    public Endpoint _endpoint;

    PartnerLinkMyRoleImpl(ODEProcess process, PartnerLinkModel plink, Endpoint endpoint) {
        super(process, plink);
        _endpoint = endpoint;
    }

    public String toString() {
        StringBuffer buf = new StringBuffer("{PartnerLinkRole-");
        buf.append(_plinkDef.getName());
        buf.append('.');
        buf.append(_plinkDef.getMyRoleName());
        buf.append(" on ");
        buf.append(_endpoint);
        buf.append('}');

        return buf.toString();
    }

    /**
     * Called when an input message has been received.
     *
     * @param mex exchange to which the message is related
     */
    public CorrelationStatus invokeMyRole(MessageExchangeDAO mex) {
        if (__log.isTraceEnabled()) {
            __log.trace(ObjectPrinter.stringifyMethodEnter(this + ":inputMsgRcvd", new Object[] { "messageExchange", mex }));
        }

        Operation operation = getMyRoleOperation(mex.getOperation());
        if (operation == null) {
            __log.error(__msgs.msgUnknownOperation(mex.getOperation(), _plinkDef.getMyRolePortType().getQName()));
            MexDaoUtil.setFailed(mex, FailureType.UNKNOWN_OPERATION, mex.getOperation());
            return null;
        }

        // Is this a /possible/ createInstance Operation?
        boolean isCreateInstance = _plinkDef.isCreateInstanceOperation(operation);
        String correlatorId = ODEProcess.genCorrelatorId(_plinkDef, operation.getName());
        CorrelatorDAO correlator = _process.getProcessDAO().getCorrelator(correlatorId);

        MessageRouteDAO messageRoute = null;

        // now, the tricks begin: when a message arrives we have to see if there is anyone waiting for it. Get the correlator, a
        // persisted communnication-reduction data structure supporting correlation correlationKey matching!

        CorrelationKey[] processKeys, uniqueKeys;

        // We need to compute the correlation keys (based on the operation
        // we can infer which correlation keys to compute - this is merely a set
        // consisting of each correlationKey used in each correlation sets
        // that is ever referenced in an <receive>/<onMessage> on this
        // partnerlink/operation.
        try {
            processKeys = computeCorrelationKeys(mex, operation);
            uniqueKeys = computeUniqueCorrelationKeys(mex, operation);
        } catch (InvalidMessageException ime) {
            // We'd like to do a graceful exit here, no sense in rolling back due to a
            // a message format problem.
            __log.debug("Unable to evaluate correlation keys, invalid message format. ", ime);
            MexDaoUtil.setFailed(mex, FailureType.FORMAT_ERROR,  ime.getMessage());
            return null;
        }

        String mySessionId = mex.getProperty(MessageExchange.PROPERTY_SEP_MYROLE_SESSIONID);
        String partnerSessionId = mex.getProperty(MessageExchange.PROPERTY_SEP_PARTNERROLE_SESSIONID);
        if (__log.isDebugEnabled()) {
            __log.debug("INPUTMSG: " + correlatorId + ": MSG RCVD keys=" + CollectionUtils.makeCollection(HashSet.class, processKeys)
                    + " mySessionId=" + mySessionId + " partnerSessionId=" + partnerSessionId);
        }

        CorrelationKey matchedKey = null;

        // Try to find a route for one of our keys.
        for (CorrelationKey key : processKeys) {
            messageRoute = correlator.findRoute(key);
            if (messageRoute != null) {
                if (__log.isDebugEnabled()) {
                    __log.debug("INPUTMSG: " + correlatorId + ": ckey " + key + " ROUTED TO (grp,index,iid) = (" + messageRoute.getGroupId() + "," + messageRoute.getIndex() + ", " + messageRoute.getTargetInstance().getInstanceId() ")");
                }
                matchedKey = key;
                break;
            }
        }

        // TODO - ODE-58

        // If no luck, and this operation qualifies for create-instance
        // treatment, then create a new process
        // instance.
        if (messageRoute == null && isCreateInstance) {
            invokeMyRoleCreateInstance(mex, operation, correlatorId, correlator, uniqueKeys);
        } else if (messageRoute != null) {
            if (__log.isDebugEnabled()) {
                __log.debug("INPUTMSG: " + correlatorId + ": ROUTING to instance "
                        + messageRoute.getTargetInstance().getInstanceId());
            }

            ProcessInstanceDAO instanceDAO = messageRoute.getTargetInstance();
            ProcessDAO processDAO = instanceDAO.getProcess();
            enforceUniqueConstraint(processDAO, uniqueKeys);

            // Reload process instance for DAO.

            // Kill the route so some new message does not get routed to
            // same process instance.
            correlator.removeRoutes(messageRoute.getGroupId(), instanceDAO);

            // send process instance event
            CorrelationMatchEvent evt = new CorrelationMatchEvent(_process.getProcessModel().getQName(),
                    _process.getProcessDAO().getProcessId(), instanceDAO.getInstanceId(), matchedKey);
            evt.setPortType(mex.getPortType());
            evt.setOperation(operation.getName());
            evt.setMexId(mex.getMessageExchangeId());

            _process._debugger.onEvent(evt);
            // store event
            _process.saveEvent(evt, instanceDAO);

            mex.setCorrelationStatus(MyRoleMessageExchange.CorrelationStatus.MATCHED.toString());
            mex.setInstance(messageRoute.getTargetInstance());

            // We're overloading the channel here to be the PICK response channel + index
            mex.setChannel(messageRoute.getGroupId() + "&" + messageRoute.getIndex());
        } else {
            if (__log.isDebugEnabled()) {
                __log.debug("INPUTMSG: " + correlatorId + ": SAVING to DB (no match) ");
            }

            // TODO: Revist (BART)
            // if (!mex.isAsynchronous()) {
            // mex.setFailure(MessageExchange.FailureType.NOMATCH, "No process instance matching correlation keys.", null);
            //
            // } else {
            // send event
            CorrelationNoMatchEvent evt = new CorrelationNoMatchEvent(mex.getPortType(), mex.getOperation(), mex
                    .getMessageExchangeId(), processKeys);

            evt.setProcessId(_process.getProcessDAO().getProcessId());
            evt.setProcessName(_process.getProcessModel().getQName());
            _process._debugger.onEvent(evt);

            mex.setCorrelationStatus(MyRoleMessageExchange.CorrelationStatus.QUEUED.toString());
            correlator.enqueueMessage(mex, processKeys);
        }

        return CorrelationStatus.valueOf(mex.getCorrelationStatus());
    }

    private void invokeMyRoleCreateInstance(MessageExchangeDAO mex, Operation operation, String correlatorId,
            CorrelatorDAO correlator, CorrelationKey[] uniqueKeys) {
        if (__log.isDebugEnabled()) {
            __log.debug("INPUTMSG: " + correlatorId + ": routing failed, CREATING NEW INSTANCE");
        }
        ProcessDAO processDAO = _process.getProcessDAO();

        if (_process._pconf.getState() == ProcessState.RETIRED) {
            throw new InvalidProcessException("Process is retired.", InvalidProcessException.RETIRED_CAUSE_CODE);
        }

        // if (!_process.processInterceptors(mex, InterceptorInvoker.__onNewInstanceInvoked)) {
        // __log.debug("Not creating a new instance for mex " + mex + "; interceptor prevented!");
        // return;
        // }

        enforceUniqueConstraint(processDAO, uniqueKeys);
       
        ProcessInstanceDAO newInstance = processDAO.createInstance(correlator);
       
        // send process instance event
        NewProcessInstanceEvent evt = new NewProcessInstanceEvent(_process.getProcessModel().getQName(),
                processDAO.getProcessId(), newInstance.getInstanceId());
        evt.setPortType(mex.getPortType());
        evt.setOperation(operation.getName());
        evt.setMexId(mex.getMessageExchangeId());
        _process._debugger.onEvent(evt);
        _process.saveEvent(evt, newInstance);
        mex.setCorrelationStatus(MyRoleMessageExchange.CorrelationStatus.CREATE_INSTANCE.toString());
        mex.setInstance(newInstance);

    }

    private void enforceUniqueConstraint(ProcessDAO processDAO, CorrelationKey[] uniqueKeys) {
        for (CorrelationKey uniqueKey : uniqueKeys) {
            // double-check that the correlation set is indeed unique
            if (uniqueKey.isUnique()) {
                Collection<ProcessInstanceDAO> instances = processDAO.findInstance(uniqueKey, false);
                if (instances.size() != 0) {
                    __log.debug("Not creating a new instance for process " + processDAO.getProcessId() + "; unique correlation constraint would be violated!");
                    throw new InvalidProcessException("Unique process constraint violated", InvalidProcessException.DUPLICATE_CAUSE_CODE);
                }
            }         
        }
    }

    @SuppressWarnings("unchecked")
    private Operation getMyRoleOperation(String operationName) {
        return _plinkDef.getMyRoleOperation(operationName);
    }

    private CorrelationKey[] computeCorrelationKeys(MessageExchangeDAO mex, Operation operation) {
        Element msg = mex.getRequest().getData();
        javax.wsdl.Message msgDescription = operation.getInput().getMessage();
        List<CorrelationKey> keys = new ArrayList<CorrelationKey>();

        Set<CorrelationSetModel> csets = _plinkDef.getCorrelationSetsForOperation(operation);
        for (CorrelationSetModel cset : csets) {
            CorrelationKey key = computeCorrelationKey(cset, msgDescription.getQName(), msg);
            keys.add(key);
        }

        // Let's creata a key based on the sessionId
        String mySessionId = mex.getProperty(MessageExchange.PROPERTY_SEP_MYROLE_SESSIONID);
        if (mySessionId != null)
            keys.add(new CorrelationKey(-1, new String[] { mySessionId }));

        return keys.toArray(new CorrelationKey[keys.size()]);
    }

    private CorrelationKey[] computeUniqueCorrelationKeys(MessageExchangeDAO mex, Operation operation) {
        Element msg = mex.getRequest().getData();
        javax.wsdl.Message msgDescription = operation.getInput().getMessage();
        List<CorrelationKey> keys = new ArrayList<CorrelationKey>();

        Set<CorrelationSetModel> csets = _plinkDef.getUniqueCorrelationSetsForOperation(operation);
        for (CorrelationSetModel cset : csets) {
            CorrelationKey key = computeCorrelationKey(cset, msgDescription.getQName(), msg);
            keys.add(key);
        }

        // Let's creata a key based on the sessionId
        String mySessionId = mex.getProperty(MessageExchange.PROPERTY_SEP_MYROLE_SESSIONID);
        if (mySessionId != null)
            keys.add(new CorrelationKey(-1, new String[] { mySessionId }));

        return keys.toArray(new CorrelationKey[keys.size()]);
    }
   
    private CorrelationKey computeCorrelationKey(CorrelationSetModel cset, QName messageName, Element msg) {
        String[] values;
        if (cset.getExtractors().isEmpty()) {
            List<PropertyAliasModel> aliases = cset.getAliases(messageName);
            values = new String[aliases.size()];
            int jIdx = 0;
            for (PropertyAliasModel alias : aliases) {
                String value;
                try {
                    value = _process._runtime.extractProperty(msg, alias, msg.toString());
                } catch (FaultException fe) {
                    String emsg = __msgs.msgPropertyAliasDerefFailedOnMessage(alias.getDescription(), fe.getMessage());
                    __log.error(emsg, fe);
                    throw new InvalidMessageException(emsg, fe);
                }
                values[jIdx++] = value;
            }
        } else {
            List<PropertyExtractor> extractors = cset.getExtractors();
            values = new String[extractors.size()];
            int jIdx = 0;
            for (PropertyExtractor extractor : extractors) {
                try {
                    values[jIdx++] = _process._runtime.extractMatch(msg, extractor);
                } catch (FaultException e) {
                    String emsg = __msgs.msgPropertyAliasDerefFailedOnMessage(extractor.toString(), e.getMessage());
                    __log.error(emsg, e);
                    throw new InvalidMessageException(emsg, e);
                }
            }
        }

        CorrelationKey key = new CorrelationKey(cset.getId(), values);
        key.setUnique(cset.isUnique());
        return key;
    }

    public boolean isOneWayOnly() {
        PortType portType = _plinkDef.getMyRolePortType();
        if (portType == null) {
            return false;
        }
        for (Operation operation : (List<Operation>) portType.getOperations()) {
            if (operation.getOutput() != null) {
                return false;
            }
        }
        return true;
    }

}
TOP

Related Classes of org.apache.ode.bpel.engine.PartnerLinkMyRoleImpl

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.