/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.savara.bpel.internal.model.change;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.scribble.protocol.util.ActivityUtil;
import org.scribble.protocol.util.RunUtil;
import org.savara.protocol.model.util.InteractionUtil;
import org.scribble.protocol.model.*;
/**
* This class provides utility functions for detecting
* patterns related to interactions.
*/
public class InteractionPatterns {
private static final Logger logger=Logger.getLogger(InteractionPatterns.class.getName());
/**
* This method checks whether the supplied interaction
* is a request that requires a scope with associated
* fault handlers.
*
* @param interaction The interaction
* @return Whether the interaction is a request requiring
* an outer fault handler
*/
public static boolean isFaultHandlerRequired(org.scribble.protocol.model.Interaction interaction) {
boolean ret=false;
// Check if interaction is an invoke, and followed
// by a choice representing a normal and multiple
// fault responses
if (InteractionUtil.isRequest(interaction) &&
InteractionUtil.getRequestLabel(interaction) != null) {
if (interaction.getParent() instanceof
org.scribble.protocol.model.Block) {
org.scribble.protocol.model.Block block=
(org.scribble.protocol.model.Block)interaction.getParent();
int pos=block.getContents().indexOf(interaction);
if (pos != -1 && pos < block.getContents().size()-1) {
org.scribble.protocol.model.Activity act=
block.getContents().get(pos+1);
ret = isFaultHandlerChoice(act);
}
}
}
return(ret);
}
protected static boolean isFaultHandlerChoice(Activity act) {
boolean ret=false;
if (act instanceof org.scribble.protocol.model.Choice) {
// Need to check if each path receives a
// response (normal and fault)
org.scribble.protocol.model.Choice choice=
(org.scribble.protocol.model.Choice)act;
if (choice.getPaths().size() > 0) {
ret = true;
}
for (int i=0; ret &&
i < choice.getPaths().size(); i++) {
// Get initial interaction
Interaction intn=getFirstInteraction(choice.getPaths().get(0));
if (intn != null) {
ret = !InteractionUtil.isRequest(intn);
}
}
} else if (act instanceof org.scribble.protocol.model.Parallel) {
org.scribble.protocol.model.Parallel par=(org.scribble.protocol.model.Parallel)act;
for (Block b : par.getPaths()) {
if (b.size() > 0 && isFaultHandlerChoice(b.get(0))) {
ret = true;
break;
}
}
}
return(ret);
}
// TODO: Method to detect if normal response, which needs
// to enhance the invoke (and subsequent activities following
// the invoke), or a fault response needing to
// place itself and subsequent activities in a fault handler.
// Methods need to return (and set) the relevant sequence
// to use for subsequent activities.
public static boolean isResponseAndFaultHandler(Choice choice) {
boolean ret=choice.getPaths().size() > 0;
// Check if all paths are responses with same reply label
String label=null;
for (int i=0; ret && i < choice.getPaths().size(); i++) {
Block path=choice.getPaths().get(i);
// Get initial interaction
Interaction interaction=getFirstInteraction(path);
if (interaction != null) {
if (i == 0) {
label = InteractionUtil.getReplyToLabel(interaction);
if (label == null || InteractionUtil.isRequest(interaction)
|| InteractionUtil.isSend(interaction)) {
ret = false;
}
} else {
String replyTo=InteractionUtil.getReplyToLabel(interaction);
if (replyTo == null ||
replyTo.equals(label) == false ||
InteractionUtil.isRequest(interaction) ||
InteractionUtil.isSend(interaction)) {
ret = false;
}
}
}
}
return(ret);
}
/**
* This method obtains the interaction that triggers a
* specified path in a BPEL pick activity.
*
* @param path The path
* @return The interaction that triggers the path in
* the pick activity
*/
public static Interaction getPickPathInteraction(Block path) {
Interaction ret=null;
// TODO: This method is the opposite of the
// 'isInteractionPickPathTrigger', so needs to be
// updated to reflect any changes to that method
if (path.getContents().size() > 0) {
org.scribble.protocol.model.Activity sub=
path.getContents().get(0);
// Check if scope
if (sub instanceof Run) {
//Protocol defn=((Run)sub).getProtocol();
Protocol defn=RunUtil.getInnerProtocol(((Run)sub).getEnclosingProtocol(),
((Run)sub).getProtocolReference());
org.scribble.protocol.model.Activity b=null;
for (int j=0; b == null &&
j < defn.getBlock().getContents().size(); j++) {
if (!ActivityUtil.isDeclaration(defn.getBlock().getContents().get(j))) {
b = (org.scribble.protocol.model.Activity)
defn.getBlock().getContents().get(j);
}
}
if (b != null) {
sub = b;
}
}
if (sub instanceof Interaction) {
ret = (Interaction)sub;
}
}
return(ret);
}
/**
* This method determines whether the supplied interaction
* is the trigger interaction within a BPEL pick activity.
*
* @param in The interaction
* @return Whether the interaction is a pick trigger activity
*/
public static boolean isInteractionPickPathTrigger(Interaction in) {
boolean ret=false;
// TODO: Need to determine all situations and ensure
// is generic enough to cope with extensions to Scribble
// model
Block path=(Block)in.getParent();
if (path.getParent() instanceof Choice &&
InteractionPatterns.isSwitch((Choice)path.getParent())) {
ret = true;
// Check if receive is directly contained within a
// sub-definition
// TODO: If first interaction in a nested protocol, then may also
// need to check whether being generated as first element in an onMessage
// with the same interaction details, as checking that the nested protocol
// has been called inside a choice in the protocol may not be adequate,
// as the same protocol may have also be called outside of a choice - so
// the context could be relevant.
} else if (InteractionUtil.isSend(in) == false &&
path.getParent() instanceof org.scribble.protocol.model.Protocol &&
path.getParent().getParent() instanceof org.scribble.protocol.model.Protocol) {
ret = true;
}
return(ret);
}
public static boolean isSwitch(Choice choice) {
boolean ret=false;
// For a choice to be considered a 'switch', it only needs
// to be a receiver
if (choice.getRole() == null || !choice.getRole().equals(choice.getEnclosingProtocol().getLocatedRole())) {
ret = true;
}
return(ret);
}
public static Interaction getRequestForResponseInFaultHandler(Interaction interaction) {
Interaction ret=null;
if (InteractionUtil.isRequest(interaction) == false &&
InteractionUtil.getReplyToLabel(interaction) != null) {
// Find if contained in 'if' path
if (interaction.getParent() instanceof Block &&
interaction.getParent().getParent() instanceof Choice) {
Choice choice=(Choice)interaction.getParent().getParent();
// Obtain interaction prior to 'If'
if (choice.getParent() instanceof
org.scribble.protocol.model.Block) {
org.scribble.protocol.model.Block block=
(org.scribble.protocol.model.Block)choice.getParent();
int pos=block.getContents().indexOf(choice);
if (pos != -1 && pos > 0) {
org.scribble.protocol.model.Activity act=
block.getContents().get(pos-1);
if (act instanceof Interaction &&
InteractionUtil.isRequest((Interaction)act) &&
InteractionUtil.getRequestLabel((Interaction)act) != null &&
InteractionUtil.getReplyToLabel(interaction).equals(
InteractionUtil.getRequestLabel((Interaction)act))) {
ret = (Interaction)act;
}
// Otherwise check if choice wrapped in parallel construct (possibly
// due to fork/join support)
} else if (block.getParent() instanceof Parallel &&
block.getParent().getParent() instanceof Block) {
Parallel par=(Parallel)block.getParent();
block = (org.scribble.protocol.model.Block)block.getParent().getParent();
pos = block.getContents().indexOf(par);
if (pos != -1 && pos > 0) {
org.scribble.protocol.model.Activity act=
block.getContents().get(pos-1);
if (act instanceof Interaction &&
InteractionUtil.isRequest((Interaction)act) &&
InteractionUtil.getRequestLabel((Interaction)act) != null &&
InteractionUtil.getReplyToLabel(interaction).equals(
InteractionUtil.getRequestLabel((Interaction)act))) {
ret = (Interaction)act;
}
}
}
}
}
}
return(ret);
}
public static boolean isResponseInFaultHandler(Interaction interaction) {
return(getRequestForResponseInFaultHandler(interaction) != null);
}
public static boolean isSyncNormalResponse(Interaction interaction) {
boolean ret=false;
if (InteractionUtil.isResponse(interaction) &&
interaction.getParent() instanceof Block) {
Block block=(Block)interaction.getParent();
int pos=block.getContents().indexOf(interaction);
if (pos > 0 && block.getContents().get(pos-1) instanceof Interaction) {
Interaction req=(Interaction)block.getContents().get(pos-1);
ret = isResponseForRequest(interaction, req);
}
}
return(ret);
}
public static boolean isResponseForRequest(Interaction resp,
Interaction req) {
boolean ret=false;
if (InteractionUtil.isRequest(req) &&
InteractionUtil.isResponse(resp) &&
InteractionUtil.getReplyToLabel(resp).equals(
InteractionUtil.getRequestLabel(req))) {
ret = true;
}
return(ret);
}
public static Interaction getFirstInteraction(Block path) {
Interaction ret=null;
// Get initial interactions
java.util.List<ModelObject> interactions=
org.scribble.protocol.util.InteractionUtil.getInitialInteractions(path);
if (interactions.size() != 1) {
// Either no interations, or more than one. Cannot
// handle either case.
if (logger.isLoggable(Level.FINEST)) {
logger.finest("Path has "+interactions.size()+" interactions");
}
} else if ((interactions.get(0) instanceof Interaction) == false) {
if (logger.isLoggable(Level.FINEST)) {
logger.finest("Path 'interaction' is not of type Interaction");
}
} else {
ret=(Interaction)interactions.get(0);
}
return(ret);
}
}