/*
* Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.wso2.carbon.registry.event.ws.internal.receivers;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.engine.AxisEngine;
import org.apache.axis2.receivers.AbstractMessageReceiver;
import org.apache.axis2.util.MessageContextBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.registry.event.ws.internal.builders.exceptions.InvalidExpirationTimeException;
import org.wso2.carbon.registry.event.ws.internal.builders.exceptions.InvalidMessageException;
import org.wso2.carbon.registry.event.ws.internal.builders.utils.BuilderUtils;
import org.wso2.carbon.registry.event.ws.internal.WSEventBrokerHolder;
import org.wso2.carbon.registry.event.ws.internal.exception.WSEventException;
import org.wso2.carbon.registry.event.ws.internal.util.EventingConstants;
import org.wso2.carbon.registry.event.ws.internal.util.EventBrokerUtils;
import org.wso2.carbon.registry.event.core.EventBroker;
import org.wso2.carbon.registry.event.core.Message;
import org.wso2.carbon.registry.event.core.util.EventBrokerConstants;
import org.wso2.carbon.registry.event.core.exception.EventBrokerException;
import org.wso2.carbon.registry.event.core.subscription.Subscription;
import org.wso2.carbon.registry.event.ws.internal.builders.*;
import javax.xml.namespace.QName;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;
public class CarbonEventingMessageReceiver extends AbstractMessageReceiver {
private static final Log log = LogFactory.getLog(CarbonEventingMessageReceiver.class);
private static final String ENABLE_SUBSCRIBE = "enableSubscribe";
private static final String ENABLE_UNSUBSCRIBE = "enableUnsubscribe";
private static final String ENABLE_RENEW = "enableRenew";
private static final String ENABLE_GET_STATUS = "enableGetStatus";
private static final Pattern TO_ADDRESS_PATTERN = Pattern.compile("/services/.*/publish/(.*)");
private boolean isEnabled(MessageContext mc, String operation) {
if (mc.getAxisService() != null) {
String operationValue =
(String) mc.getAxisService().getParameterValue(operation);
return operationValue == null || !operationValue.toLowerCase().equals(
Boolean.toString(false));
}
return true;
}
public final void invokeBusinessLogic(MessageContext mc) throws AxisFault {
try {
processMessage(mc);
} catch (WSEventException e) {
log.error("An exception occured. Unable to Process Request", e);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String details = sw.toString();
pw.close();
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "EventSourceUnableToProcess",
e.getMessage(), details, mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
}
protected void handleSubscribe(MessageContext mc) throws AxisFault, WSEventException {
try {
if (!isEnabled(mc, ENABLE_SUBSCRIBE)) {
log.warn("Subscribe operation is disabled");
return;
}
Subscription subscription = null;
SubscribeCommandBuilder builder = new SubscribeCommandBuilder(mc);
try {
subscription = builder.toSubscription(mc.getEnvelope());
subscription.setOwner(EventBrokerUtils.getLoggedInUserName());
} catch (InvalidExpirationTimeException e) {
if (log.isDebugEnabled()) {
log.debug(e.getMessage());
}
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "InvalidExpirationTime",
e.getMessage(), "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
} catch (InvalidMessageException e) {
if (log.isDebugEnabled()) {
log.debug(e.getMessage());
}
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "InvalidMessage",
e.getMessage(), "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
if (subscription != null) {
// set the topic name using the url
String toAddress = mc.getOptions().getTo().getAddress();
String topicName = subscription.getEventFilter().getValue();
if ((topicName == null) || (topicName.equals(""))) {
// we take string after the service name as the topic name
if (toAddress.indexOf(EventingConstants.BROKER_SERVICE_NAME + "/") > 0) {
topicName = toAddress.substring(
toAddress.indexOf(EventingConstants.BROKER_SERVICE_NAME + "/")
+ EventingConstants.BROKER_SERVICE_NAME.length() + 1);
}
}
subscription.setTopicName(topicName);
if (log.isDebugEnabled()) {
log.debug("Subscription request recieved : " + subscription.getId());
}
if (subscription.getEventSinkURL().startsWith("sqs://")){
subscription.setEventDispatcherName(EventBrokerConstants.EVENT_SINK_DISPATCHER_NAME);
} else {
subscription.setEventDispatcherName(EventBrokerConstants.WS_EVENT_DISPATCHER_NAME);
}
String subID = WSEventBrokerHolder.getInstance().getEventBroker().subscribe(subscription);
subscription.setId(subID);
if (subID != null) {
if (log.isDebugEnabled()) {
log.debug("Sending subscription response for Subscription ID : " +
subscription.getId());
}
SOAPEnvelope soapEnvelope = builder.fromSubscription(subscription);
dispatchResponse(soapEnvelope, EventingConstants.WSE_SUBSCRIBE_RESPONSE, mc, false);
} else {
log.debug("Subscription Failed, sending fault response");
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "EventSourceUnableToProcess",
"Unable to subscribe ", "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
} else {
log.debug("Subscription Failed, sending fault response");
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "EventSourceUnableToProcess",
"Unable to subscribe ", "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
} catch (Exception e) {
String errorMessage = e.getMessage();
if(errorMessage.contains("errorCode=UNAUTHORIZED_ACCESS")){
String user = EventBrokerUtils.getLoggedInUserName();
errorMessage = user +" does not has permission to perform subscription, please check permissions";
}
throw new WSEventException(errorMessage, e);
}
}
protected void handleUnsubscribe(MessageContext mc) throws AxisFault, WSEventException {
if (!isEnabled(mc, ENABLE_UNSUBSCRIBE)) {
log.warn("Unsubscribe operation is disabled");
return;
}
try {
UnSubscribeCommandBuilder builder = new UnSubscribeCommandBuilder(mc);
Subscription subscription = builder.toSubscription(mc.getEnvelope());
if (log.isDebugEnabled()) {
log.debug("UnSubscribe response recived for Subscription ID : " +
subscription.getId());
}
getBrokerService().unsubscribe(subscription.getId());
if (log.isDebugEnabled()) {
log.debug("Sending UnSubscribe responce for Subscription ID : " +
subscription.getId());
}
SOAPEnvelope soapEnvelope = builder.fromSubscription(subscription);
dispatchResponse(soapEnvelope, EventingConstants.WSE_UNSUBSCRIBE_RESPONSE, mc, false);
} catch (InvalidMessageException e) {
throw new WSEventException("Invalid message ", e);
} catch (EventBrokerException e) {
log.debug("UnSubscription failed, sending fault repsponse");
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "EventSourceUnableToProcess",
"Unable to Unsubscribe", "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
}
protected void handleGetStatus(MessageContext mc) throws AxisFault, WSEventException {
if (!isEnabled(mc, ENABLE_GET_STATUS)) {
log.warn("Get Status operation is disabled");
return;
}
try {
GetStatusCommandBuilder builder = new GetStatusCommandBuilder(mc);
Subscription subscription = builder.toSubscription(mc.getEnvelope());
if (log.isDebugEnabled()) {
log.debug("GetStatus request recived for Subscription ID : " +
subscription.getId());
}
subscription = getBrokerService().getSubscription(subscription.getId());
if (subscription != null) {
String loggedInUser = EventBrokerUtils.getLoggedInUserName();
if (!loggedInUser.equals("admin") && !loggedInUser.equals(subscription.getOwner())) {
throw new WSEventException("User " + loggedInUser + " does not own subscription " + subscription.getId());
}
if (log.isDebugEnabled()) {
log.debug("Sending GetStatus responce for Subscription ID : " +
subscription.getId());
}
SOAPEnvelope soapEnvelope = builder.fromSubscription(subscription);
dispatchResponse(soapEnvelope, EventingConstants.WSE_GET_STATUS_RESPONSE, mc, false);
} else {
log.debug("GetStatus failed, sending fault response");
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "EventSourceUnableToProcess",
"Subscription Not Found", "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
} catch (InvalidMessageException e) {
throw new WSEventException("Invalid message exception ", e);
} catch (EventBrokerException e) {
throw new WSEventException("Event processing exception ",e);
}
}
protected void handleRenew(MessageContext mc) throws AxisFault, WSEventException {
if (!isEnabled(mc, ENABLE_RENEW)) {
log.warn("Renew operation is disabled");
return;
}
RenewCommandBuilder builder = new RenewCommandBuilder(mc);
Subscription subscription = null;
try {
subscription = builder.toSubscription(mc.getEnvelope());
} catch (InvalidExpirationTimeException e) {
if (log.isDebugEnabled()) {
log.debug(e.getMessage());
}
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "InvalidExpirationTime",
e.getMessage(), "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
} catch (InvalidMessageException e) {
e.printStackTrace();
}
if (subscription != null && subscription.getId() != null) {
if (log.isDebugEnabled()) {
log.debug("Renew request recived for Subscription ID : " +
subscription.getId());
}
try {
getBrokerService().renewSubscription(subscription);
if (log.isDebugEnabled()) {
log.debug("Sending Renew response for Subscription ID : " +
subscription.getId());
}
SOAPEnvelope soapEnvelope =
builder.fromSubscription(subscription);
dispatchResponse(soapEnvelope, EventingConstants.WSE_RENEW_RESPONSE, mc, false);
} catch (EventBrokerException e) {
log.debug("Renew failed, sending fault response");
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "UnableToRenew",
"Subscription Not Found", "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
} else {
SOAPEnvelope soapEnvelope = BuilderUtils.genFaultResponse(
EventingConstants.WSE_FAULT_CODE_RECEIVER, "UnableToRenew",
"Subscription Not Found", "", mc.isSOAP11());
dispatchResponse(soapEnvelope, EventingConstants.WSA_FAULT, mc, true);
}
}
protected void handleGetSubscriptions(MessageContext mc) throws WSEventException {
try {
OMElement element = mc.getEnvelope().getBody().getFirstElement();
String maxResultCountStr = element.getAttributeValue(new QName("maxResultCount"));
String resultFilterStr = element.getAttributeValue(new QName("resultFilter"));
String firstIndexStr = element.getAttributeValue(new QName("firstIndex"));
boolean ascending = true;
String sortingInstructions = null;
if (mc.getEnvelope().getHeader() != null) {
OMElement sortingInstructionsEle = mc.getEnvelope().getHeader().getFirstChildWithName(EventingConstants.SORTING_DATA);
if (sortingInstructionsEle != null) {
sortingInstructions = sortingInstructionsEle.getText();
String style = sortingInstructionsEle.getAttributeValue(new QName(EventingConstants.SORTING_STYLE));
ascending = (style == null || !style.equals(EventingConstants.SORTING_STYLES.decending.toString()));
}
}
int maxResultCount = Integer.MAX_VALUE;
if (maxResultCountStr != null) {
maxResultCount = Integer.parseInt(maxResultCountStr);
if (maxResultCount < 0) {
maxResultCount = Integer.MAX_VALUE;
}
}
int firstIndex = 0;
if (firstIndexStr != null) {
firstIndex = Integer.parseInt(firstIndexStr);
}
String loggedInUser = EventBrokerUtils.getLoggedInUserName();
List<Subscription> filteredSubscriptions = new ArrayList<Subscription>();
List<Subscription> subscriptions = getBrokerService().getAllSubscriptions(resultFilterStr);
subscriptions = sortResults(sortingInstructions, ascending, subscriptions);
for (Subscription subscription : subscriptions) {
if (loggedInUser.equals("admin") || loggedInUser.equals(subscription.getOwner())) {
filteredSubscriptions.add(subscription);
}
}
SOAPEnvelope getSubscriptionsResponseEnv =
GetSubscriptionsCommandBuilder.buildResponseforGetSubscriptions(
filteredSubscriptions, maxResultCount, firstIndex);
dispatchResponse(getSubscriptionsResponseEnv,
EventingConstants.WSE_RENEW_RESPONSE, mc, false);
} catch (AxisFault e) {
throw new WSEventException("Error at Get Subscriptions:" + e.getMessage(), e);
} catch (EventBrokerException e) {
throw new WSEventException("Can not get the subscriptions ", e);
}
}
protected void handleInstallEventSink(MessageContext mc) throws WSEventException {
throw new UnsupportedOperationException();
}
protected void handleEvent(MessageContext mc) throws AxisFault, WSEventException {
String topic = EventBrokerUtils.extractTopicFromMessage(mc);
if (topic == null) {
// No topic, just drop the message.
return;
}
try {
Message message = new Message();
message.setMessage(mc.getEnvelope().getBody().getFirstElement());
getBrokerService().publishRobust(message, topic);
} catch (EventBrokerException e) {
throw new WSEventException("Can not publish the message : " + e.getMessage(), e);
}
}
public final void processMessage(MessageContext mc) throws AxisFault, WSEventException {
if (EventingConstants.WSE_SUBSCRIBE.equals(mc.getWSAAction())) {
handleSubscribe(mc);
} else if (EventingConstants.WSE_UNSUBSCRIBE.equals(mc.getWSAAction())) {
handleUnsubscribe(mc);
} else if (EventingConstants.WSE_GET_STATUS.equals(mc.getWSAAction())) {
handleGetStatus(mc);
} else if (EventingConstants.WSE_RENEW.equals(mc.getWSAAction())) {
handleRenew(mc);
} else if (EventingConstants.WSE_GET_SUBSCRIPTIONS.equals(mc.getWSAAction())) {
handleGetSubscriptions(mc);
} else if (EventingConstants.WSE_INSTALL_EVENT_SINK.equals(mc.getWSAAction())) {
//TODO this is to install certain new event sink (e.g. by adding classes to classpath) so it can be used by subscriptions
handleInstallEventSink(mc);
} else {
handleEvent(mc);
}
}
/**
* Dispatch the message to the target endpoint
*
* @param soapEnvelope Soap Enevlop with message
* @param responseAction WSE action for the response
* @param mc Message Context
* @param isFault Whether a Fault message must be sent
* @throws AxisFault Thrown by the axis2 engine.
*/
private void dispatchResponse(SOAPEnvelope soapEnvelope, String responseAction,
MessageContext mc, boolean isFault) throws AxisFault {
MessageContext rmc = MessageContextBuilder.createOutMessageContext(mc);
rmc.getOperationContext().addMessageContext(rmc);
replicateState(mc);
rmc.setEnvelope(soapEnvelope);
rmc.setWSAAction(responseAction);
rmc.setSoapAction(responseAction);
if (isFault) {
AxisEngine.sendFault(rmc);
} else {
AxisEngine.send(rmc);
}
}
private EventBroker getBrokerService() {
return WSEventBrokerHolder.getInstance().getEventBroker();
}
public List<Subscription> sortResults(String sortingInstructions, final boolean ascending, List<Subscription> list) {
if (sortingInstructions != null) {
Comparator<Subscription> comparator = null;
if (sortingInstructions.equals("eventSinkAddress")) {
comparator = new Comparator<Subscription>() {
public int compare(Subscription o1, Subscription o2) {
if (o2 == null || o1 == null) {
return 0;
}
return (ascending ? 1 : -1) * o1.getEventSinkURL().compareTo(o2.getEventSinkURL());
}
};
} else if (sortingInstructions.equals("createdTime")) {
comparator = new Comparator<Subscription>() {
public int compare(Subscription o1, Subscription o2) {
if (o2 == null || o1 == null) {
return 0;
}
return (ascending ? 1 : -1) * o1.getCreatedTime().compareTo(o2.getCreatedTime());
}
};
} else if (sortingInstructions.equals("subscriptionEndingTime")) {
comparator = new Comparator<Subscription>() {
public int compare(Subscription o1, Subscription o2) {
if (o2 == null || o1 == null) {
return 0;
}
return (ascending ? 1 : -1) * o1.getExpires().compareTo(o2.getExpires());
}
};
}
if (comparator != null) {
Collections.sort(list, comparator);
}
}
return list;
}
}