/* * Copyright (c) WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * 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.wso2.carbon.bpel.analytics.publisher; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ode.bpel.common.FaultException; import org.apache.ode.bpel.elang.xpath20.o.OXPath20ExpressionBPEL20; import org.apache.ode.bpel.explang.ConfigurationException; import org.apache.ode.bpel.explang.EvaluationException; import org.apache.ode.bpel.o.OExpressionLanguage; import org.apache.ode.bpel.runtime.ExprEvaluationContextImpl; import org.apache.ode.bpel.runtime.ExtensionContextImpl; import org.apache.ode.bpel.runtime.ScopeFrame; import org.apache.ode.bpel.runtime.extension.AbstractSyncExtensionOperation; import org.apache.ode.bpel.runtime.extension.ExtensionContext; import org.apache.ode.store.DeploymentUnitDir; import org.apache.ode.utils.DOMUtils; import org.apache.ode.utils.Namespaces; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.wso2.carbon.bpel.analytics.publisher.internal.AnalyticsPublisherServiceComponent; import org.wso2.carbon.bpel.core.ode.integration.config.analytics.AnalyticsKey; import org.wso2.carbon.bpel.core.ode.integration.config.analytics.AnalyticsServerProfile; import org.wso2.carbon.bpel.core.ode.integration.config.analytics.AnalyticsStreamConfiguration; import org.wso2.carbon.bpel.core.ode.integration.store.TenantProcessStore; import org.wso2.carbon.databridge.agent.DataPublisher; import org.wso2.carbon.databridge.agent.exception.DataEndpointAgentConfigurationException; import org.wso2.carbon.databridge.agent.exception.DataEndpointAuthenticationException; import org.wso2.carbon.databridge.agent.exception.DataEndpointConfigurationException; import org.wso2.carbon.databridge.agent.exception.DataEndpointException; import org.wso2.carbon.databridge.commons.Event; import org.wso2.carbon.databridge.commons.exception.*; import org.wso2.carbon.databridge.commons.utils.DataBridgeCommonsUtils; import javax.xml.namespace.QName; import java.io.File; import java.util.HashMap; import java.util.Iterator; import java.util.List; public class AnalyticsPublisherExtensionOperation extends AbstractSyncExtensionOperation { private static final Log log = LogFactory.getLog(AnalyticsPublisherExtensionOperation.class); @Override protected void runSync(ExtensionContext extensionContext, Element element) throws FaultException { String analyticsServerProfileName = element.getAttribute("analyticsServerProfile"); String streamName = element.getAttribute(AnalyticsPublisherConstants.STREAM_NAME_ATTR); String streamVersion = element.getAttribute(AnalyticsPublisherConstants.STREAM_VERSION); Integer tenantId = getTenantId(extensionContext); AnalyticsStreamConfiguration stream = getEventStream(tenantId, analyticsServerProfileName, streamName, streamVersion); if(stream == null) { log.debug("Stream configuration is invalid"); return; } DataPublisher dataPublisher = getDataPublisher(extensionContext, tenantId, analyticsServerProfileName); if (dataPublisher == null) { String msg = "Error while creating data publisher"; handleException(msg); } String streamId = DataBridgeCommonsUtils.generateStreamId(stream.getName(), stream.getVersion()); dataPublisher.tryPublish(streamId, createMetadata(stream, extensionContext, element), createCorrelationData(stream, extensionContext, element), createPayloadData(stream, extensionContext, element)); } private Integer getTenantId(ExtensionContext context) { DeploymentUnitDir du = new DeploymentUnitDir(new File(context.getDUDir())); QName processIdQname = new QName(context.getProcessModel().getQName().getNamespaceURI(), context.getProcessModel().getQName().getLocalPart() + "-" + du.getStaticVersion()); return AnalyticsPublisherServiceComponent.getBPELServer(). getMultiTenantProcessStore().getTenantId(processIdQname); } private AnalyticsServerProfile getAnalyticsServerProfile(int tenantId, String analyticsServerProfileName) { TenantProcessStore tenantsProcessStore = AnalyticsPublisherServiceComponent.getBPELServer(). getMultiTenantProcessStore().getTenantsProcessStore(tenantId); return tenantsProcessStore.getAnalyticsServerProfile(analyticsServerProfileName); } private AnalyticsStreamConfiguration getEventStream(int tenantId, String analyticsServerProfileName, String streamName, String streamVersion) { AnalyticsServerProfile analyticsServerProfile = getAnalyticsServerProfile(tenantId, analyticsServerProfileName); if(null == analyticsServerProfile) { String errMsg = "AnalyticsServerProfile not found for stream name and version " + streamName + " " + streamVersion; log.error(errMsg); return null; } return analyticsServerProfile.getAnalyticsStreamConfiguration(streamName, streamVersion); } private void handleException(String errMsg, Throwable t) throws FaultException { log.error(errMsg, t); throw new FaultException(AnalyticsPublisherConstants.ANALYTICS_FAULT, errMsg, t); } private void handleException(String errMsg) throws FaultException { log.error(errMsg); throw new FaultException(AnalyticsPublisherConstants.ANALYTICS_FAULT, errMsg); } private Object[] createCorrelationData(AnalyticsStreamConfiguration stream, ExtensionContext context, Element element) throws FaultException { List<AnalyticsKey> correlationAnalyticsKeyList = stream.getCorrelationAnalyticsKeyList(); int objectListSize = correlationAnalyticsKeyList.size(); Object[] dataArray = new Object[objectListSize]; int startIndex = 0; fillDataArray(dataArray, correlationAnalyticsKeyList, startIndex, context, element); return dataArray; } private Object[] createMetadata(AnalyticsStreamConfiguration stream, ExtensionContext context, Element element) throws FaultException { List<AnalyticsKey> metaAnalyticsKeyList = stream.getMetaAnalyticsKeyList(); int objectListSize = metaAnalyticsKeyList.size(); Object[] dataArray = new Object[objectListSize]; int startIndex = 0; fillDataArray(dataArray, metaAnalyticsKeyList, startIndex, context, element); return dataArray; } private Object[] createPayloadData(AnalyticsStreamConfiguration stream, ExtensionContext context, Element element) throws FaultException { List<AnalyticsKey> payloadAnalyticsKeyList = stream.getPayloadAnalyticsKeyList(); int objectListSize = payloadAnalyticsKeyList.size(); Object[] dataArray = new Object[objectListSize]; int startIndex = 0; fillDataArray(dataArray, payloadAnalyticsKeyList, startIndex, context, element); return dataArray; } private void fillDataArray(Object[] dataArray, List<AnalyticsKey> payloadAnalyticsKeyList, int startIndex, ExtensionContext context, Element element) throws FaultException { for (int i = 0; i < payloadAnalyticsKeyList.size(); i++) { AnalyticsKey analyticsKey = payloadAnalyticsKeyList.get(i); if (analyticsKey.getExpression() != null) { String expression = evaluateXPathExpression(context, analyticsKey.getExpression(), element); convertDataType(dataArray, (i + startIndex) , analyticsKey, expression); } else if (analyticsKey.getVariable() != null && analyticsKey.getPart() == null) { if (analyticsKey.getQuery() == null) { String variable = context.readVariable(analyticsKey.getVariable()).getTextContent(); convertDataType(dataArray, ( i + startIndex) , analyticsKey, variable); /* simple types should be specified for here */ } else { String errMsg = "This functionality is currently not supported"; log.error(errMsg); handleException(errMsg); } } else if (analyticsKey.getVariable() != null && analyticsKey.getPart() != null) { NodeList childNodes = context.readVariable(analyticsKey.getVariable()).getChildNodes(); String result = null; String part = analyticsKey.getPart(); for(int j=0; j < childNodes.getLength(); j++) { Node item = childNodes.item(j); if(item != null && item.getNodeType() == Node.ELEMENT_NODE && item.getLocalName().equals(part)) { /* remove the payload part */ result = DOMUtils.domToString(DOMUtils.getFirstChildElement(item)); } } convertDataType(dataArray, ( i + startIndex) , analyticsKey, result); dataArray[i + startIndex] = result; } } } private String evaluateXPathExpression(ExtensionContext context, String xpath, Element element) throws FaultException{ String result = ""; QName qnVariableData = new QName(Namespaces.BPEL11_NS, "getVariableData"); QName qnGetVariableProperty = new QName(Namespaces.BPEL11_NS, "getVariableProperty"); QName qnGetLinkStatus = new QName(Namespaces.BPEL11_NS, "getLinkStatus"); QName qnDoXslTransform = new QName(Namespaces.BPEL11_NS,"getDoXslTransform"); OXPath20ExpressionBPEL20 oexpr = new OXPath20ExpressionBPEL20( context.getInternalInstance().getProcessModel().getOwner(), qnVariableData, qnGetVariableProperty, qnGetLinkStatus, qnDoXslTransform, false); OExpressionLanguage oExpressionLanguage= new OExpressionLanguage(context.getProcessModel().getOwner(),null); oExpressionLanguage.expressionLanguageUri="urn:oasis:names:tc:wsbpel:2.0:sublang:xpath2.0"; oexpr.expressionLanguage= oExpressionLanguage; oExpressionLanguage.properties.put("runtime-class","org.apache.ode.bpel.elang.xpath20.runtime.XPath20ExpressionRuntime"); try{ context.getInternalInstance().getExpLangRuntime().registerRuntime(oExpressionLanguage); } catch (ConfigurationException ex) { String errMsg = "Error when trying to register xpath runtime"; log.error(errMsg, ex); handleException(errMsg, ex); } oexpr.insertMissingData=true; ScopeFrame scopeFrame=((ExtensionContextImpl)context).getScopeFrame(); ExprEvaluationContextImpl exprEvaluationContext= new ExprEvaluationContextImpl( scopeFrame,context.getInternalInstance()); oexpr.vars = (HashMap)context.getVisibleVariables(); oexpr.namespaceCtx = context.getProcessModel().namespaceContext; try { oexpr.xpath = xpath; List resultList= context.getInternalInstance().getExpLangRuntime().evaluate( oexpr, exprEvaluationContext); if(result != null) { Iterator iterator = resultList.iterator(); /** for analytics publishing to work, there should only be a single node here */ while (iterator.hasNext()){ Node node = ((Node)iterator.next()); if(node.getNodeType() == Node.ELEMENT_NODE) { result += node.getTextContent(); } else if(node.getNodeType() == Node.ATTRIBUTE_NODE) { result += node.getNodeValue(); } } } } catch (EvaluationException e) { String errMsg = "Xpath evaluation failed"; log.error(errMsg); handleException(errMsg, e); } return result; } private DataPublisher getDataPublisher(ExtensionContext context, int tenantId, String analyticsServerProfileName) throws FaultException { DataPublisher dataPublisher = null; TenantProcessStore tenantsProcessStore = AnalyticsPublisherServiceComponent.getBPELServer().getMultiTenantProcessStore().getTenantsProcessStore(tenantId); String processName = context.getProcessModel().getName().toString(); dataPublisher = (DataPublisher) tenantsProcessStore.getDataPublisher(processName); // Create new DataPublisher if not created already. if(dataPublisher == null) { AnalyticsServerProfile analyticsServerProfile = getAnalyticsServerProfile(tenantId, analyticsServerProfileName); try { dataPublisher = new DataPublisher(analyticsServerProfile.getType(), analyticsServerProfile.getReceiverURLSet(), analyticsServerProfile.getAuthURLSet(), analyticsServerProfile.getUserName(), analyticsServerProfile.getPassword()); } catch (TransportException e) { String errorMsg = "Transport layer problem."; handleException(errorMsg, e); } catch (DataEndpointAuthenticationException e) { String errorMsg = "Data endpoint authentication problem."; handleException(errorMsg, e); } catch (DataEndpointAgentConfigurationException e) { String errorMsg = "Data endpoint agent configuration problem."; handleException(errorMsg, e); } catch (DataEndpointException e) { String errorMsg = "Data endpoint problem."; handleException(errorMsg, e); } catch (DataEndpointConfigurationException e) { String errorMsg = "Data endpoint configuration problem."; handleException(errorMsg, e); } if (log.isDebugEnabled()) { log.debug("Data Publisher Created : " + analyticsServerProfile.toString()); } if(dataPublisher != null) { tenantsProcessStore.addDataPublisher(processName, dataPublisher); } } return dataPublisher; } public void convertDataType(Object[] dataArray, int index, AnalyticsKey key, String value) { AnalyticsKey.AnalyticsKeyDataType dataType = key.getDataType(); switch (dataType) { case INTEGER : dataArray[index] = Integer.valueOf(value); break; case LONG: dataArray[index] = Long.valueOf(value); break; case DOUBLE: dataArray[index] = Double.valueOf(value); break; case FLOAT: dataArray[index] = Float.valueOf(value); break; case BOOL: dataArray[index] = Boolean.valueOf(value); break; case STRING: dataArray[index] = String.valueOf(value); break; default: dataArray[index] = String.valueOf(value); break; } } }