package org.opennaas.extensions.roadm.wonesys.protocols; import static org.opennaas.extensions.roadm.wonesys.protocols.WonesysProtocolBundleActivator.getEventManagerService; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.opennaas.core.events.EventFilter; import org.opennaas.core.events.IEventManager; import org.opennaas.core.resources.ActivatorException; import org.opennaas.core.resources.protocol.IProtocolMessageFilter; import org.opennaas.core.resources.protocol.IProtocolSession; import org.opennaas.core.resources.protocol.IProtocolSessionListener; import org.opennaas.core.resources.protocol.ProtocolException; import org.opennaas.core.resources.protocol.ProtocolSessionContext; import org.opennaas.extensions.roadm.wonesys.protocols.listeners.CommandResponseListener; import org.opennaas.extensions.roadm.wonesys.protocols.listeners.RawSocketAlarmListener; import org.opennaas.extensions.roadm.wonesys.transports.ITransport; import org.opennaas.extensions.roadm.wonesys.transports.ITransportListener; import org.opennaas.extensions.roadm.wonesys.transports.WonesysTransport; import org.opennaas.extensions.roadm.wonesys.transports.mock.MockTransport; import org.opennaas.extensions.roadm.wonesys.transports.rawsocket.RawSocketTransport; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; public class WonesysProtocolSession implements IProtocolSession, ITransportListener { // public static final String PROTOCOL_URI = "URI"; public static final long PROTOCOL_DEFAULT_TIMEOUT = 30000; // millis public static final String CMD_RCVD_EVENT_TOPIC = "net/i2cat/luminis/protocol/wonesys/session/COMMAND_RECEIVED"; public static final String ALARM_RCVD_EVENT_TOPIC = "net/i2cat/luminis/protocol/wonesys/session/alarms/RECEIVED"; public static final String COMMAND_PROPERTY_NAME = "command"; public static final String SESSION_ID_PROPERTY = "sessionId"; /** The logger **/ public static Log log = LogFactory.getLog(WonesysProtocolSession.class); /** * Contains information about the protocol capability configuration: transport, host, port, ... **/ private ProtocolSessionContext protocolSessionContext = null; private String sessionID = null; private Status status = null; private ITransport wonesysTransport = null; private Map<String, IProtocolSessionListener> protocolListeners = null; private Map<String, IProtocolMessageFilter> protocolMessageFilters = null; private final Object mutex = new Object(); private Object response; private long timeout; RawSocketAlarmListener rawSocketAlarmListener; public WonesysProtocolSession(ProtocolSessionContext protocolSessionContext, String sessionID) throws ProtocolException { this.protocolListeners = new HashMap<String, IProtocolSessionListener>(); this.protocolMessageFilters = new HashMap<String, IProtocolMessageFilter>(); this.protocolSessionContext = protocolSessionContext; this.sessionID = sessionID; this.status = Status.DISCONNECTED_BY_USER; log.debug("Initializing transport"); /* is mock or not */ if (WonesysProtocolSessionContextUtils.isMock(protocolSessionContext)) { log.info("Using MockTransport connected to a Proteus ROADM simulator"); wonesysTransport = new MockTransport(); } else { wonesysTransport = new WonesysTransport(protocolSessionContext); } String timeoutParam = (String) protocolSessionContext.getSessionParameters().get("protocol.responsetimeout"); if (timeoutParam != null) timeout = Long.parseLong(timeoutParam); else timeout = PROTOCOL_DEFAULT_TIMEOUT; // register session as a transport listener // this session will receive all events from its wonesysTransport log.info("Registering session as a transport listener"); registerToTransport(this, RawSocketTransport.ALL_EVENTS_TOPIC); log.info("Registering alarm listener"); rawSocketAlarmListener = new RawSocketAlarmListener(sessionID); registerToTransport(rawSocketAlarmListener, RawSocketTransport.MSG_RCVD_EVENT_TOPIC); } @Override synchronized public void asyncSend(Object requestMessage) throws ProtocolException { // Send a message to the device, and don't wait for the response throw new ProtocolException("Unsupported Operation"); } /** * Send a message to the device, and wait for the response. */ @Override synchronized public Object sendReceive(Object requestMessage) throws ProtocolException { try { String message = (String) requestMessage; CommandResponseListener responseListener = new CommandResponseListener(message); int serviceId = registerToTransport(responseListener, RawSocketTransport.MSG_RCVD_EVENT_TOPIC); try { wonesysTransport.sendMsg(message); log.info("Message sent"); return waitResponse(responseListener); } finally { getEventManagerService().unregisterHandler(serviceId); } } catch (ProtocolException e) { throw e; } catch (Exception e) { throw new ProtocolException("TransportException: ", e); } } private int registerToTransport(EventHandler listener, String topic) throws ProtocolException { try { Properties properties = new Properties(); properties.setProperty(RawSocketTransport.TRANSPORT_ID_PROPERTY_NAME, wonesysTransport.getTransportID()); EventFilter filter = new EventFilter(new String[] { topic }, properties); IEventManager eventManager = getEventManagerService(); return eventManager.registerEventHandler(listener, filter); } catch (ActivatorException e) { throw new ProtocolException("Failed to register to transport events.", e); } } private String waitResponse(CommandResponseListener responseListener) throws ProtocolException { try { long start = System.currentTimeMillis(); log.debug("Waiting for a response within " + timeout + "ms @ " + start); String response = responseListener.getResponse(timeout); log.debug("Finished waiting. Waited during " + (System.currentTimeMillis() - start) + "ms"); if (response == null) { throw new ProtocolException("Timeout waiting for a command response"); } return response; } catch (InterruptedException e) { throw new ProtocolException("Error while receiving message response: " + e.getMessage(), e); } } @Override public void connect() throws ProtocolException { if (status.equals(Status.CONNECTED)) { throw new ProtocolException("Cannot connect because the session is already connected"); } log.info("Connecting to the device"); try { wonesysTransport.connect(); changeSessionStatus(Status.CONNECTED); } catch (Exception e) { ProtocolException pe = new ProtocolException("TransportException: " + e.getMessage()); // te.initCause(e); throw pe; } } @Override public void disconnect() throws ProtocolException { if (!status.equals(Status.CONNECTED)) { throw new ProtocolException("Cannot disconnect because the session is not connected. Current state: " + status); } try { wonesysTransport.disconnect(); changeSessionStatus(Status.DISCONNECTED_BY_USER); } catch (Exception e) { throw new ProtocolException("TransportException: " + e.getMessage()); } log.info("Protocol session stopped"); } @Override public ProtocolSessionContext getSessionContext() { return protocolSessionContext; } @Override public void setSessionContext(ProtocolSessionContext context) { // FIXME should create a new Transport ???? this.protocolSessionContext = context; } @Override public String getSessionId() { return sessionID; } @Override public void setSessionId(String sessionId) { this.sessionID = sessionId; } @Override public Status getStatus() { return status; } // FIXME allow sessionListeners @Override public void registerProtocolSessionListener(IProtocolSessionListener protocolSessionListener, IProtocolMessageFilter protocolMessageFilter, String idListener) { protocolMessageFilters.put(idListener, protocolMessageFilter); protocolListeners.put(idListener, protocolSessionListener); } @Override public void unregisterProtocolSessionListener(IProtocolSessionListener protocolSessionListener, String idListener) { protocolMessageFilters.remove(idListener); protocolListeners.remove(idListener); } public void changeSessionStatus(Status status) { this.status = status; // notifyListeners(); } public ITransport getWonesysTransport() { return wonesysTransport; } @Override /** * This method manages events. This method is responsible to manage two type of alarms, ERROR_EVENT and CMD_RCVD. Other type of alarms are managed for * RAWSocketAlarmListener */ public void handleEvent(Event event) { log.debug("Event received"); if (event.getTopic().equals(RawSocketTransport.ERROR_EVENT_TOPIC)) { Exception error = (Exception) event.getProperty(RawSocketTransport.ERROR_PROPERTY_NAME); if (error != null) { errorHappened(error); } } else if (event.getTopic().equals(CMD_RCVD_EVENT_TOPIC)) { String response = (String) event.getProperty(COMMAND_PROPERTY_NAME); if (response != null) { commandReceived(response); } } } public void commandReceived(Object message) { log.info("Message received by session"); synchronized (mutex) { response = message; mutex.notify(); } } public void errorHappened(Exception e) { log.error("Error in session " + sessionID, e); log.info("Disconnecting session " + sessionID); // disconnect session try { disconnect(); } catch (ProtocolException e1) { log.error("Failed to disconnect session. This error may create a memory leak due to unclosed sockets", e1); } changeSessionStatus(Status.CONNECTION_LOST); // FIXME notify listeners } }