/*
* 2012-3 Red Hat Inc. and/or its affiliates and other contributors.
*
* 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.overlord.rtgov.switchyard.exchange;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.naming.InitialContext;
import javax.transaction.TransactionManager;
import javax.xml.namespace.QName;
import org.overlord.commons.services.ServiceListener;
import org.overlord.commons.services.ServiceRegistryUtil;
import org.overlord.rtgov.activity.model.soa.RPCActivityType;
import org.overlord.rtgov.activity.model.soa.RequestReceived;
import org.overlord.rtgov.activity.model.soa.RequestSent;
import org.overlord.rtgov.activity.model.soa.ResponseReceived;
import org.overlord.rtgov.activity.model.soa.ResponseSent;
import org.overlord.rtgov.activity.collector.ActivityCollector;
import org.overlord.rtgov.common.util.RTGovProperties;
import org.overlord.rtgov.internal.switchyard.exchange.PropertyAccessor;
import org.switchyard.Exchange;
import org.switchyard.ExchangePhase;
import org.switchyard.HandlerException;
import org.switchyard.Message;
import org.switchyard.Property;
import org.switchyard.Service;
import org.switchyard.ServiceReference;
import org.switchyard.extensions.java.JavaService;
import org.switchyard.extensions.wsdl.WSDLService;
import org.switchyard.metadata.ExchangeContract;
import org.switchyard.metadata.ServiceInterface;
import org.switchyard.security.context.SecurityContext;
import org.switchyard.security.context.SecurityContextManager;
import org.switchyard.security.credential.Credential;
/**
* This class observes exchanges and uses the information to create activity
* events to be validateda.
*
*/
public class AbstractExchangeValidator {
private static final Logger LOG=Logger.getLogger(AbstractExchangeValidator.class.getName());
private static final String JAVAX_TRANSACTION_MANAGER = "javax.transaction.manager";
private static final String JBOSS_TRANSACTION_MANAGER = "java:jboss/TransactionManager";
private TransactionManager _transactionManager=null;
private ActivityCollector _activityCollector=null;
/**
* This method initializes the auditor.
*/
@PostConstruct
protected void init() {
ServiceRegistryUtil.addServiceListener(ActivityCollector.class, new ServiceListener<ActivityCollector>() {
@Override
public void registered(ActivityCollector service) {
_activityCollector = service;
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Exchange Validator: collector="+_activityCollector);
}
}
@Override
public void unregistered(ActivityCollector service) {
_activityCollector = null;
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Exchange Validator: collector unset");
}
}
});
try {
String txnMgr=RTGovProperties.getProperty(JAVAX_TRANSACTION_MANAGER);
if (txnMgr == null) {
txnMgr = JBOSS_TRANSACTION_MANAGER;
}
InitialContext ctx=new InitialContext();
_transactionManager = (TransactionManager)ctx.lookup(txnMgr);
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("Transaction manager '"+txnMgr+"' = "+_transactionManager);
}
} catch (Exception e) {
LOG.log(Level.SEVERE, java.util.PropertyResourceBundle.getBundle(
"rtgov-jbossas.Messages").getString("RTGOV-JBOSSAS-1"), e);
}
}
/**
* This method handles the exchange.
*
* @param exch The exchange
* @throws HandlerException Validation issue found
*/
protected void handleExchange(Exchange exch) throws HandlerException {
org.switchyard.Message mesg=exch.getMessage();
ExchangePhase phase=exch.getPhase();
if (mesg == null) {
LOG.severe("Could not obtain message for phase ("+phase+") and exchange: "+exch);
return;
}
org.switchyard.Context context=exch.getContext();
Service provider=exch.getProvider();
ServiceReference consumer=exch.getConsumer();
SecurityContextManager scm=new SecurityContextManager(exch.getConsumer().getDomain());
SecurityContext securityContext=scm.getContext(exch);
ExchangeContract contract=exch.getContract();
if (provider == null
&& LOG.isLoggable(Level.FINEST)) {
LOG.finest("No provider specified - probably an exception: "
+mesg.getContent());
}
if (_activityCollector != null) {
// Check if transaction should be started
boolean f_txnStarted=false;
try {
if (_transactionManager != null && _transactionManager.getTransaction() == null) {
_transactionManager.begin();
f_txnStarted = true;
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("Validator txn has started");
}
}
} catch (Exception e) {
LOG.log(Level.SEVERE, "Failed to start validator transaction", e);
}
try {
// TODO: If message is transformed, then should the contentType
// be updated to reflect the transformed type?
String messageId=null;
Property mip=context.getProperty(Exchange.MESSAGE_ID, org.switchyard.Scope.MESSAGE);
if (mip != null) {
messageId = (String)mip.getValue();
}
String contentType=null;
Property ctp=context.getProperty(Exchange.CONTENT_TYPE, org.switchyard.Scope.MESSAGE);
if (ctp != null) {
contentType = ((QName)ctp.getValue()).toString();
// RTGOV-250 - remove java: prefix from Java types, to make the type consistent with
// events reported outside switchyard
if (contentType != null && contentType.startsWith("java:")) {
contentType = contentType.substring(5);
}
}
// Extract service type and operation from the consumer
// (service reference), as provider is not always available
QName serviceType=consumer.getName();
String opName=contract.getConsumerOperation().getName();
if (phase == ExchangePhase.IN) {
if (!consumer.getServiceMetadata().getRegistrant().isBinding()) {
// Only record the request being sent, if the source is a component, not a binding
RequestSent sent=new RequestSent();
// Only report service type if provider is not a binding
if (provider == null
|| !provider.getServiceMetadata().getRegistrant().isBinding()) {
sent.setServiceType(serviceType.toString());
}
sent.setInterface(getInterface(consumer, provider));
sent.setOperation(opName);
sent.setMessageId(messageId);
validate(mesg, contentType, sent, securityContext);
}
if (provider == null || !provider.getServiceMetadata().getRegistrant().isBinding()) {
RequestReceived recvd=new RequestReceived();
recvd.setServiceType(serviceType.toString());
recvd.setInterface(getInterface(consumer, provider));
recvd.setOperation(opName);
recvd.setMessageId(messageId);
validate(mesg, contentType, recvd, securityContext);
}
} else if (phase == ExchangePhase.OUT) {
if (contentType == null) {
// Ignore as probably due to exception on handling the request
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("No content type - possibly due to exception on handling the request");
}
return;
}
String relatesTo=null;
Property rtp=context.getProperty(Exchange.RELATES_TO, org.switchyard.Scope.MESSAGE);
if (rtp != null) {
relatesTo = (String)rtp.getValue();
}
if (provider == null
|| !provider.getServiceMetadata().getRegistrant().isBinding()) {
ResponseSent sent=new ResponseSent();
// Only report service type if provider is not a binding
if (provider == null
|| !provider.getServiceMetadata().getRegistrant().isBinding()) {
sent.setServiceType(serviceType.toString());
}
sent.setInterface(getInterface(consumer, provider));
sent.setOperation(opName);
sent.setMessageId(messageId);
sent.setReplyToId(relatesTo);
validate(mesg, contentType, sent, securityContext);
}
if (!consumer.getServiceMetadata().getRegistrant().isBinding()) {
// Only record the response being received, if the
// target is a component, not a binding
ResponseReceived recvd=new ResponseReceived();
recvd.setServiceType(serviceType.toString());
recvd.setInterface(getInterface(consumer, provider));
recvd.setOperation(opName);
recvd.setMessageId(messageId);
recvd.setReplyToId(relatesTo);
validate(mesg, contentType, recvd, securityContext);
}
}
} finally {
if (f_txnStarted) {
try {
_transactionManager.commit();
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("Validator txn has committed");
}
} catch (Exception e) {
LOG.log(Level.SEVERE, "Failed to commit validator transaction", e);
}
}
}
}
}
/**
* This method extracts the interface from the exchange details.
*
* @param consumer The exchange consumer
* @param provider The exchange provider
* @return The interface
*/
protected String getInterface(ServiceReference consumer, Service provider) {
String ret=null;
ServiceInterface intf=null;
if (consumer.getServiceMetadata().getRegistrant().isBinding()) {
intf = consumer.getInterface();
} else {
intf = provider.getInterface();
}
if (JavaService.TYPE.equals(intf.getType())) {
ret = ((JavaService)intf).getJavaInterface().getName();
} else if (WSDLService.TYPE.equals(intf.getType())) {
ret = ((WSDLService)intf).getPortType().toString();
}
return (ret);
}
/**
* This method validates the supplied information as an activity
* event.
*
* @param exchange The exchange
* @param contentType The message content type
* @param at The activity type
* @param sc The optional security context
* @throws HandlerException Validation failure
*/
protected void validate(Message msg, String contentType,
RPCActivityType at, SecurityContext sc) throws HandlerException {
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("Validate msg="+msg+" contentType="+contentType+" at="+at);
}
if (at != null) {
at.setMessageType(contentType);
Object content=msg.getContent();
at.setContent(_activityCollector.processInformation(null,
contentType, content, new PropertyAccessor(msg.getContext()), at));
// Check if principal has been defined
if (sc != null) {
for (Credential cred : sc.getCredentials()) {
if (cred instanceof org.switchyard.security.credential.NameCredential) {
at.setPrincipal(((org.switchyard.security.credential.NameCredential)cred).getName());
break;
} else if (cred instanceof org.switchyard.security.credential.PrincipalCredential) {
at.setPrincipal(((org.switchyard.security.credential.PrincipalCredential)cred)
.getPrincipal().getName());
break;
}
}
}
try {
_activityCollector.validate(at);
} catch (Exception e) {
// Strip the exception and just return the message
throw new HandlerException(e.getMessage());
}
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("Activity is valid: at="+at);
}
}
}
}