/******************************************************************************* * 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.bulkio.util.internal; import gov.redhawk.bulkio.util.AbstractUberBulkIOPort; import gov.redhawk.bulkio.util.BulkIOType; import gov.redhawk.bulkio.util.BulkIOUtilActivator; import gov.redhawk.bulkio.util.IPortFactory; import gov.redhawk.bulkio.util.PortReference; import gov.redhawk.sca.util.Debug; import gov.redhawk.sca.util.OrbSession; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import org.apache.commons.lang.RandomStringUtils; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.SafeRunner; 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 BULKIO.PrecisionUTCTime; import BULKIO.StreamSRI; import BULKIO.dataCharOperations; import BULKIO.dataDoubleOperations; import BULKIO.dataFloatOperations; import BULKIO.dataLongLongOperations; import BULKIO.dataLongOperations; import BULKIO.dataOctetOperations; import BULKIO.dataShortOperations; import BULKIO.dataUlongLongOperations; import BULKIO.dataUlongOperations; import BULKIO.dataUshortOperations; import BULKIO.updateSRIOperations; /** * @since 1.1 */ public class Connection extends AbstractUberBulkIOPort { private static final Debug DEBUG_PUSHPACKET = new Debug(BulkIOUtilActivator.PLUGIN_ID, Connection.class.getSimpleName()); private static final String FORMAT_STR = "MMdd'_'HHmmss"; private OrbSession orbSession = OrbSession.createSession(); private final String ior; private final String connectionId; private final boolean generatedID; private PortReference ref; private final List<updateSRIOperations> children = Collections.synchronizedList(new ArrayList<updateSRIOperations>()); private LinkedBlockingQueue<StreamSRIEvent> sriChanges = new LinkedBlockingQueue<Connection.StreamSRIEvent>(); private final Thread workerThread; private static class StreamSRIEvent { String streamID; StreamSRI oldSri; StreamSRI newSri; } private final Runnable handleStreamRunnable = new Runnable() { @Override public void run() { while (!Thread.currentThread().isInterrupted() || disposed) { final StreamSRIEvent event; try { event = sriChanges.take(); } catch (InterruptedException e) { break; } for (final Object child : getSafeChildren()) { SafeRunner.run(new ISafeRunnable() { @Override public void handleException(Throwable exception) { } @Override public void run() throws Exception { ((updateSRIOperations) child).pushSRI(event.newSri); } }); } } } }; private boolean disposed; private boolean warnedPushPacketError = false; public Connection(@NonNull String ior, @NonNull BulkIOType type, @Nullable String connectionId) { super(type); Assert.isNotNull(ior); Assert.isNotNull(type); this.ior = ior; if (connectionId == null || connectionId.isEmpty()) { this.connectionId = Connection.createConnectionID(); this.generatedID = true; } else { this.connectionId = connectionId; this.generatedID = false; } workerThread = new Thread(handleStreamRunnable, Connection.class.getName() + ":" + connectionId); workerThread.setDaemon(true); workerThread.start(); } public boolean isGeneratedID() { return generatedID; } public void connectPort() throws CoreException { if (disposed) { // Connection is disposed, do nothing return; } IPortFactory factory = BulkIOUtilActivator.getDefault().getPortFactory(); ref = factory.connect(connectionId, ior, getBulkIOType(), this); } // SRI has changed for specified streamID @Override protected void handleStreamSRIChanged(@NonNull String streamID, @Nullable StreamSRI oldSri, @NonNull final StreamSRI newSri) { if (disposed) { return; } StreamSRIEvent event = new StreamSRIEvent(); event.streamID = streamID; event.oldSri = oldSri; event.newSri = newSri; if (!sriChanges.offer(event)) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, handleStreamSRIChanged queue full, event dropped!", null); } } @NonNull public String getConnectionId() { return connectionId; } private static String createConnectionID() { SimpleDateFormat formater = new SimpleDateFormat(FORMAT_STR); String user = System.getProperty("user.name", "user"); String randomAlphanumeric = RandomStringUtils.random(3, true, true); // 62^3 = 238,328 String dateTime = formater.format(Calendar.getInstance().getTime()); return "IDE_" + user + "_" + randomAlphanumeric + "_" + dateTime; } public synchronized void dispose() { if (disposed) { return; } disposed = true; if (ref != null) { ref.dispose(); ref = null; } children.clear(); workerThread.interrupt(); sriChanges.clear(); orbSession.dispose(); } public void registerDataReceiver(@NonNull final updateSRIOperations receiver) { getBulkIOType().getPortType().cast(receiver); children.add(receiver); if (activeSRIs().length > 0) { Job job = new Job("pushSRI to new receiver") { @Override protected IStatus run(IProgressMonitor monitor) { StreamSRI[] currentSri = activeSRIs(); for (StreamSRI sri : currentSri) { receiver.pushSRI(sri); } return Status.OK_STATUS; } }; job.setSystem(true); // hide from progress monitor job.setUser(false); job.schedule(0); } } /** * * Disconnect an internal connection */ public void deregisterDataReceiver(@NonNull updateSRIOperations receiver) { children.remove(receiver); } /** * @return True if there are no internal connections */ public boolean isEmpty() { return children.isEmpty(); } @Override public void pushPacket(char[] data, PrecisionUTCTime time, boolean eos, String streamID) { if (!super.pushPacket(data.length, time, eos, streamID)) { return; } for (updateSRIOperations child : getSafeChildren()) { try { ((dataCharOperations) child).pushPacket(data, time, eos, streamID); } catch (Exception e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!warnedPushPacketError) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, got exception calling pushPacket(" + data.getClass().getCanonicalName() + "...) on " + child, e); } if (Connection.DEBUG_PUSHPACKET.enabled) { Connection.DEBUG_PUSHPACKET.message("Got exception calling pushPacket({0}...) on {1}. Exception={2}. IOR={3}", data.getClass().getCanonicalName(), child, e, ior); } } } } private updateSRIOperations[] getSafeChildren() { synchronized (children) { return children.toArray(new updateSRIOperations[children.size()]); } } @Override public void pushPacket(double[] data, PrecisionUTCTime time, boolean eos, String streamID) { if (!super.pushPacket(data.length, time, eos, streamID)) { return; } for (updateSRIOperations child : getSafeChildren()) { try { ((dataDoubleOperations) child).pushPacket(data, time, eos, streamID); } catch (Exception e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!warnedPushPacketError) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, got exception calling pushPacket(" + data.getClass().getCanonicalName() + "...) on " + child, e); } if (Connection.DEBUG_PUSHPACKET.enabled) { Connection.DEBUG_PUSHPACKET.message("Got exception calling pushPacket({0}...) on {1}. Exception={2}. IOR={3}", data.getClass().getCanonicalName(), child, e, ior); } } } } @Override public void pushPacket(float[] data, PrecisionUTCTime time, boolean eos, String streamID) { if (!super.pushPacket(data.length, time, eos, streamID)) { return; } for (updateSRIOperations child : getSafeChildren()) { try { ((dataFloatOperations) child).pushPacket(data, time, eos, streamID); } catch (Exception e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!warnedPushPacketError) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, got exception calling pushPacket(" + data.getClass().getCanonicalName() + "...) on " + child, e); } if (Connection.DEBUG_PUSHPACKET.enabled) { Connection.DEBUG_PUSHPACKET.message("Got exception calling pushPacket({0}...) on {1}. Exception={2}. IOR={3}", data.getClass().getCanonicalName(), child, e, ior); } } } } @Override public void pushPacket(byte[] data, PrecisionUTCTime time, boolean eos, String streamID) { if (!super.pushPacket(data.length, time, eos, streamID)) { return; } for (updateSRIOperations child : getSafeChildren()) { try { ((dataOctetOperations) child).pushPacket(data, time, eos, streamID); } catch (Exception e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!warnedPushPacketError) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, got exception calling pushPacket(" + data.getClass().getCanonicalName() + "...) on " + child, e); } if (Connection.DEBUG_PUSHPACKET.enabled) { Connection.DEBUG_PUSHPACKET.message("Got exception calling pushPacket({0}...) on {1}. Exception={2}. IOR={3}", data.getClass().getCanonicalName(), child, e, ior); } } } } @Override public void pushPacket(final short[] data, final PrecisionUTCTime time, final boolean eos, final String streamID) { if (!super.pushPacket(data.length, time, eos, streamID)) { return; } for (final updateSRIOperations child : getSafeChildren()) { try { if (getBulkIOType().isUnsigned()) { ((dataUshortOperations) child).pushPacket(data, time, eos, streamID); } else { ((dataShortOperations) child).pushPacket(data, time, eos, streamID); } } catch (Exception e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!warnedPushPacketError) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, got exception calling pushPacket(" + data.getClass().getCanonicalName() + "...) on " + child, e); } if (Connection.DEBUG_PUSHPACKET.enabled) { Connection.DEBUG_PUSHPACKET.message("Got exception calling pushPacket({0}...) on {1}. Exception={2}. IOR={3}", data.getClass().getCanonicalName(), child, e, ior); } } } } @Override public void pushPacket(int[] data, PrecisionUTCTime time, boolean eos, String streamID) { if (!super.pushPacket(data.length, time, eos, streamID)) { return; } for (updateSRIOperations child : getSafeChildren()) { try { if (getBulkIOType().isUnsigned()) { ((dataUlongOperations) child).pushPacket(data, time, eos, streamID); } else { ((dataLongOperations) child).pushPacket(data, time, eos, streamID); } } catch (Exception e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!warnedPushPacketError) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, got exception calling pushPacket(" + data.getClass().getCanonicalName() + "...) on " + child, e); } if (Connection.DEBUG_PUSHPACKET.enabled) { Connection.DEBUG_PUSHPACKET.message("Got exception calling pushPacket({0}...) on {1}. Exception={2}. IOR={3}", data.getClass().getCanonicalName(), child, e, ior); } } } } @Override public void pushPacket(long[] data, PrecisionUTCTime time, boolean eos, String streamID) { if (!super.pushPacket(data.length, time, eos, streamID)) { return; } for (updateSRIOperations child : getSafeChildren()) { try { if (getBulkIOType().isUnsigned()) { ((dataUlongLongOperations) child).pushPacket(data, time, eos, streamID); } else { ((dataLongLongOperations) child).pushPacket(data, time, eos, streamID); } } catch (Exception e) { // SUPPRESS CHECKSTYLE IllegalCatch if (!warnedPushPacketError) { warnedPushPacketError = true; log(IStatus.ERROR, "This will only be logged once per Port Connection, got exception calling pushPacket(" + data.getClass().getCanonicalName() + "...) on " + child, e); } if (Connection.DEBUG_PUSHPACKET.enabled) { Connection.DEBUG_PUSHPACKET.message("Got exception calling pushPacket({0}...) on {1}. Exception={2}. IOR={3}", data.getClass().getCanonicalName(), child, e, ior); } } } } private void log(int severity, String msg, Throwable t) { BulkIOUtilActivator.getDefault().getLog().log(new Status(severity, BulkIOUtilActivator.PLUGIN_ID, msg, t)); } @NonNull public String getIor() { return ior; } }