/**
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* All rights reserved. This program and the accompanying materials are made available under
* the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html.
*
*/
package gov.redhawk.ui.port.nxmblocks;
import gov.redhawk.bulkio.util.AbstractBulkIOSDDSPort;
import gov.redhawk.bulkio.util.AbstractBulkIOSDDSPort.SddsStreamSession;
import gov.redhawk.model.sca.ScaUsesPort;
import gov.redhawk.sca.util.Debug;
import gov.redhawk.sca.util.ORBUtil;
import gov.redhawk.sca.util.OrbSession;
import gov.redhawk.ui.port.nxmplot.AbstractNxmPlotWidget;
import gov.redhawk.ui.port.nxmplot.PlotActivator;
import java.nio.ByteOrder;
import java.text.MessageFormat;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.omg.CORBA.SystemException;
import org.omg.PortableServer.Servant;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.PortableServer.POAPackage.WrongPolicy;
import BULKIO.SDDSDataDigraph;
import BULKIO.SDDSStreamDefinition;
import BULKIO.StreamSRI;
import BULKIO.dataSDDSPackage.AttachError;
import BULKIO.dataSDDSPackage.DetachError;
import BULKIO.dataSDDSPackage.StreamInputError;
import CF.PortPackage.InvalidPort;
import CF.PortPackage.OccupiedPort;
/**
* @noreference This class is provisional/beta and is subject to API changes
* @since 4.4
*/
public class BulkIOSddsNxmBlock extends SddsNxmBlock {
private static final Debug TRACE_LOG = new Debug(PlotActivator.PLUGIN_ID, BulkIOSddsNxmBlock.class.getSimpleName());
private static OrbSession orbSession = OrbSession.createSession();
private final ConcurrentHashMap<String, SddsStreamSession> streamIDToSSSMap = new ConcurrentHashMap<String, SddsStreamSession>();
private ScaUsesPort scaUsesPort;
private org.omg.CORBA.Object corbaObjRef;
private String connectionId;
private SddsPort sddsPort;
class SddsPort extends AbstractBulkIOSDDSPort {
@Override
protected void handleAttach(SddsStreamSession sss) throws AttachError, StreamInputError {
final String streamID;
final String id = sss.getSddsStreamDef().id; // SDDSStreamDefinition.id matches StreamSRI.streamID
if (id != null) {
streamID = id;
} else {
streamID = sss.getAttachId(); // fall-back to attachment ID
BulkIOSddsNxmBlock.TRACE_LOG.message("WARN: no SDDSStreamDefinition.id specified! using attachID: " + streamID);
}
if (BulkIOSddsNxmBlock.TRACE_LOG.enabled) {
BulkIOSddsNxmBlock.TRACE_LOG.message("handleAttach: SDDSStreamDefinition.id = [{0}] attachID = [{1}] SddsStreamSession = {2}", id, sss.getAttachId(), sss);
}
streamIDToSSSMap.put(streamID, sss);
StreamSRI streamSRI = getSri(streamID);
if (streamSRI == null) {
streamSRI = new StreamSRI();
streamSRI.streamID = streamID;
putSri(streamID, streamSRI);
BulkIOSddsNxmBlock.TRACE_LOG.message("handleAttach: creating new StreamSRI for map: {0}", streamSRI);
} else {
BulkIOSddsNxmBlock.TRACE_LOG.message("handleAttach: using StreamSRI found in map: {0}", streamSRI);
}
int sr = sss.getSddsStreamDef().sampleRate;
if (sr > 0) {
streamSRI.xdelta = 1.0 / sr;
}
final StreamSRI sri = streamSRI;
// run in background so we don't further block our caller
Job job = new Job("launching BulkIO SDDS stream: " + streamID) {
@Override
protected IStatus run(IProgressMonitor monitor) {
launch(streamID, sri);
return Status.OK_STATUS;
}
};
job.setUser(false);
job.schedule(0);
}
@Override
protected void handleDetach(SddsStreamSession sss) throws DetachError, StreamInputError {
BulkIOSddsNxmBlock.TRACE_LOG.enteringMethod(sss);
String streamID = sss.getSddsStreamDef().id;
if (streamID == null) {
streamID = sss.getAttachId(); // fall-back to attachment ID
}
shutdown(streamID);
streamIDToSSSMap.remove(streamID);
BulkIOSddsNxmBlock.TRACE_LOG.exitingMethod();
}
@Override
protected void handleStreamSRIChanged(@NonNull String streamID, @Nullable StreamSRI oldSri, @NonNull StreamSRI newSri) {
BulkIOSddsNxmBlock.TRACE_LOG.enteringMethod(streamID, oldSri, newSri);
// TODO: what should we do here?
}
} // inner class SddsPort
public BulkIOSddsNxmBlock(@NonNull AbstractNxmPlotWidget plotWidget, @NonNull ScaUsesPort scaUsesPort) {
this(plotWidget, scaUsesPort, null);
}
public BulkIOSddsNxmBlock(@NonNull AbstractNxmPlotWidget plotWidget, @NonNull ScaUsesPort scaUsesPort, @Nullable SddsNxmBlockSettings settings) {
super(plotWidget, settings);
this.scaUsesPort = scaUsesPort;
}
@Override
@NonNull
protected String formCmdLine(@NonNull AbstractNxmPlotWidget plotWidget, String streamID) {
final String outputName = AbstractNxmPlotWidget.createUniqueName(true);
putOutputNameMapping(0, streamID, outputName); // save output name mapping
SddsStreamSession sss = streamIDToSSSMap.get(streamID);
SDDSStreamDefinition sddsStreamDef = sss.getSddsStreamDef();
final StringBuilder switches = new StringBuilder("");
ByteOrder byteOrder = getDataByteOrder();
if (byteOrder != null) {
switches.append("/BYTEORDER=").append(byteOrder);
}
final int pipeSize = getPipeSize(); // in bytes
if (pipeSize > 0) {
switches.append("/PS=").append(pipeSize);
}
// use values from SDDSStreamDefinition as each attach might be from different source mcastAddr, port, vlan, format, etc.
String outputFormat = BulkIOSddsNxmBlock.sddsDigraph2MidasFormatType(sddsStreamDef.dataFormat);
switches.append("/FC=").append(outputFormat);
switches.append("/MGRP=").append(sddsStreamDef.multicastAddress);
switches.append("/PORT=").append(sddsStreamDef.port);
switches.append("/VLAN=").append(sddsStreamDef.vlan);
String pattern = "SOURCENIC{0}/BG OUT={1}";
String cmdLine = MessageFormat.format(pattern, switches, outputName);
return cmdLine;
}
private void connect() throws CoreException {
sddsPort = new SddsPort();
Servant sddsPortServant = sddsPort.toServant(BulkIOSddsNxmBlock.orbSession.getPOA());
try {
corbaObjRef = BulkIOSddsNxmBlock.orbSession.getPOA().servant_to_reference(sddsPortServant);
connectionId = BulkIOSddsNxmBlock.createConnectionID();
scaUsesPort.connectPort(corbaObjRef, connectionId);
} catch (ServantNotActive e) {
throw new CoreException(new Status(IStatus.ERROR, PlotActivator.PLUGIN_ID, "Failed to register connection (1).", e));
} catch (WrongPolicy e) {
throw new CoreException(new Status(IStatus.ERROR, PlotActivator.PLUGIN_ID, "Failed to register connection (2).", e));
} catch (InvalidPort e) {
throw new CoreException(new Status(IStatus.ERROR, PlotActivator.PLUGIN_ID, "Failed to register connection (3).", e));
} catch (OccupiedPort e) {
throw new CoreException(new Status(IStatus.ERROR, PlotActivator.PLUGIN_ID, "Failed to register connection (4).", e));
} catch (SystemException e) {
throw new CoreException(new Status(IStatus.ERROR, PlotActivator.PLUGIN_ID, "Failed to register connection (5).", e));
}
}
@Override
public void start() throws CoreException {
BulkIOSddsNxmBlock.TRACE_LOG.enteringMethod();
if (sddsPort != null) {
throw new IllegalStateException("This block has already started! " + this);
}
connect();
BulkIOSddsNxmBlock.TRACE_LOG.exitingMethod();
}
@Override
public void stop() {
BulkIOSddsNxmBlock.TRACE_LOG.enteringMethod(isStopped());
if (isStopped()) {
return; // It is valid to attempt to stop a block more than once, so just return
}
super.stop();
try {
ScaUsesPort scaPort;
synchronized (this) {
scaPort = scaUsesPort;
if (scaUsesPort != null) {
scaUsesPort = null;
}
}
if (!scaPort.isDisposed()) {
scaPort.disconnectPort(connectionId); // disconnect from BULKIO dataSddsOut Port
}
} catch (InvalidPort e) {
// PASS
} catch (SystemException e) {
// PASS
}
if (corbaObjRef != null) {
ORBUtil.release(corbaObjRef); // release corba object reference
corbaObjRef = null;
}
if (sddsPort != null) {
sddsPort = null;
}
BulkIOSddsNxmBlock.TRACE_LOG.exitingMethod();
}
private static String sddsDigraph2MidasFormatType(SDDSDataDigraph sddsDataFormat) {
String format = null;
if (SDDSDataDigraph.SDDS_SF.equals(sddsDataFormat)) {
format = "SF";
} else if (SDDSDataDigraph.SDDS_SI.equals(sddsDataFormat)) {
format = "SI";
} else if (SDDSDataDigraph.SDDS_SB.equals(sddsDataFormat)) {
format = "SB";
} else if (SDDSDataDigraph.SDDS_SL.equals(sddsDataFormat)) {
format = "SL";
} else if (SDDSDataDigraph.SDDS_SX.equals(sddsDataFormat)) {
format = "SX";
} else if (SDDSDataDigraph.SDDS_SD.equals(sddsDataFormat)) {
format = "SD";
} else if (SDDSDataDigraph.SDDS_CB.equals(sddsDataFormat)) {
format = "CB";
} else if (SDDSDataDigraph.SDDS_CI.equals(sddsDataFormat)) {
format = "CI";
} else if (SDDSDataDigraph.SDDS_CL.equals(sddsDataFormat)) {
format = "CL";
} else if (SDDSDataDigraph.SDDS_CX.equals(sddsDataFormat)) {
format = "CX";
} else if (SDDSDataDigraph.SDDS_CF.equals(sddsDataFormat)) {
format = "CF";
} else if (SDDSDataDigraph.SDDS_CD.equals(sddsDataFormat)) {
format = "CD";
} else {
format = ""; // unknown ?TODO: throw exception? or return empty string?
}
return format;
}
private static String createConnectionID() {
return System.getProperty("user.name", "user") + "_" + System.currentTimeMillis();
}
}