package org.drools.mas.helpers;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
import javax.xml.namespace.QName;
import org.drools.mas.*;
import org.drools.mas.body.acts.AbstractMessageBody;
import org.drools.mas.body.acts.Inform;
import org.drools.mas.body.acts.InformRef;
import org.drools.mas.body.content.Action;
import org.drools.mas.body.acts.InformIf;
import org.drools.mas.util.ACLMessageFactory;
import org.drools.mas.util.MessageContentEncoder;
import org.drools.mas.util.MessageContentFactory;
import org.drools.runtime.rule.Variable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SyncDialogueHelper {
boolean multiReturnValue = false;
private AbstractMessageBody returnBody;
private Encodings encode = Encodings.XML;
private URL endpointURL;
private QName qname;
private long maximumWaitTime = 60000;
private long minWaitTime = 500;
private int maxRetries = 1;
private static Logger logger = LoggerFactory.getLogger( SyncDialogueHelper.class.getName() );
public SyncDialogueHelper(String url, Encodings enc) {
try {
this.endpointURL = new URL(AsyncAgentService.class.getResource("."), url);
} catch (MalformedURLException ex) {
logger.error( ex.getMessage() );
}
this.qname = new QName("http://mas.drools.org/", "AsyncAgentService");
this.encode = enc;
}
public SyncDialogueHelper(String url) {
try {
this.endpointURL = new URL(AsyncAgentService.class.getResource("."), url);
} catch (MalformedURLException ex) {
logger.error(ex.getMessage());
}
this.qname = new QName("http://mas.drools.org/", "AsyncAgentService");
}
public long getMaximumWaitTime() {
return maximumWaitTime;
}
public void setMaximumWaitTime( long maximumWaitTime ) {
this.maximumWaitTime = maximumWaitTime;
}
public long getMinWaitTime() {
return minWaitTime;
}
public void setMinWaitTime( long minWaitTime ) {
this.minWaitTime = minWaitTime;
}
public int getMaxRetries() {
return maxRetries;
}
public void setMaxRetries( int maxRetries ) {
this.maxRetries = maxRetries;
}
public String invokeRequest( String sender, String methodName, LinkedHashMap<String, Object> args ) throws UnsupportedOperationException {
return invokeRequest( sender, "", methodName, args);
}
public String invokeRequest( String methodName, LinkedHashMap<String, Object> args ) throws UnsupportedOperationException {
return invokeRequest( UUID.randomUUID().toString(), "", methodName, args );
}
public String invokeRequest( String sender, String receiver, String methodName, LinkedHashMap<String, Object> args )
throws UnsupportedOperationException, IllegalStateException {
multiReturnValue = false;
int numVars = 0;
for ( Object o : args.values() ) {
if ( o == Variable.v ) {
numVars++;
if ( numVars >= 2 ) {
multiReturnValue = true;
break;
}
}
}
AsyncDroolsAgentService asyncServicePort = null;
if ( this.endpointURL == null || this.qname == null ) {
throw new IllegalStateException( "A Web Service URL and a QName Must be Provided for the client to work!" );
} else {
asyncServicePort = new AsyncAgentService( this.endpointURL, this.qname ).getAsyncAgentServicePort();
}
ACLMessageFactory factory = new ACLMessageFactory( encode );
Action action = MessageContentFactory.newActionContent( methodName, args );
int numTries = 0;
do {
ACLMessage req = factory.newRequestMessage( sender, receiver, action );
asyncServicePort.tell( req );
List<ACLMessage> answers = waitForAnswers( asyncServicePort, req.getId(), 2, maximumWaitTime, methodName );
if ( validateRequestResponses( answers, methodName, args ) ) {
if ( ! multiReturnValue ) {
returnBody = answers.size() == 2 ? ( (Inform) answers.get( 1 ).getBody() ) : null;
} else {
returnBody = answers.size() == 2 ? ( (InformRef) answers.get( 1 ).getBody() ) : null;
}
return req.getId();
}
} while ( ++numTries < maxRetries );
throw new IllegalStateException(" Request " + methodName + " with args "
+ args + " did not return in time" );
}
private boolean validateRequestResponses( List<ACLMessage> answers, String methodName, Map<String,Object> args ) {
if ( answers.size() != 2 ) {
return false;
}
if ( Act.AGREE.equals( answers.get( 1 ).getPerformative() ) ) {
throw new IllegalStateException( " TODO : Agree was collected after its response, check rules" );
}
ACLMessage answer1 = answers.get( 0 );
if ( ! Act.AGREE.equals( answer1.getPerformative() ) ) {
throw new UnsupportedOperationException( " Request " + methodName + " was not agreed with args " + args );
}
ACLMessage answer2 = answers.get( 1 );
Act act2 = answer2.getPerformative();
if ( ! ( Act.INFORM.equals( act2 ) || Act.INFORM_REF.equals( act2 ) ) ) {
throw new IllegalStateException(" Request " + methodName + " with args "
+ args + "failed and returned this msg: " + answer2 );
}
return true;
}
public String invokeQueryIf( String sender, String receiver, Object proposition ) {
AsyncDroolsAgentService asyncServicePort = null;
if (this.endpointURL == null || this.qname == null) {
throw new IllegalStateException("A Web Service URL and a QName Must be Provided for the client to work!");
} else {
asyncServicePort = new AsyncAgentService(this.endpointURL, this.qname).getAsyncAgentServicePort();
}
ACLMessageFactory factory = new ACLMessageFactory(Encodings.XML);
ACLMessage qryif = factory.newQueryIfMessage(sender, receiver, proposition);
asyncServicePort.tell(qryif);
List<ACLMessage> answers = waitForAnswers( asyncServicePort, qryif.getId(), 1, maximumWaitTime, proposition.toString() );
returnBody = answers.get(0).getBody();
return qryif.getId();
}
public String invokeInform( String sender, String receiver, Object proposition ) {
AsyncDroolsAgentService asyncServicePort;
if ( this.endpointURL == null || this.qname == null ) {
throw new IllegalStateException( "A Web Service URL and a QName Must be Provided for the client to work!" );
} else {
asyncServicePort = new AsyncAgentService( this.endpointURL, this.qname ).getAsyncAgentServicePort();
}
ACLMessageFactory factory = new ACLMessageFactory( encode );
ACLMessage newInformMessage = factory.newInformMessage( sender, receiver, proposition );
asyncServicePort.tell( newInformMessage );
return newInformMessage.getId();
}
public String invokeConfirm( String sender, String receiver, Object proposition ) {
AsyncDroolsAgentService asyncServicePort;
if ( this.endpointURL == null || this.qname == null ) {
throw new IllegalStateException("A Web Service URL and a QName Must be Provided for the client to work!");
} else {
asyncServicePort = new AsyncAgentService(this.endpointURL, this.qname).getAsyncAgentServicePort();
}
ACLMessageFactory factory = new ACLMessageFactory( encode );
ACLMessage newConfirmMessage = factory.newConfirmMessage( sender, receiver, proposition );
asyncServicePort.tell( newConfirmMessage );
return newConfirmMessage.getId();
}
public String invokeDisconfirm( String sender, String receiver, Object proposition ) {
AsyncDroolsAgentService asyncServicePort;
if ( this.endpointURL == null || this.qname == null ) {
throw new IllegalStateException("A Web Service URL and a QName Must be Provided for the client to work!");
} else {
asyncServicePort = new AsyncAgentService( this.endpointURL, this.qname ).getAsyncAgentServicePort();
}
ACLMessageFactory factory = new ACLMessageFactory( encode );
ACLMessage newDisconfirmMessage = factory.newDisconfirmMessage( sender, receiver, proposition );
asyncServicePort.tell( newDisconfirmMessage );
return newDisconfirmMessage.getId();
}
private List<ACLMessage> waitForAnswers( AsyncDroolsAgentService asyncServicePort, String msgid, int numExpectedMessages, long maxTimeout, String msgRef ) {
List<ACLMessage> answers = new ArrayList<ACLMessage>();
long waitTime = minWaitTime;
do {
try {
logger.debug( " >>> [" + msgid + "] Waiting for " + numExpectedMessages + " answers (" + waitTime + ") for: Message -> " + msgRef + " , now I have " + answers.size() );
logger.debug( answers.toString() );
Thread.sleep( waitTime );
} catch ( InterruptedException ex ) {
logger.error( ex.getMessage() );
}
logger.debug( " >>> [" + msgid + "] Wake up with " + answers );
List<ACLMessage> incomingAnswers = asyncServicePort.getResponses( msgid );
logger.debug( " >>> [" + msgid + "] Incoming new " + incomingAnswers );
answers.addAll( incomingAnswers );
logger.debug( " >>> [" + msgid + "] After adding new " + answers );
waitTime *= 2;
} while ( answers.size() < numExpectedMessages && waitTime < maxTimeout );
if ( answers.size() < numExpectedMessages ) {
logger.equals( " >>> [" + msgid + "] Expecting " + numExpectedMessages + " but got " + answers.size() );
}
return answers;
}
public Object getReturn( boolean decode ) throws UnsupportedOperationException {
if ( returnBody == null ) {
return null;
}
if ( decode ) {
MessageContentEncoder.decodeBody( returnBody, encode );
if ( returnBody instanceof Inform ) {
return ( (Inform) returnBody ).getProposition().getData();
}
if ( returnBody instanceof InformIf ) {
return ( (InformIf) returnBody ).getProposition().getData();
}
} else {
if ( returnBody instanceof Inform ) {
return ( (Inform) returnBody ).getProposition().getEncodedContent();
}
if ( returnBody instanceof InformIf ) {
return ( (InformIf) returnBody ).getProposition().getEncodedContent();
}
}
return returnBody;
}
// public List<ACLMessage> getAgentAnswers(String reqId) {
// AsyncDroolsAgentService asyncServicePort = null;
// if (this.endpointURL == null || this.qname == null) {
// throw new IllegalStateException("A Web Service URL and a QName Must be Provided for the client to work!");
// } else {
// asyncServicePort = new AsyncAgentService(this.endpointURL, this.qname).getAsyncAgentServicePort();
// }
// return asyncServicePort.getResponses(reqId);
// }
}