/*
* MicroJIAC - A Lightweight Agent Framework
* This file is part of MicroJIAC Interaction.
*
* Copyright (c) 2007-2012 DAI-Labor, Technische Universität Berlin
*
* This library includes software developed at DAI-Labor, Technische
* Universität Berlin (http://www.dai-labor.de)
*
* This library is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY 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
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
package de.jiac.micro.ips;
import com.github.libxjava.util.BasicArrayList;
import com.github.libxjava.util.BasicEnumeration;
import com.github.libxjava.util.BasicHashMap;
import de.jiac.micro.core.io.IMessage;
import de.jiac.micro.ips.AbstractProtocolPart.Interaction;
import de.jiac.micro.ips.AbstractProtocolPart.ProtocolState;
/**
*
* @author Marcel Patzlaff
*/
/*package*/ final class InteractionManager implements IProtocolRegistry {
private final BasicHashMap _protocolParticipants;
private final BasicArrayList _currentInteractions;
/*package*/ InteractionManager() {
_protocolParticipants= new BasicHashMap();
_currentInteractions= new BasicArrayList();
}
/*package*/ void addInteraction(Interaction ctx) {
synchronized (_currentInteractions) {
_currentInteractions.add(ctx);
}
}
/*package*/ void handleMessage(IMessage message) {
String id= message.getHeader(IMessageConstants.HEADER_CONVERSATION_ID);
if(id != null) {
Interaction ctx;
synchronized (_currentInteractions) {
ctx= findContext(id);
if(ctx == null) {
String protocol= message.getHeader(IMessageConstants.HEADER_PROTOCOL);
if(protocol != null) {
ctx= newParticipantInteraction(protocol, id);
}
}
}
// TODO: should we do something if id == null || ctx == null ?
if(ctx != null) {
processInteraction(ctx, message);
}
}
}
public void registerProtocolPart(AbstractProtocolPart protocolPart) {
if(protocolPart == null) {
throw new IllegalArgumentException("protocol part must not be null");
}
if(protocolPart instanceof AbstractProtocolParticipant) {
synchronized (_protocolParticipants) {
String name= protocolPart.protocolName;
AbstractProtocolParticipant old= (AbstractProtocolParticipant) _protocolParticipants.put(name, protocolPart);
if(old != null && old != protocolPart) {
_protocolParticipants.put(name, old);
throw new IllegalArgumentException("protocol participant for '" + name + "' already specified");
}
}
}
protocolPart.manager= this;
}
public void unregisterProtocolPart(AbstractProtocolPart protocolPart) {
if(protocolPart == null) {
throw new IllegalArgumentException("protocol part must not be null");
}
synchronized (_protocolParticipants) {
_protocolParticipants.remove(protocolPart.protocolName);
}
synchronized (_currentInteractions) {
for(BasicEnumeration e= _currentInteractions.enumeration(); e.hasMoreElements();) {
Interaction ctx= (Interaction) e.nextElement();
if(ctx.protocolPart == protocolPart) {
// TODO: abort interaction
e.remove();
}
}
}
protocolPart.manager= null;
}
/**
* Caller must hold lock on interactions
*/
private Interaction findContext(String id) {
for(int i= _currentInteractions.size() - 1; i >= 0; i--) {
Interaction ia= (Interaction) _currentInteractions.get(i);
if(ia.id.equals(id)) {
return ia;
}
}
return null;
}
private Interaction newParticipantInteraction(String protocol, String id) {
synchronized (_protocolParticipants) {
AbstractProtocolParticipant participant= (AbstractProtocolParticipant) _protocolParticipants.get(protocol);
if(participant != null) {
// TODO: timeouts
return new Interaction(id, participant, -1, null);
}
}
return null;
}
private void processInteraction(Interaction ia, IMessage message) {
String performative= message.getHeader(IMessageConstants.HEADER_PERFORMATIVE);
if(performative != null) {
// enable reference-based equality checks
performative= performative.intern();
message.setHeader(IMessageConstants.HEADER_PERFORMATIVE, performative);
ProtocolState nextState= ia.state.handleStateChange(ia, performative, message, ia.protocolPart);
if(nextState != null) {
ia.state= nextState;
} else {
// interaction is finished
synchronized (_currentInteractions) {
_currentInteractions.remove(ia);
}
}
} else {
// TODO: what to do here?
}
}
}