package org.opennaas.extensions.roadm.wonesys.actionsets.actions;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opennaas.core.resources.action.Action;
import org.opennaas.core.resources.action.ActionException;
import org.opennaas.core.resources.action.ActionResponse;
import org.opennaas.core.resources.action.ActionResponse.STATUS;
import org.opennaas.core.resources.command.CommandException;
import org.opennaas.core.resources.command.Response;
import org.opennaas.core.resources.protocol.IProtocolSession;
import org.opennaas.core.resources.protocol.IProtocolSessionManager;
import org.opennaas.core.resources.protocol.ProtocolException;
import org.opennaas.extensions.roadm.wonesys.actionsets.ActionConstants;
import org.opennaas.extensions.roadm.wonesys.commandsets.WonesysCommand;
import org.opennaas.extensions.roadm.wonesys.commandsets.commands.psroadm.SetChannel;
import org.opennaas.extensions.router.model.FCPort;
import org.opennaas.extensions.router.model.LogicalDevice;
import org.opennaas.extensions.router.model.LogicalPort;
import org.opennaas.extensions.router.model.NetworkPort;
import org.opennaas.extensions.router.model.opticalSwitch.DWDMChannel;
import org.opennaas.extensions.router.model.opticalSwitch.FiberChannel;
import org.opennaas.extensions.router.model.opticalSwitch.FiberConnection;
import org.opennaas.extensions.router.model.opticalSwitch.WDMChannelPlan;
import org.opennaas.extensions.router.model.opticalSwitch.dwdm.WDMFCPort;
import org.opennaas.extensions.router.model.opticalSwitch.dwdm.proteus.ProteusOpticalSwitch;
import org.opennaas.extensions.router.model.opticalSwitch.dwdm.proteus.cards.ProteusOpticalSwitchCard;
public class MakeConnectionAction extends Action {
static Log log = LogFactory.getLog(MakeConnectionAction.class);
public MakeConnectionAction() {
super();
initialize();
}
protected void initialize() {
this.setActionID(ActionConstants.MAKECONNECTION);
}
@Override
public ActionResponse execute(IProtocolSessionManager protocolSessionManager) throws ActionException {
try {
/* get protocol */
IProtocolSession protocol = protocolSessionManager.obtainSessionByProtocol("wonesys", false);
/* get params */
FiberConnection connection = loadParams((FiberConnection) params, (ProteusOpticalSwitch) modelToUpdate);
double srcLambda = connection.getSrcFiberChannel().getLambda();
double dstLambda = connection.getDstFiberChannel().getLambda();
// check there is no connection using given channel
// return error if there is
if (channelAlreadyInUse(connection, (ProteusOpticalSwitch) modelToUpdate))
return ActionResponse.errorResponse("Could not make connection. Desired channel is already in use.");
ActionResponse actionResponse;
if (srcLambda == dstLambda) {
actionResponse = makeConnectionWithSameLambda(connection, protocol);
} else {
actionResponse = makeConnectionWithDifferentLambda(connection, protocol);
}
if (actionResponse.getStatus().equals(STATUS.OK)) {
((ProteusOpticalSwitch) modelToUpdate).getFiberConnections().add(connection);
}
return actionResponse;
} catch (ProtocolException e) {
throw new ActionException(e);
}
}
private ActionResponse makeConnectionWithDifferentLambda(FiberConnection connection, IProtocolSession protocol) {
// TODO NOT SUPPORTED YET
return ActionResponse.errorResponse("Could not make connection. Connections with different lambdas are not supported.");
}
private ActionResponse makeConnectionWithSameLambda(FiberConnection connection, IProtocolSession protocol) throws ActionException {
ActionResponse response = ActionResponse.okResponse(getActionID());
FCPort srcPort = connection.getSrcPort();
FCPort dstPort = connection.getDstPort();
double lambda = connection.getSrcFiberChannel().getLambda();
/* find paths */
NetworkPort[] path = findInternPath(srcPort, dstPort);
// foreach hop in path concerning a single card
for (int i = 0; i < path.length - 1; i++) {
if (path[i].getModule().equals(path[i + 1].getModule())) {
Response partialResponse = makeConnectionInCard((FCPort) path[i], (FCPort) path[i + 1], lambda, protocol);
response.addResponse(partialResponse);
}
}
// foreach hop in path concerning different cards
for (int i = 0; i < path.length - 1; i++) {
if (!path[i].getModule().equals(path[i + 1].getModule())) {
// create passthrough between subports
FCPort subPort1 = getSubportWithLambda((FCPort) path[i], lambda);
FCPort subPort2 = getSubportWithLambda((FCPort) path[i + 1], lambda);
// subports have been created in previous "for" so they cannot be null
subPort1.addDeviceConnection(subPort2);
}
}
return response;
}
private Response makeConnectionInCard(FCPort srcPort, FCPort dstPort, double lambda, IProtocolSession protocol)
throws ActionException {
try {
ProteusOpticalSwitchCard card = (ProteusOpticalSwitchCard) srcPort.getModule();
int channelNum = ((WDMChannelPlan) card.getChannelPlan()).getChannelNumberFromLambda(lambda);
FiberChannel channel = ((WDMChannelPlan) card.getChannelPlan()).getChannel(channelNum);
Response response = Response.okResponse("none");
if (!card.isPassive()) {
int chassis = card.getChasis();
int slot = card.getModuleNumber();
int portNum = dstPort.getPortNumber();
// send command to the card
WonesysCommand command = new SetChannel(chassis, slot, channelNum, portNum);
command.initialize();
response = command.checkResponse(protocol.sendReceive(command.message()));
validateResponse(response);
}
// create subports and their connection in model
makeConnectionInCardUpdateModel(card, srcPort, dstPort, channel, channel);
// setChannelInModel(card, channelNum, portNum, (ProteusOpticalSwitch) modelToUpdate);
return response;
} catch (ProtocolException e) {
throw new ActionException(e);
} catch (CommandException e) {
throw new ActionException(e);
}
}
private void validateResponse(Response response) throws CommandException {
if (response.getStatus().equals(Response.Status.ERROR)) {
if (response.getErrors().size() > 0)
throw new CommandException(response.getErrors().get(0));
else
throw new CommandException("Command Failed");
}
}
/**
* Finds a route from srcPort to dstPort following connections inside the switch <br/>
* FIXME: NOTE: Right now it only tries paths with less than two hops of card.
*
* @param srcPort
* @param dstPort
* @return
* @throws ActionException
*/
private NetworkPort[] findInternPath(NetworkPort srcPort, NetworkPort dstPort) throws ActionException {
/* simple case */
if (dstPort.getModule().equals(srcPort.getModule())) {
ProteusOpticalSwitchCard srcCard = (ProteusOpticalSwitchCard) srcPort.getModule();
if (srcCard.isInternallyConnected(srcPort, dstPort)) {
return new NetworkPort[] { srcPort, dstPort };
} else {
throw new ActionException("Could not internally connect given ports");
}
/* we search a route */
} else {
for (NetworkPort p1 : srcPort.getModule().getModulePorts()) {
ProteusOpticalSwitchCard srcCard = (ProteusOpticalSwitchCard) srcPort.getModule();
/* srcPort is internally connected with the p1 */
if (srcCard.isInternallyConnected(srcPort, p1)) {
/* search ports connected to p1 */
for (LogicalDevice p2 : p1.getOutgoingDeviceConnections()) {
// TODO assure only local ports are checked
/* it is a correct port definition */
if (p2 instanceof NetworkPort) {
ProteusOpticalSwitchCard dstCard = (ProteusOpticalSwitchCard) ((NetworkPort) p2).getModule();
/* assure p2 is internally connected to dstPort */
if (dstCard.isInternallyConnected((NetworkPort) p2, dstPort)) {
return new NetworkPort[] { srcPort, p1, (NetworkPort) p2, dstPort };
}
}
}
}
}
throw new ActionException("Could not internally connect given ports");
}
}
@Override
public boolean checkParams(Object params) throws ActionException {
if (!(params instanceof FiberConnection)) {
return false;
}
return true;
}
private FiberConnection loadParams(FiberConnection connectionRequest, ProteusOpticalSwitch opticalSwitch) throws ActionException {
if (!checkParams(connectionRequest))
throw new ActionException("The Action " + getActionID() + " doesn't accept given params");
return loadFiberConnectionFromRequest(connectionRequest, opticalSwitch);
}
/**
* Uses given request to create a FiberConnection request with information from opticalSwitch model. Checks all params are correct.
*
* @param connectionRequest
* request to select which data must be loaded
* @param opticalSwitch
* model to get data from
* @return
* @throws ActionException
* if param checking fails
*/
public static FiberConnection loadFiberConnectionFromRequest(FiberConnection connectionRequest, ProteusOpticalSwitch opticalSwitch)
throws ActionException {
log.info("Loading request...");
// connection src
ProteusOpticalSwitchCard srcCard = opticalSwitch.getCard(connectionRequest.getSrcCard().getChasis(), connectionRequest.getSrcCard()
.getSlot());
if (srcCard == null)
throw new ActionException(
"There is no such card in model : Chassis: " + connectionRequest.getSrcCard().getChasis() + " Slot: " + connectionRequest
.getSrcCard().getSlot());
FCPort srcPort = (FCPort) srcCard.getPort(connectionRequest.getSrcPort().getPortNumber());
if (srcPort == null)
throw new ActionException(
"There is no such port in model: Chassis: " + connectionRequest.getSrcCard().getChasis() + " Slot: " + connectionRequest
.getSrcCard().getSlot() + " PortNumber : " + connectionRequest.getSrcPort().getPortNumber());
DWDMChannel srcFiberChannel = loadCompleteDWDMChannel((DWDMChannel) connectionRequest.getSrcFiberChannel(), srcCard);
// connection dst
ProteusOpticalSwitchCard dstCard = opticalSwitch.getCard(connectionRequest.getDstCard().getChasis(), connectionRequest.getDstCard()
.getSlot());
if (dstCard == null)
throw new ActionException(
"There is no such card in model : Chassis: " + connectionRequest.getDstCard().getChasis() + " Slot: " + connectionRequest
.getDstCard().getSlot());
FCPort dstPort = (FCPort) dstCard.getPort(connectionRequest.getDstPort().getPortNumber());
if (dstPort == null)
throw new ActionException(
"There is no such port in model: Chassis: " + connectionRequest.getDstCard().getChasis() + " Slot: " + connectionRequest
.getDstCard().getSlot() + " PortNumber : " + connectionRequest.getDstPort().getPortNumber());
DWDMChannel dstFiberChannel = loadCompleteDWDMChannel((DWDMChannel) connectionRequest.getDstFiberChannel(), dstCard);
FiberConnection connection = new FiberConnection();
connection.setSrcCard(srcCard);
connection.setDstCard(dstCard);
connection.setSrcPort(srcPort);
connection.setDstPort(dstPort);
connection.setSrcFiberChannel(srcFiberChannel);
connection.setDstFiberChannel(dstFiberChannel);
log.info("Connection request loaded. \n" +
"Connection source: " + connection.getSrcCard().getChasis() + "-" + connection.getSrcCard().getModuleNumber() + "-" + connection
.getSrcPort().getPortNumber() + "-" + connection.getSrcFiberChannel().getNumChannel() + "\n" +
"Connection destination: " + connection.getDstCard().getChasis() + "-" + connection.getDstCard().getModuleNumber() + "-" + connection
.getDstPort().getPortNumber() + "-" + connection.getDstFiberChannel().getNumChannel());
return connection;
}
/**
* Loads existent DWDMChannel from request. Tries to load it from request lambda. If lambda is not set, loads it from request channelNum.
*
* @param request
* @param card
* @return
* @throws ActionException
*/
private static DWDMChannel loadCompleteDWDMChannel(DWDMChannel request, ProteusOpticalSwitchCard card) throws ActionException {
int channelNum = request.getNumChannel();
if (request.getLambda() != 0.0) {
// load from lambda
// FIXME what if it's not a valid lambda????
channelNum = ((WDMChannelPlan) card.getChannelPlan()).getChannelNumberFromLambda(request.getLambda());
}
// check channelNum is a valid one
int[] allChannelsNum = ((WDMChannelPlan) card.getChannelPlan()).getAllChannelsNum();
boolean found = false;
int position = -1;
for (int i = 0; i < allChannelsNum.length; i++) {
if (allChannelsNum[i] == channelNum) {
position = i;
found = true;
break;
} else {
if (allChannelsNum[i] > channelNum) {
position = i;
// allChannelsNum is an ordered list (allChannelsNum[i] < allChannelsNum[i+1])
break;
}
}
}
if (!found) {
log.debug("Could not find specified channel. Looking for channel " + channelNum + ". Found " + allChannelsNum[position] + " and gap is " + ((WDMChannelPlan) card
.getChannelPlan()).getChannelGap());
throw new ActionException("Invalid connectionRequest: Could not find specified channel");
}
DWDMChannel completeChannel = (DWDMChannel) ((WDMChannelPlan) card.getChannelPlan()).getChannel(channelNum);
if (completeChannel == null) {
throw new ActionException("Invalid connectionRequest: Could not find specified channel");
}
return completeChannel;
}
/**********************
* CONTROLLER METHODS *
**********************/
public static void makeConnectionInCardUpdateModel(ProteusOpticalSwitchCard card, FCPort srcPort, FCPort dstPort, FiberChannel srcChannel,
FiberChannel dstChannel) {
card.addSwitchingRule(srcChannel, srcPort, dstChannel, dstPort);
}
public static WDMFCPort getSubportWithLambda(FCPort parentPort, double lambda) {
for (LogicalPort subport : parentPort.getPortsOnDevice()) {
if (subport instanceof WDMFCPort) {
if (((WDMFCPort) subport).getDWDMChannel().getLambda() == lambda) {
return (WDMFCPort) subport;
}
}
}
return null;
}
public static boolean channelAlreadyInUse(FiberConnection connection, ProteusOpticalSwitch model) {
boolean channelInUse = false;
for (FiberConnection existentConnection : model.getFiberConnections()) {
if (existentConnection.getSrcCard().getChasis() == connection.getSrcCard().getChasis() &&
existentConnection.getSrcCard().getSlot() == connection.getSrcCard().getSlot()) {
if (existentConnection.getSrcFiberChannel().getLambda() == connection.getSrcFiberChannel().getLambda()) {
channelInUse = true;
break;
}
}
if (existentConnection.getDstCard().getChasis() == connection.getDstCard().getChasis() &&
existentConnection.getDstCard().getSlot() == connection.getDstCard().getSlot()) {
if (existentConnection.getDstFiberChannel().getLambda() == connection.getDstFiberChannel().getLambda()) {
channelInUse = true;
break;
}
}
}
return channelInUse;
}
}