History

Added GridSolutionsFramework.sln to source control.

StephenCWills committed 14 years ago

Commit c5f7ca6No parent (first commit)915 files · +335125 −-73Browse files

Showing the changes to Source/Libraries/TSFJavaLibrary/src/org (33 of 915 files). Show all

Unified · Split

33 files
  1. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/Measurement.java +287 −0
  2. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/MeasurementKey.java +143 −0
  3. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/AdvancedSubscribe.java +453 −0
  4. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/SampleSubscriberConnectorListener.java +90 −0
  5. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/SampleSubscriberListener.java +182 −0
  6. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/SimpleSubscribe.java +111 −0
  7. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/CompactMeasurementParser.java +288 −0
  8. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/DataSubscriber.java +1212 −0
  9. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/GatewayMeasurementParser.java +56 −0
  10. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/SignalIndexCache.java +128 −0
  11. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/SubscriberConnector.java +356 −0
  12. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/SubscriptionInfo.java +563 −0
  13. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/CompressionMode.java +40 −0
  14. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/DataPacketFlags.java +52 −0
  15. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/OperationalEncoding.java +54 −0
  16. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/OperationalModes.java +78 −0
  17. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/ServerCommand.java +82 −0
  18. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/ServerResponse.java +86 −0
  19. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/MeasurementEvent.java +66 −0
  20. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/MessageEvent.java +86 −0
  21. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/MetadataEvent.java +91 −0
  22. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/StartTimeEvent.java +59 −0
  23. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberAdapter.java +69 −0
  24. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberConnectorAdapter.java +44 −0
  25. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberConnectorListener.java +47 −0
  26. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberEvent.java +60 −0
  27. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberListener.java +90 −0
  28. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/ArrayExtensions.java +195 −0
  29. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/InputStreamExtensions.java +73 −0
  30. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/Masks.java +92 −0
  31. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/NumberExtensions.java +132 −0
  32. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/StringExtensions.java +88 −0
  33. Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/TimeExtensions.java +65 −0
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/Measurement.java+287−0
@@ -0,0 +1,287 @@
1+//******************************************************************************************************
2+// Measurement.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/12/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf;
25+
26+import java.util.UUID;
27+
28+/**
29+ * Fundamental data type used by the Time Series Framework.
30+ */
31+public class Measurement
32+{
33+ private int m_id;
34+ private String m_source;
35+ private UUID m_signalId;
36+ private String m_tag;
37+ private double m_value;
38+ private double m_adder;
39+ private double m_multiplier;
40+ private long m_timestamp;
41+ private int m_flags;
42+
43+ /**
44+ * Creates a new instance.
45+ */
46+ public Measurement()
47+ {
48+ m_multiplier = 1;
49+ }
50+
51+ /**
52+ * Creates a new instance that is a copy of another instance.
53+ *
54+ * @param copy the measurement to be copied
55+ */
56+ public Measurement(Measurement copy)
57+ {
58+ m_id = copy.m_id;
59+ m_source = copy.m_source;
60+ m_signalId = copy.m_signalId;
61+ m_tag = copy.m_tag;
62+ m_value = copy.m_value;
63+ m_adder = copy.m_adder;
64+ m_multiplier = copy.m_multiplier;
65+ m_timestamp = copy.m_timestamp;
66+ m_flags = copy.m_flags;
67+ }
68+
69+ /**
70+ * Gets the point ID of the measurement, which is
71+ * the suffix of the human-readable measurement key.
72+ *
73+ * @return the point ID of the measurement
74+ * @see #setId(int)
75+ */
76+ public int getId()
77+ {
78+ return m_id;
79+ }
80+
81+ /**
82+ * Sets the point ID of the measurement.
83+ *
84+ * @param id the new value of the point ID
85+ * @see #getId()
86+ */
87+ public void setId(int id)
88+ {
89+ m_id = id;
90+ }
91+
92+ /**
93+ * Gets the source of the measurement, which is
94+ * the prefix of the human-readable measurement key.
95+ *
96+ * @return the source of the measurement
97+ * @see #setSource(String)
98+ */
99+ public String getSource()
100+ {
101+ return m_source;
102+ }
103+
104+ /**
105+ * Sets the source of the measurement.
106+ *
107+ * @param source the new value of the source
108+ * @see #getSource()
109+ */
110+ public void setSource(String source)
111+ {
112+ m_source = source;
113+ }
114+
115+ /**
116+ * Gets the measurement's globally unique identifier.
117+ *
118+ * @return the measurement's globally unique identifier
119+ * @see #setSignalId(UUID)
120+ */
121+ public UUID getSignalId()
122+ {
123+ return m_signalId;
124+ }
125+
126+ /**
127+ * Sets the measurement's globally unique identifier.
128+ *
129+ * @param signalID the new value of the measurement's globally unique identifier
130+ * @see #getSignalId()
131+ */
132+ public void setSignalId(UUID signalID)
133+ {
134+ m_signalId = signalID;
135+ }
136+
137+ /**
138+ * Gets the human-readable tag name that describes the measurement.
139+ *
140+ * @return the human readable tag name
141+ * @see #setTag(String)
142+ */
143+ public String getTag()
144+ {
145+ return m_tag;
146+ }
147+
148+ /**
149+ * Sets the human-readable tag name.
150+ *
151+ * @param tag the new value of the human-readable tag name
152+ * @see #getTag()
153+ */
154+ public void setTag(String tag)
155+ {
156+ m_tag = tag;
157+ }
158+
159+ /**
160+ * Gets the value of the measurement.
161+ *
162+ * @return the value of the measurement
163+ * @see #setValue(double)
164+ * @see #getAdjustedValue()
165+ */
166+ public double getValue()
167+ {
168+ return m_value;
169+ }
170+
171+ /**
172+ * Sets the value of the measurement.
173+ *
174+ * @param value the new value
175+ * @see #getValue()
176+ * @see #getAdjustedValue()
177+ */
178+ public void setValue(double value)
179+ {
180+ m_value = value;
181+ }
182+
183+ /**
184+ * Gets the additive value modifier.
185+ *
186+ * @return the additive value modifier
187+ * @see #setAdder(double)
188+ * @see #getAdjustedValue()
189+ */
190+ public double getAdder()
191+ {
192+ return m_adder;
193+ }
194+
195+ /**
196+ * Sets the additive value modifier.
197+ *
198+ * @param adder the new additive value modifier
199+ * @see #getAdder()
200+ * @see #getAdjustedValue()
201+ */
202+ public void setAdder(double adder)
203+ {
204+ m_adder = adder;
205+ }
206+
207+ /**
208+ * Gets the multiplicative value modifier.
209+ *
210+ * @return the multiplicative value modifier
211+ * @see #setMultiplier(double)
212+ * @see #getAdjustedValue()
213+ */
214+ public double getMultiplier()
215+ {
216+ return m_multiplier;
217+ }
218+
219+ /**
220+ * Sets the multiplicative value modifier.
221+ *
222+ * @param multiplier the new multiplicative value modifier
223+ * @see #getMultiplier()
224+ * @see #getAdjustedValue()
225+ */
226+ public void setMultiplier(double multiplier)
227+ {
228+ m_multiplier = multiplier;
229+ }
230+
231+ /**
232+ * Gets the timestamp of the measurement in ticks.
233+ *
234+ * @return the timestamp of the measurement
235+ */
236+ public long getTimestamp()
237+ {
238+ return m_timestamp;
239+ }
240+
241+ /**
242+ * Sets the timestamp of the measurement.
243+ *
244+ * @param timestamp the new timestamp
245+ */
246+ public void setTimestamp(long timestamp)
247+ {
248+ m_timestamp = timestamp;
249+ }
250+
251+ /**
252+ * Gets the flags which define the measurement's state.
253+ *
254+ * @return the measurement's state flags
255+ */
256+ public int getFlags()
257+ {
258+ return m_flags;
259+ }
260+
261+ /**
262+ * Sets the flags which define the measurement's state.
263+ *
264+ * @param flags the new state flags
265+ */
266+ public void setFlags(int flags)
267+ {
268+ m_flags = flags;
269+ }
270+
271+ /**
272+ * Gets the adjusted value of the measurement, which is the value
273+ * of the measurement after applying the multiplicative and
274+ * additive value modifiers. Mathematically defined as:
275+ * <p>
276+ * {@code AdjustedValue = (Multiplier * Value) + Adder}
277+ *
278+ * @return the value of the measurement after applying modifiers
279+ * @see #getValue()
280+ * @see #getAdder()
281+ * @see #getMultiplier()
282+ */
283+ public double getAdjustedValue()
284+ {
285+ return m_value * m_multiplier + m_adder;
286+ }
287+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/MeasurementKey.java+143−0
@@ -0,0 +1,143 @@
1+//******************************************************************************************************
2+// MeasurementKey.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/12/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf;
25+
26+import java.util.UUID;
27+
28+import org.gpa.tsf.util.StringExtensions;
29+
30+/**
31+ * Represents a grouping of a measurement's globally unique identifier
32+ * and the alternate human-readable identifier {@code SOURCE:ID}.
33+ * @see Measurement
34+ */
35+public class MeasurementKey
36+{
37+ private UUID m_signalId;
38+ private String m_source;
39+ private int m_id;
40+
41+ /**
42+ * Constructs a measurement key by grouping the given parameters.
43+ *
44+ * @param signalId the measurement's globally unique identifier
45+ * @param source the measurement's source
46+ * @param id the measurement's ID
47+ * @throws IllegalArgumentException if the given {@code signalID} is {@code null}
48+ * or the given {@code source} is {@code null} or empty
49+ */
50+ public MeasurementKey(UUID signalId, String source, int id)
51+ {
52+ if (signalId == null)
53+ throw new IllegalArgumentException("signalId must not be null");
54+
55+ if (StringExtensions.isNullOrWhitespace(source))
56+ throw new IllegalArgumentException("source must not be null or empty");
57+
58+ m_signalId = signalId;
59+ m_source = source;
60+ m_id = id;
61+ }
62+
63+ /**
64+ * Gets the globally unique identifier of the measurement.
65+ *
66+ * @return the measurement's globally unique identifier
67+ * @see Measurement#getSignalId()
68+ */
69+ public UUID getSignalId()
70+ {
71+ return m_signalId;
72+ }
73+
74+ /**
75+ * Gets the source of the measurement.
76+ *
77+ * @return the measurement's source
78+ * @see Measurement#getSource()
79+ */
80+ public String getSource()
81+ {
82+ return m_source;
83+ }
84+
85+ /**
86+ * Gets the simple numeric identifier of the measurement.
87+ *
88+ * @return the measurement's simple numeric identifier
89+ * @see Measurement#getId()
90+ */
91+ public int getId()
92+ {
93+ return m_id;
94+ }
95+
96+ /**
97+ * Compares this object to the specified object. The result is
98+ * true if and only if the argument is not {@code null} and is
99+ * a {@code MeasurementKey} that contains the same signal ID as
100+ * this object.
101+ */
102+ @Override
103+ public boolean equals(Object obj)
104+ {
105+ MeasurementKey key;
106+
107+ if(obj == null || !(obj instanceof MeasurementKey))
108+ return false;
109+
110+ key = (MeasurementKey)obj;
111+ return m_signalId.equals(key.m_signalId);
112+ }
113+
114+ /**
115+ * Returns a hash code for this {@code MeasurementKey}.
116+ */
117+ @Override
118+ public int hashCode()
119+ {
120+ return m_signalId.hashCode();
121+ }
122+
123+ /**
124+ * Creates a measurement key for the given measurement, if it has one.
125+ * This method returns null if either the measurement's signal ID
126+ * is null or the source is null or empty.
127+ *
128+ * @param measurement the measurement whose key is to be created
129+ * @return the key for the given measurement
130+ */
131+ public static MeasurementKey getKey(Measurement measurement)
132+ {
133+ UUID signalId = measurement.getSignalId();
134+ String source = measurement.getSource();
135+ int id = measurement.getId();
136+ MeasurementKey key = null;
137+
138+ if (signalId != null && StringExtensions.isNullOrWhitespace(source))
139+ key = new MeasurementKey(signalId, source, id);
140+
141+ return key;
142+ }
143+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/AdvancedSubscribe.java+453−0
@@ -0,0 +1,453 @@
1+//******************************************************************************************************
2+// AdvancedSubscribe.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/23/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.sample;
25+
26+import java.awt.GridBagConstraints;
27+import java.awt.GridBagLayout;
28+import java.awt.event.ActionEvent;
29+import java.awt.event.ActionListener;
30+import java.io.IOException;
31+import java.io.OutputStream;
32+import java.io.PrintStream;
33+import java.net.SocketException;
34+import java.nio.ByteBuffer;
35+import java.nio.charset.Charset;
36+
37+import javax.swing.Box;
38+import javax.swing.BoxLayout;
39+import javax.swing.JApplet;
40+import javax.swing.JButton;
41+import javax.swing.JLabel;
42+import javax.swing.JScrollPane;
43+import javax.swing.JTextArea;
44+import javax.swing.JTextField;
45+import javax.swing.SwingUtilities;
46+
47+import org.gpa.tsf.transport.DataSubscriber;
48+import org.gpa.tsf.transport.SubscriberConnector;
49+import org.gpa.tsf.transport.SubscriptionInfo;
50+import org.gpa.tsf.transport.event.SubscriberConnectorListener;
51+
52+/**
53+ * Sample applet to demonstrate the more advanced use of the subscriber API.
54+ *
55+ * This application accepts the hostname and port of the publisher via text
56+ * fields on the applet, connects to the publisher, subscribes, and displays
57+ * information about the measurements it receives. It assumes that the
58+ * publisher is providing fourteen measurements (PPA:1 through PPA:14) and
59+ * will retry infinitely if it has any trouble connecting. It will also
60+ * automatically reconnect if the connection is terminated.
61+ *
62+ * Measurements are transmitted via a separate UDP data channel.
63+ */
64+public class AdvancedSubscribe extends JApplet
65+{
66+ private Object m_connectLock;
67+ private ActionListener m_connectListener;
68+ private ActionListener m_disconnectListener;
69+
70+ private JScrollPane m_outputScrollPane;
71+ private JTextArea m_outputTextArea;
72+ private JLabel m_hostnameLabel;
73+ private JLabel m_portLabel;
74+ private JTextField m_hostnameTextField;
75+ private JTextField m_portTextField;
76+ private JButton m_connectButton;
77+ private JButton m_disconnectButton;
78+ private Box m_buttonBox;
79+
80+ private PrintStream m_outputStream;
81+ private SubscriptionInfo m_subscriptionInfo;
82+ private SubscriberConnector m_connector;
83+ private DataSubscriber m_subscriber;
84+
85+ @Override
86+ public void init()
87+ {
88+ GridBagConstraints constraints;
89+
90+ super.init();
91+
92+ // Initialize members
93+ m_connectLock = new Object();
94+ m_connectListener = createConnectListener();
95+ m_disconnectListener = createDisconnectListener();
96+
97+ m_outputTextArea = createOutputTextArea();
98+ m_outputScrollPane = new JScrollPane(m_outputTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
99+ m_hostnameLabel = new JLabel("Hostname");
100+ m_portLabel = new JLabel("Port");
101+ m_hostnameTextField = createHostnameTextField();
102+ m_portTextField = createPortTextField();
103+ m_connectButton = createConnectButton();
104+ m_disconnectButton = createDisconnectButton();
105+ m_buttonBox = createButtonBox();
106+
107+ m_outputStream = createOutputStream();
108+ m_subscriptionInfo = createSubscriptionInfo();
109+ m_connector = createSubscriberConnector(m_subscriptionInfo, m_outputStream);
110+ m_subscriber = createSubscriber();
111+
112+ // Component layout
113+ getContentPane().setLayout(new GridBagLayout());
114+
115+ constraints = new GridBagConstraints();
116+ constraints.fill = GridBagConstraints.BOTH;
117+ constraints.gridwidth = 2;
118+ constraints.weighty = 1.0;
119+ getContentPane().add(m_outputScrollPane, constraints);
120+
121+ constraints = new GridBagConstraints();
122+ constraints.gridy = 1;
123+ constraints.weightx = 0.5;
124+ getContentPane().add(m_hostnameLabel, constraints);
125+
126+ constraints = new GridBagConstraints();
127+ constraints.gridx = 1;
128+ constraints.gridy = 1;
129+ constraints.weightx = 0.5;
130+ getContentPane().add(m_portLabel, constraints);
131+
132+ constraints = new GridBagConstraints();
133+ constraints.fill = GridBagConstraints.HORIZONTAL;
134+ constraints.gridy = 2;
135+ constraints.weightx = 0.5;
136+ getContentPane().add(m_hostnameTextField, constraints);
137+
138+ constraints = new GridBagConstraints();
139+ constraints.fill = GridBagConstraints.HORIZONTAL;
140+ constraints.gridx = 1;
141+ constraints.gridy = 2;
142+ constraints.weightx = 0.5;
143+ getContentPane().add(m_portTextField, constraints);
144+
145+ constraints = new GridBagConstraints();
146+ constraints.anchor = GridBagConstraints.CENTER;
147+ constraints.gridy = 3;
148+ constraints.gridwidth = 2;
149+ getContentPane().add(m_buttonBox, constraints);
150+ }
151+
152+ // Creates the action listener used to connect to the publisher.
153+ private ActionListener createConnectListener()
154+ {
155+ return new ActionListener()
156+ {
157+ @Override
158+ public void actionPerformed(ActionEvent arg0)
159+ {
160+ // Set the hostname and port before attempting to connect
161+ m_connector.setHostname(m_hostnameTextField.getText());
162+ m_connector.setPort(Integer.parseInt(m_portTextField.getText()));
163+
164+ // Connect asynchronously so we don't hog the UI thread
165+ connectAsync();
166+ }
167+ };
168+ }
169+
170+ // Connects and subscribes to the publisher asynchronously.
171+ private void connectAsync()
172+ {
173+ new Thread(new Runnable()
174+ {
175+ @Override
176+ public void run()
177+ {
178+ // Lock the connect lock so we don't encounter
179+ // synchronization issues between calls to connectAsync
180+ // and disconnectAsync
181+ synchronized (m_connectLock)
182+ {
183+ try
184+ {
185+ if (m_connector.connect(m_subscriber))
186+ m_subscriber.subscribe(m_subscriptionInfo);
187+ }
188+ catch (SocketException ex)
189+ {
190+ ex.printStackTrace(m_outputStream);
191+ }
192+ }
193+ }
194+ }).start();
195+ }
196+
197+ // Creates the disconnect listener used to disconnect from the publisher.
198+ private ActionListener createDisconnectListener()
199+ {
200+ return new ActionListener()
201+ {
202+ @Override
203+ public void actionPerformed(ActionEvent arg0)
204+ {
205+ // Disconnect asynchronously so we don't hog the UI thread
206+ disconnectAsync();
207+ }
208+ };
209+ }
210+
211+ // Disconnects from the publisher asynchronously.
212+ private void disconnectAsync()
213+ {
214+ new Thread(new Runnable()
215+ {
216+ @Override
217+ public void run()
218+ {
219+ // Cancel the connector first so it won't try
220+ // to automatically reconnect for any reason
221+ m_connector.cancel();
222+
223+ // Lock the connect lock so we don't encounter
224+ // synchronization issues between calls to connectAsync
225+ // and disconnectAsync
226+ synchronized (m_connectLock)
227+ {
228+ // Disconnect from the publisher
229+ m_subscriber.disconnect();
230+
231+ // Create a new subscriber connector since we cancelled the old one
232+ m_connector = createSubscriberConnector(m_subscriptionInfo, m_outputStream);
233+ }
234+ }
235+ }).start();
236+ }
237+
238+ // Creates the text area to which we send our program output.
239+ private JTextArea createOutputTextArea()
240+ {
241+ JTextArea outputTextArea = new JTextArea();
242+ outputTextArea.setEditable(false);
243+ outputTextArea.setLineWrap(true);
244+ outputTextArea.setWrapStyleWord(true);
245+ return outputTextArea;
246+ }
247+
248+ // Creates the text field where the user enters the hostname.
249+ private JTextField createHostnameTextField()
250+ {
251+ JTextField hostnameTextField = new JTextField("localhost");
252+ hostnameTextField.addActionListener(m_connectListener);
253+ return hostnameTextField;
254+ }
255+
256+ // Creates the text field where the user enters the port number.
257+ private JTextField createPortTextField()
258+ {
259+ JTextField portTextField = new JTextField("6170");
260+ portTextField.addActionListener(m_connectListener);
261+ return portTextField;
262+ }
263+
264+ // Creates the button used to connect to the publisher.
265+ private JButton createConnectButton()
266+ {
267+ JButton connectButton = new JButton("Connect");
268+ connectButton.addActionListener(m_connectListener);
269+ return connectButton;
270+ }
271+
272+ // Creates the button used to disconnect from the publisher.
273+ private JButton createDisconnectButton()
274+ {
275+ JButton disconnectButton = new JButton("Disconnect");
276+ disconnectButton.addActionListener(m_disconnectListener);
277+ return disconnectButton;
278+ }
279+
280+ // Creates the box that contains the connect and disconnect buttons.
281+ private Box createButtonBox()
282+ {
283+ Box buttonBox = new Box(BoxLayout.X_AXIS);
284+ buttonBox.add(m_connectButton);
285+ buttonBox.add(m_disconnectButton);
286+ return buttonBox;
287+ }
288+
289+ // Creates the output stream that writes to the text area.
290+ private PrintStream createOutputStream()
291+ {
292+ return new PrintStream(new TextAreaOutputStream(m_outputTextArea));
293+ }
294+
295+ // SubscriptionInfo is a helper object which allows the user
296+ // to set up their subscription and resuse subscription settings.
297+ private SubscriptionInfo createSubscriptionInfo()
298+ {
299+ SubscriptionInfo info = new SubscriptionInfo();
300+
301+ // The following filter expression formats are also available:
302+ //
303+ // - Signal ID list -
304+ //info.setFilterExpression("7aaf0a8f-3a4f-4c43-ab43-ed9d1e64a255;" +
305+ // "93673c68-d59d-4926-b7e9-e7678f9f66b4;" +
306+ // "65ac9cf6-ae33-4ece-91b6-bb79343855d5;" +
307+ // "3647f729-d0ed-4f79-85ad-dae2149cd432;" +
308+ // "069c5e29-f78a-46f6-9dff-c92cb4f69371;" +
309+ // "25355a7b-2a9d-4ef2-99ba-4dd791461379");
310+ //
311+ // - Filter pattern -
312+ //info.setFilterExpression("FILTER ActiveMeasurements WHERE ID LIKE 'PPA:*'");
313+ //info.setFilterExpression("FILTER ActiveMeasurements WHERE Device = 'SHELBY' AND SignalType = 'FREQ'");
314+
315+ info.setFilterExpression("PPA:1;PPA:2;PPA:3;PPA:4;PPA:5;PPA:6;PPA:7;PPA:8;PPA:9;PPA:10;PPA:11;PPA:12;PPA:13;PPA:14");
316+
317+ // To set up a remotely synchronized subscription, set this flag
318+ // to true and add the framesPerSecond parameter to the
319+ // ExtraConnectionStringParameters. Additionally, the following
320+ // example demonstrates the use of some other useful parameters
321+ // when setting up remotely synchronized subscriptions.
322+ //
323+ //info.setRemotelySynchronized(true);
324+ //info.setExtraConnectionStringParameters("framesPerSecond=30;timeResolution=10000;downsamplingMethod=Closest");
325+
326+ info.setRemotelySynchronized(false);
327+ info.setThrottled(false);
328+
329+ info.setUdpDataChannel(true);
330+ info.setDataChannelLocalPort(9600);
331+
332+ info.setTimeIncluded(true);
333+ info.setLagTime(3.0);
334+ info.setLeadTime(1.0);
335+ info.setLocalClockAsRealTime(false);
336+ info.setMillisecondResolution(true);
337+
338+ return info;
339+ }
340+
341+ // SubscriberConnector is another helper object which allows the
342+ // user to modify settings for auto-reconnects and retry cycles.
343+ private SubscriberConnector createSubscriberConnector(SubscriptionInfo info, PrintStream outputStream)
344+ {
345+ SubscriberConnector connector = new SubscriberConnector();
346+ SubscriberConnectorListener listener = new SampleSubscriberConnectorListener(info, outputStream);
347+
348+ connector.setMaxRetries(-1);
349+ connector.setRetryInterval(5000);
350+ connector.setAutoReconnect(true);
351+ connector.addSubscriberConnectorListener(listener);
352+
353+ return connector;
354+ }
355+
356+ // Creates the data subscriber.
357+ private DataSubscriber createSubscriber()
358+ {
359+ DataSubscriber subscriber = new DataSubscriber();
360+ subscriber.addSubscriberListener(new SampleSubscriberListener(m_outputStream, m_outputStream));
361+ return subscriber;
362+ }
363+
364+ private static final long serialVersionUID = -787591661184215315L;
365+
366+ // OutputStream that, when wrapped by a
367+ // PrintStream, allows for output to a JTextArea.
368+ private class TextAreaOutputStream extends OutputStream
369+ {
370+ private ByteBuffer m_buffer;
371+ private JTextArea m_outputArea;
372+
373+ public TextAreaOutputStream(JTextArea outputTextArea)
374+ {
375+ if (outputTextArea == null)
376+ throw new IllegalArgumentException("outputTextArea must not be null");
377+
378+ m_buffer = ByteBuffer.allocate(2000);
379+ m_outputArea = outputTextArea;
380+ }
381+
382+ @Override
383+ public void flush() throws IOException
384+ {
385+ m_buffer.flip();
386+ append(Charset.defaultCharset().decode(m_buffer).toString());
387+ m_buffer = m_buffer.compact();
388+ }
389+
390+ @Override
391+ public void write(byte[] b) throws IOException
392+ {
393+ write(b, 0, b.length);
394+ }
395+
396+ @Override
397+ public void write(byte[] b, int off, int len) throws IOException
398+ {
399+ int rem = m_buffer.remaining();
400+
401+ if (len <= rem)
402+ {
403+ m_buffer.put(b, off, len);
404+
405+ if (m_buffer.position() >= DumpThreshold)
406+ flush();
407+ }
408+ else
409+ {
410+ m_buffer.put(b, off, rem);
411+ flush();
412+
413+ for (int i = rem; i < len; i += m_buffer.capacity())
414+ {
415+ rem = Math.min(m_buffer.remaining(), len - i);
416+ m_buffer.put(b, off + i, rem);
417+ flush();
418+ }
419+ }
420+ }
421+
422+ @Override
423+ public void write(int b) throws IOException
424+ {
425+ m_buffer.put((byte)b);
426+
427+ if (m_buffer.position() >= DumpThreshold)
428+ flush();
429+ }
430+
431+ private void append(final String text)
432+ {
433+ SwingUtilities.invokeLater(new Runnable()
434+ {
435+ @Override
436+ public void run()
437+ {
438+ StringBuilder textBuilder = new StringBuilder(m_outputArea.getText());
439+
440+ textBuilder.append(text);
441+
442+ while (textBuilder.length() > CharacterLimit)
443+ textBuilder.delete(0, textBuilder.indexOf(System.lineSeparator()) + 1);
444+
445+ m_outputArea.setText(textBuilder.toString());
446+ }
447+ });
448+ }
449+
450+ private static final int DumpThreshold = 50;
451+ private static final int CharacterLimit = 8192;
452+ }
453+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/SampleSubscriberConnectorListener.java+90−0
@@ -0,0 +1,90 @@
1+//******************************************************************************************************
2+// SampleSubscriberConnectorListener.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/23/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.sample;
25+
26+import java.io.PrintStream;
27+
28+import org.gpa.tsf.transport.SubscriptionInfo;
29+import org.gpa.tsf.transport.event.MessageEvent;
30+import org.gpa.tsf.transport.event.SubscriberConnectorAdapter;
31+import org.gpa.tsf.transport.event.SubscriberEvent;
32+
33+/**
34+ * Sample listener for a subscriber connector.
35+ *
36+ * @see SubscriberConnector
37+ */
38+public class SampleSubscriberConnectorListener extends SubscriberConnectorAdapter
39+{
40+ private SubscriptionInfo m_info;
41+ private PrintStream m_errorStream;
42+
43+ /**
44+ * Constructs a new instance using the standard {@code System.err}
45+ * print stream for displaying errors.
46+ *
47+ * @param info subscription info used to automatically
48+ * resubscribe to the publisher
49+ */
50+ public SampleSubscriberConnectorListener(SubscriptionInfo info)
51+ {
52+ this(info, System.err);
53+ }
54+
55+ /**
56+ * Constructs a new instance.
57+ *
58+ * @param info subscription info used to automatically
59+ * resubscribe to the publisher
60+ * @param errorStream print stream used for displaying errors
61+ */
62+ public SampleSubscriberConnectorListener(SubscriptionInfo info, PrintStream errorStream)
63+ {
64+ if (info == null)
65+ throw new IllegalArgumentException("info must not be null");
66+
67+ m_info = info;
68+ m_errorStream = errorStream;
69+ }
70+
71+ @Override
72+ public void exceptionEncountered(MessageEvent evt)
73+ {
74+ if (m_errorStream != null)
75+ evt.getException().printStackTrace(m_errorStream);
76+ }
77+
78+ @Override
79+ public void reconnected(SubscriberEvent evt)
80+ {
81+ try
82+ {
83+ evt.getSubscriber().subscribe(m_info);
84+ }
85+ catch (Exception ex)
86+ {
87+ ex.printStackTrace(m_errorStream);
88+ }
89+ }
90+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/SampleSubscriberListener.java+182−0
@@ -0,0 +1,182 @@
1+//******************************************************************************************************
2+// SampleSubscriberListener.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/19/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.sample;
25+
26+import java.io.PrintStream;
27+import java.text.DateFormat;
28+import java.text.SimpleDateFormat;
29+import java.util.Collection;
30+import java.util.Iterator;
31+
32+import org.gpa.tsf.Measurement;
33+import org.gpa.tsf.transport.DataSubscriber;
34+import org.gpa.tsf.transport.event.MeasurementEvent;
35+import org.gpa.tsf.transport.event.MessageEvent;
36+import org.gpa.tsf.transport.event.SubscriberAdapter;
37+import org.gpa.tsf.util.TimeExtensions;
38+
39+/**
40+ * Sample listener class for the {@link DataSubscriber}.
41+ *
42+ * @see SimpleSubscribe
43+ */
44+public class SampleSubscriberListener extends SubscriberAdapter
45+{
46+ private PrintStream m_outputStream;
47+ private PrintStream m_errorStream;
48+ private int m_processCount;
49+
50+ /**
51+ * Constructs a new sample subscriber listener using the standard
52+ * {@link System.out} and {@link System.err} print streams.
53+ */
54+ public SampleSubscriberListener()
55+ {
56+ this(System.out, System.err);
57+ }
58+
59+ /**
60+ * Constructs a new sample subscriber listener using
61+ * the given output stream and no error stream.
62+ *
63+ * @param outputStream the output stream to which messages will be written
64+ * @throws IllegalArgumentException if {@code outputStream} is {@code null}
65+ */
66+ public SampleSubscriberListener(PrintStream outputStream)
67+ {
68+ this(outputStream, null);
69+ }
70+
71+ /**
72+ * Constructs a new sample subscriber litener using
73+ * the given output stream and error stream.
74+ *
75+ * @param outputStream the output stream to which status messages will be written
76+ * @param errorStream the error stream to which error messages will be written
77+ * @throws IllegalArgumentException if {@code outputStream} is {@code null}
78+ */
79+ public SampleSubscriberListener(PrintStream outputStream, PrintStream errorStream)
80+ {
81+ if (outputStream == null)
82+ throw new IllegalArgumentException("outputStream cannot be null");
83+
84+ m_outputStream = outputStream;
85+ m_errorStream = errorStream;
86+ }
87+
88+ /**
89+ * Writes status messages from the {@link DataSubscriber} to the output stream.
90+ */
91+ @Override
92+ public void statusMessageReceived(MessageEvent evt)
93+ {
94+ m_outputStream.println(evt.getMessage());
95+ m_outputStream.println();
96+ }
97+
98+ /**
99+ * Writes the stack trace of exceptions encountered
100+ * by the {@link DataSubscriber} to the error stream.
101+ */
102+ @Override
103+ public void exceptionEncountered(MessageEvent evt)
104+ {
105+ if (m_errorStream != null)
106+ {
107+ evt.getException().printStackTrace(m_errorStream);
108+ m_errorStream.println();
109+ }
110+ }
111+
112+ /**
113+ * Writes information about measurements received from the
114+ * {@link DataSubscriber} to the output stream every so often.
115+ */
116+ @Override
117+ public void newMeasurementsReceived(MeasurementEvent evt)
118+ {
119+ Collection<Measurement> newMeasurements = evt.getMeasurements();
120+
121+ DataSubscriber subscriber = null;
122+ Measurement firstMeasurement = null;
123+ Measurement nextMeasurement = null;
124+ Iterator<Measurement> iter = null;
125+
126+ DateFormat dateFormat;
127+ String dateString;
128+
129+ // Only display messages every five
130+ // seconds (assuming 30 calls per second)
131+ if (m_processCount % 150 == 0)
132+ {
133+ if (evt.getSource() instanceof DataSubscriber)
134+ subscriber = (DataSubscriber)evt.getSource();
135+
136+ if (newMeasurements.size() > 0)
137+ {
138+ firstMeasurement = newMeasurements.iterator().next();
139+ iter = newMeasurements.iterator();
140+ }
141+
142+ if (subscriber != null)
143+ m_outputStream.println(subscriber.getTotalMeasurementsReceived() + " measurements received so far...");
144+
145+ if (firstMeasurement != null)
146+ {
147+ dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
148+ dateString = dateFormat.format(TimeExtensions.fromTicks(firstMeasurement.getTimestamp()).getTime());
149+ m_outputStream.println("Timestamp: " + dateString);
150+ }
151+
152+ if (iter != null)
153+ {
154+ m_outputStream.println("Point\tValue");
155+
156+ while (iter.hasNext())
157+ {
158+ nextMeasurement = iter.next();
159+ m_outputStream.println(nextMeasurement.getId() + "\t" + nextMeasurement.getValue());
160+ }
161+
162+ m_outputStream.println();
163+ }
164+ }
165+
166+ m_processCount++;
167+ }
168+
169+ /**
170+ * Writes the message received when the {@link DataSubscriber}'s
171+ * connection is terminated to the error stream.
172+ */
173+ @Override
174+ public void connectionTerminated(MessageEvent evt)
175+ {
176+ if (m_errorStream != null)
177+ {
178+ m_errorStream.println(evt.getMessage());
179+ m_errorStream.println();
180+ }
181+ }
182+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/sample/SimpleSubscribe.java+111−0
@@ -0,0 +1,111 @@
1+//******************************************************************************************************
2+// SimpleSubscribe.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/19/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.sample;
25+
26+import java.io.IOException;
27+import java.util.Scanner;
28+
29+import org.gpa.tsf.transport.DataSubscriber;
30+import org.gpa.tsf.transport.SubscriptionInfo;
31+
32+/**
33+ * Provides an example of how to use the Subscriber API.
34+ *
35+ * @see DataSubscriber
36+ */
37+public class SimpleSubscribe
38+{
39+ private static DataSubscriber s_subscriber;
40+
41+ /**
42+ * Main method. Entry point into the program.
43+ *
44+ * @param args command line arguments
45+ */
46+ public static void main(String[] args)
47+ {
48+ String hostname;
49+ int port;
50+
51+ // Ensure that the necessary
52+ // command line arguments are given
53+ if (args.length < 2)
54+ {
55+ System.err.println("Error: requires two command line arguments");
56+ System.err.println(" 1. hostname of publisher");
57+ System.err.println(" 2. port used to initiate connection");
58+ return;
59+ }
60+
61+ // Get hostname and port
62+ hostname = args[0];
63+ port = Integer.parseInt(args[1]);
64+
65+ // Run the subscriber
66+ runSubscriber(hostname, port);
67+
68+ // Wait until user presses enter before quitting
69+ waitForUserInput();
70+
71+ // Disconnect the subscriber to stop background threads
72+ if (s_subscriber != null)
73+ s_subscriber.disconnect();
74+ }
75+
76+ // The proper procedure when creating and running a subscriber is:
77+ // - Create subscriber
78+ // - Add listeners
79+ // - Connect to publisher
80+ // - Subscribe
81+ private static void runSubscriber(String hostname, int port)
82+ {
83+ try
84+ {
85+ s_subscriber = new DataSubscriber();
86+ s_subscriber.addSubscriberListener(new SampleSubscriberListener());
87+ s_subscriber.connect(hostname, port);
88+ s_subscriber.subscribe(createSubscriptionInfo());
89+ }
90+ catch (IOException ex)
91+ {
92+ ex.printStackTrace();
93+ }
94+ }
95+
96+ // SubscriptionInfo is a helper object which allows the user
97+ // to set up their subscription and reuse subscription settings
98+ private static SubscriptionInfo createSubscriptionInfo()
99+ {
100+ SubscriptionInfo info = new SubscriptionInfo();
101+ info.setFilterExpression("PPA:1;PPA:2;PPA:3;PPA:4;PPA:5;PPA:6;PPA:7;PPA:8;PPA:9;PPA:10;PPA:11;PPA:12;PPA:13;PPA:14");
102+ return info;
103+ }
104+
105+ // Waits for the user to press Enter before proceeding
106+ private static void waitForUserInput()
107+ {
108+ Scanner scan = new Scanner(System.in);
109+ scan.nextLine();
110+ }
111+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/CompactMeasurementParser.java+288−0
@@ -0,0 +1,288 @@
1+//******************************************************************************************************
2+// CompactMeasurementParser.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/12/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport;
25+
26+import java.nio.ByteBuffer;
27+import java.util.ArrayList;
28+import java.util.Collection;
29+
30+import org.gpa.tsf.Measurement;
31+import org.gpa.tsf.MeasurementKey;
32+import org.gpa.tsf.util.Masks;
33+
34+/**
35+ * Implementation of {@link GatewayMeasurementParser} that parses
36+ * measurements serialized using the compact measurement format.
37+ */
38+public class CompactMeasurementParser implements GatewayMeasurementParser
39+{
40+ private SignalIndexCache m_signalIndexCache;
41+ private long[] m_baseTimeOffsets;
42+ private boolean m_includeTime;
43+ private boolean m_useMillisecondResolution;
44+
45+ /**
46+ * Constructs a new compact measurement parser with the given signal index cache.
47+ *
48+ * @param signalIndexCache the cache used to compact measurement IDs during serialization
49+ * @throws IllegalArgumentException if {@code signalIndexCache} is {@code null}
50+ */
51+ public CompactMeasurementParser(SignalIndexCache signalIndexCache)
52+ {
53+ this(signalIndexCache, null, true, false);
54+ }
55+
56+ /**
57+ * Constructs a new compact measurement parser with the
58+ * given signal index cache and base time offsets.
59+ *
60+ * @param signalIndexCache the cache used to compact measurement IDs during serialization
61+ * @param baseTimeOffsets the offsets used to compact measurement timestamps during serialization
62+ * @param includeTime indicates whether timestamps were included when serializing the measurements
63+ * @param useMillisecondResolution determines whether measurement timestamps were further compacted
64+ * during serialization by specifying them to be in millisecond resolution
65+ * @throws IllegalArgumentException if {@code signalIndexCache} is {@code null}
66+ */
67+ public CompactMeasurementParser(SignalIndexCache signalIndexCache, long[] baseTimeOffsets, boolean includeTime, boolean useMillisecondResolution)
68+ {
69+ if(signalIndexCache == null)
70+ throw new IllegalArgumentException("signalIndexCache cannot be null");
71+
72+ m_signalIndexCache = signalIndexCache;
73+ m_baseTimeOffsets = baseTimeOffsets;
74+ m_includeTime = includeTime;
75+ m_useMillisecondResolution = useMillisecondResolution;
76+ }
77+
78+ /**
79+ * Parses a collection of serialized measurements.
80+ */
81+ @Override
82+ public Collection<Measurement> parseMeasurements(byte[] serializedMeasurements, int offset, int length)
83+ {
84+ return parseMeasurements(ByteBuffer.wrap(serializedMeasurements, offset, length));
85+ }
86+
87+ /**
88+ * Parses a collection of serialized measurements.
89+ */
90+ @Override
91+ public Collection<Measurement> parseMeasurements(ByteBuffer serializedMeasurementBuffer)
92+ {
93+ Collection<Measurement> measurements = new ArrayList<Measurement>();
94+ Measurement parsedMeasurement;
95+
96+ // Parsed from serialized measurement
97+ byte compactFlags;
98+ short signalIndex;
99+ float measurementValue;
100+ long timestamp = 0L;
101+
102+ // Used for base time offsets
103+ boolean usingBaseTimeOffset;
104+ int timeIndex;
105+
106+ // Obtained from signal index cache
107+ MeasurementKey key;
108+
109+ while (serializedMeasurementBuffer.hasRemaining())
110+ {
111+ // Get and validate compact measurement flags
112+ compactFlags = serializedMeasurementBuffer.get();
113+ usingBaseTimeOffset = (compactFlags & CompactBaseTimeOffsetFlag) != 0;
114+ timeIndex = ((compactFlags & CompactTimeIndexFlag) != 0) ? 1 : 0;
115+
116+ if (usingBaseTimeOffset && (m_baseTimeOffsets == null || m_baseTimeOffsets[timeIndex] == 0))
117+ break;
118+
119+ if (serializedMeasurementBuffer.remaining() + 1 < getMeasurementByteLength(usingBaseTimeOffset))
120+ break;
121+
122+ // Get and validate signal index
123+ signalIndex = serializedMeasurementBuffer.getShort();
124+
125+ if (!m_signalIndexCache.contains(signalIndex))
126+ break;
127+
128+ // Get measurement value and timestamp
129+ measurementValue = serializedMeasurementBuffer.getFloat();
130+
131+ if (m_includeTime)
132+ {
133+ if (!usingBaseTimeOffset)
134+ {
135+ timestamp = serializedMeasurementBuffer.getLong();
136+ }
137+ else if (!m_useMillisecondResolution)
138+ {
139+ timestamp = serializedMeasurementBuffer.getInt() & Masks.getLongMask(Integer.SIZE);
140+ timestamp += m_baseTimeOffsets[timeIndex];
141+ }
142+ else
143+ {
144+ timestamp = serializedMeasurementBuffer.getShort() & Masks.getLongMask(Short.SIZE);
145+ timestamp *= 10000;
146+ timestamp += m_baseTimeOffsets[timeIndex];
147+ }
148+ }
149+
150+ // Construct the parsed measurement and add it to the collection
151+ key = m_signalIndexCache.getMeasurementKey(signalIndex);
152+ parsedMeasurement = new Measurement();
153+
154+ parsedMeasurement.setFlags(mapToFullFlags(compactFlags));
155+ parsedMeasurement.setSignalId(key.getSignalId());
156+ parsedMeasurement.setSource(key.getSource());
157+ parsedMeasurement.setId(key.getId());
158+ parsedMeasurement.setValue(measurementValue);
159+ parsedMeasurement.setTimestamp(timestamp);
160+
161+ measurements.add(parsedMeasurement);
162+ }
163+
164+ return measurements;
165+ }
166+
167+ /**
168+ * Gets the byte length of measurements parsed by this parser.
169+ *
170+ * @param usingBaseTimeOffset If false, measurement timestamps are 8 bytes; otherwise, they're smaller.
171+ * This value is determined at serialization time for each individual measurement, so the value
172+ * returned by this method may not be representative of all parsed measurements.
173+ * @return the byte length of measurements parsed by this parser
174+ */
175+ public int getMeasurementByteLength(boolean usingBaseTimeOffset)
176+ {
177+ int byteLength = 7;
178+
179+ if (m_includeTime)
180+ {
181+ if (!usingBaseTimeOffset)
182+ byteLength += 8;
183+ else if(!m_useMillisecondResolution)
184+ byteLength += 4;
185+ else
186+ byteLength += 2;
187+ }
188+
189+ return byteLength;
190+ }
191+
192+ // Maps the 8-bit compact flag format to the 32-bit full flag format.
193+ private int mapToFullFlags(byte compactFlags)
194+ {
195+ int fullFlags = 0;
196+
197+ if ((compactFlags & CompactDataRangeFlag) != 0)
198+ fullFlags |= DataRangeMask;
199+
200+ if ((compactFlags & CompactDataQualityFlag) != 0)
201+ fullFlags |= DataQualityMask;
202+
203+ if ((compactFlags & CompactTimeQualityFlag) != 0)
204+ fullFlags |= TimeQualityMask;
205+
206+ if ((compactFlags & CompactSystemIssueFlag) != 0)
207+ fullFlags |= SystemIssueMask;
208+
209+ if ((compactFlags & CompactCalculatedValueFlag) != 0)
210+ fullFlags |= CalculatedValueMask;
211+
212+ if ((compactFlags & CompactDiscardedValueFlag) != 0)
213+ fullFlags |= DiscardedValueMask;
214+
215+ return fullFlags;
216+ }
217+
218+ /**
219+ * A data range flag was set.
220+ */
221+ public static final byte CompactDataRangeFlag = 0x01;
222+
223+ /**
224+ * A data quality flag was set.
225+ */
226+ public static final byte CompactDataQualityFlag = 0x02;
227+
228+ /**
229+ * A time quality flag was set.
230+ */
231+ public static final byte CompactTimeQualityFlag = 0x04;
232+
233+ /**
234+ * A system flag was set.
235+ */
236+ public static final byte CompactSystemIssueFlag = 0x08;
237+
238+ /**
239+ * Calculated value bit was set.
240+ */
241+ public static final byte CompactCalculatedValueFlag = 0x10;
242+
243+ /**
244+ * Discarded value bit was set.
245+ */
246+ public static final byte CompactDiscardedValueFlag = 0x20;
247+
248+ /**
249+ * Compact measurement timestamp was serialized using base time offset when set.
250+ */
251+ public static final byte CompactBaseTimeOffsetFlag = 0x40;
252+
253+ /**
254+ * Use odd time index (i.e., 1) when bit is set; even time index (i.e., 0) when bit is clear.
255+ */
256+ public static final byte CompactTimeIndexFlag = (byte)0x80;
257+
258+ /**
259+ * Mask over the data range flags.
260+ */
261+ public static final int DataRangeMask = 0x000000FC;
262+
263+ /**
264+ * Mask over the data quality flags.
265+ */
266+ public static final int DataQualityMask = 0x0000EF03;
267+
268+ /**
269+ * Mask over the time quality flags.
270+ */
271+ public static final int TimeQualityMask = 0x00BF0000;
272+
273+ /**
274+ * Mask over the system issue flags.
275+ */
276+ public static final int SystemIssueMask = 0xE0000000;
277+
278+ /**
279+ * Mask over the calculated value bit.
280+ */
281+ public static final int CalculatedValueMask = 0x00001000;
282+
283+ /**
284+ * Mask over the dicarded value bit.
285+ */
286+ public static final int DiscardedValueMask = 0x00400000;
287+
288+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/DataSubscriber.java+1212−0
@@ -0,0 +1,1212 @@
1+//******************************************************************************************************
2+// DataSubscriber.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport;
25+
26+import java.io.ByteArrayInputStream;
27+import java.io.IOException;
28+import java.io.InputStream;
29+import java.io.OutputStream;
30+import java.net.DatagramPacket;
31+import java.net.DatagramSocket;
32+import java.net.InetAddress;
33+import java.net.Socket;
34+import java.net.SocketException;
35+import java.net.UnknownHostException;
36+import java.nio.ByteBuffer;
37+import java.nio.ByteOrder;
38+import java.nio.charset.Charset;
39+import java.util.ArrayList;
40+import java.util.Collection;
41+import java.util.UUID;
42+import java.util.concurrent.BlockingQueue;
43+import java.util.concurrent.LinkedBlockingQueue;
44+import java.util.concurrent.TimeUnit;
45+import java.util.zip.GZIPInputStream;
46+
47+import org.gpa.tsf.Measurement;
48+import org.gpa.tsf.transport.constant.CompressionMode;
49+import org.gpa.tsf.transport.constant.DataPacketFlags;
50+import org.gpa.tsf.transport.constant.OperationalEncoding;
51+import org.gpa.tsf.transport.constant.OperationalModes;
52+import org.gpa.tsf.transport.constant.ServerCommand;
53+import org.gpa.tsf.transport.constant.ServerResponse;
54+import org.gpa.tsf.transport.event.MeasurementEvent;
55+import org.gpa.tsf.transport.event.MessageEvent;
56+import org.gpa.tsf.transport.event.MetadataEvent;
57+import org.gpa.tsf.transport.event.StartTimeEvent;
58+import org.gpa.tsf.transport.event.SubscriberListener;
59+import org.gpa.tsf.util.ArrayExtensions;
60+import org.gpa.tsf.util.InputStreamExtensions;
61+import org.gpa.tsf.util.Masks;
62+import org.gpa.tsf.util.StringExtensions;
63+
64+/**
65+ * Implementation of the Subscriber API that will connect
66+ * to a data publisher for a data subscription.
67+ */
68+public class DataSubscriber
69+{
70+ private SubscriptionInfo m_currentSubscription;
71+ private InetAddress[] m_allHostAddresses;
72+ private InetAddress m_hostAddress;
73+ private int m_operationalModes;
74+ private Charset m_characterEncoding;
75+ private boolean m_unsubscribing;
76+ private boolean m_disconnecting;
77+
78+ // Statistics counters
79+ private long m_totalCommandChannelBytesReceived;
80+ private long m_totalDataChannelBytesReceived;
81+ private long m_totalMeasurementsReceived;
82+ private boolean m_connected;
83+ private boolean m_subscribed;
84+
85+ // Measurement parsing
86+ private SignalIndexCache m_signalIndexCache;
87+ private long[] m_baseTimeOffsets;
88+
89+ // Command thread members
90+ private Thread m_commandThread;
91+ private BlockingQueue<byte[]> m_commandQueue;
92+
93+ // Callback thread members
94+ private Thread m_callbackThread;
95+ private BlockingQueue<Runnable> m_callbackQueue;
96+
97+ // Command channel
98+ private Thread m_commandChannelResponseThread;
99+ private Socket m_commandChannelSocket;
100+
101+ // Data channel
102+ private Thread m_dataChannelResponseThread;
103+ private DatagramSocket m_dataChannelSocket;
104+
105+ // Callbacks
106+ private Collection<SubscriberListener> m_subscriberListeners;
107+
108+ /**
109+ * Constructs a new data subscriber.
110+ */
111+ public DataSubscriber()
112+ {
113+ m_commandQueue = new LinkedBlockingQueue<byte[]>();
114+ m_callbackQueue = new LinkedBlockingQueue<Runnable>();
115+ m_subscriberListeners = new ArrayList<SubscriberListener>();
116+
117+ setOperationalModes(OperationalModes.UseCommonSerializationFormat | OperationalEncoding.Unicode | OperationalModes.CompressMetadata);
118+ }
119+
120+ /**
121+ * Adds the given listener to receive events from this subscriber.
122+ * If the {@code listener} is {@code null}, no exception is thrown
123+ * and no action is performed.
124+ *
125+ * @param subscriberListener the listener to be added
126+ */
127+ public void addSubscriberListener(SubscriberListener subscriberListener)
128+ {
129+ if (subscriberListener != null)
130+ m_subscriberListeners.add(subscriberListener);
131+ }
132+
133+ /**
134+ * Removes the given listener so that it no longer receives events
135+ * from this subscriber. This method performs no function, nor does
136+ * it throw an exception, if {@code subscriberListener} was not
137+ * previously added to this component. If {@code subscriberListener}
138+ * is {@code null}, no exception is thrown and no action is performed.
139+ *
140+ * @param subscriberListener the listener to be removed
141+ */
142+ public void removeSubscriberListener(SubscriberListener subscriberListener)
143+ {
144+ if (subscriberListener != null)
145+ m_subscriberListeners.remove(subscriberListener);
146+ }
147+
148+ /**
149+ * Gets the operational modes currently in use by this subscriber.
150+ *
151+ * @return the subscriber's operational modes
152+ */
153+ public int getOperationalModes()
154+ {
155+ return m_operationalModes;
156+ }
157+
158+ /**
159+ * Sets the operational modes of the subscriber.
160+ * <p>
161+ * The operational modes define a set of flags that can be used to
162+ * indicate to the publisher how the subscriber wishes to communicate
163+ * with it. This method will throw an {@code UnsupportedOperationException}
164+ * if any of the following are true.
165+ * <p>
166+ * <ul>
167+ * <li>{@link OperationalModes.UseCommonSerializationFormat} is unset</li>
168+ * <li>{@link OperationalModes.CompressSignalIndexCache} is set</li>
169+ * </ul>
170+ *
171+ * @param operationalModes the new operational modes
172+ * @throws UnsupportedOperationException if an unsupported operational mode is detected
173+ * @see OperationalModes
174+ */
175+ public void setOperationalModes(int operationalModes)
176+ {
177+ int operationalEncoding;
178+
179+ // .NET serialization format not supported
180+ if ((operationalModes & OperationalModes.UseCommonSerializationFormat) == 0)
181+ throw new UnsupportedOperationException("Cannot use .NET serialization format. Use common serialization format instead.");
182+
183+ // Update operational modes and character encoding
184+ m_operationalModes = operationalModes;
185+ operationalEncoding = operationalModes & OperationalModes.EncodingMask;
186+
187+ switch (operationalEncoding)
188+ {
189+ case OperationalEncoding.Unicode:
190+ m_characterEncoding = Charset.forName("UTF-16LE");
191+ break;
192+
193+ case OperationalEncoding.BigEndianUnicode:
194+ m_characterEncoding = Charset.forName("UTF-16BE");
195+ break;
196+
197+ case OperationalEncoding.UTF8:
198+ m_characterEncoding = Charset.forName("UTF-8");
199+ break;
200+
201+ case OperationalEncoding.OperatingSystemDefault:
202+ m_characterEncoding = Charset.defaultCharset();
203+ break;
204+ }
205+
206+ // If subscriber is connected, send automatically
207+ if (m_connected)
208+ sendOperationalModes();
209+ }
210+
211+ /**
212+ * Connects to the publisher listening at the given hostname and port.
213+ *
214+ * @param hostname name or address of the machine hosting the publisher
215+ * @param port the port that the publisher is listening on
216+ * @throws IllegalStateException if the subscriber is already connected
217+ * @throws IOException if an I/O error occurs when creating the socket
218+ * @see #disconnect()
219+ */
220+ public void connect(String hostname, int port) throws IOException
221+ {
222+ m_totalCommandChannelBytesReceived = 0L;
223+ m_totalDataChannelBytesReceived = 0L;
224+ m_totalMeasurementsReceived = 0L;
225+
226+ if (m_connected)
227+ throw new IllegalStateException("Subscriber is already connected; disconnect first");
228+
229+ m_commandChannelSocket = new Socket(hostname, port);
230+ m_hostAddress = m_commandChannelSocket.getInetAddress();
231+
232+ if (m_hostAddress.isAnyLocalAddress())
233+ m_hostAddress = InetAddress.getLocalHost();
234+
235+ try
236+ {
237+ m_allHostAddresses = InetAddress.getAllByName(m_hostAddress.getHostName());
238+ }
239+ catch (UnknownHostException ex)
240+ {
241+ m_allHostAddresses = new InetAddress[0];
242+ }
243+
244+ startCommandThread();
245+ startCallbackThread();
246+ startCommandChannelResponseThread();
247+
248+ sendOperationalModes();
249+ m_connected = true;
250+ }
251+
252+ /**
253+ * Disconnects from the data publisher. This method does not return
254+ * until all connections have been closed and all threads spawned by
255+ * the subscriber have shut down gracefully (with the exception of
256+ * the thread that executes the connection terminated callback).
257+ *
258+ * @see #connect(String, int)
259+ */
260+ public void disconnect()
261+ {
262+ // Notify running threads that
263+ // the subscriber is disconnecting
264+ m_unsubscribing = true;
265+ m_disconnecting = true;
266+
267+ try
268+ {
269+ // Close sockets so that threads using
270+ // them can shut down gracefully
271+ if (m_commandChannelSocket != null)
272+ m_commandChannelSocket.close();
273+ }
274+ catch (IOException ex)
275+ {
276+ // Ignore exceptions and
277+ // continue shutdown procedure
278+ }
279+
280+ if (m_dataChannelSocket != null)
281+ m_dataChannelSocket.close();
282+
283+ // Join with all threads to guarantee their completion
284+ // before returning control to the caller
285+ joinThread(m_commandThread);
286+ joinThread(m_callbackThread);
287+ joinThread(m_commandChannelResponseThread);
288+ joinThread(m_dataChannelResponseThread);
289+
290+ // Empty queues so they can be used again later
291+ m_commandQueue.clear();
292+ m_callbackQueue.clear();
293+
294+ // Release references to threads and
295+ // sockets that we are no longer using
296+ m_commandThread = null;
297+ m_callbackThread = null;
298+ m_commandChannelResponseThread = null;
299+ m_dataChannelResponseThread = null;
300+ m_commandChannelSocket = null;
301+ m_dataChannelSocket = null;
302+
303+ // Disconnect completed
304+ m_unsubscribing = false;
305+ m_subscribed = false;
306+ m_disconnecting = false;
307+ m_connected = false;
308+ }
309+
310+ /**
311+ * Subscribes to the signals specified by the
312+ * filter expression in the {@code info} object.
313+ *
314+ * @param info subscription info used to configure the subscription
315+ * @throws SocketException if, when defining a UDP data channel, the
316+ * socket could not be opened, or the socket could not bind
317+ * to the specified local port
318+ * @see #unsubscribe()
319+ */
320+ public void subscribe(SubscriptionInfo info) throws SocketException
321+ {
322+ StringBuilder connectionStringBuilder = new StringBuilder();
323+ byte[] connectionStringBytes;
324+ ByteBuffer packetData;
325+ int packetDataSize;
326+
327+ // Make sure to unsubscribe before attempting another
328+ // subscription so we don't leave connections open
329+ if (m_subscribed)
330+ unsubscribe();
331+
332+ m_currentSubscription = new SubscriptionInfo(info);
333+ m_totalMeasurementsReceived = 0L;
334+
335+ connectionStringBuilder.append("trackLatestMeasurements").append(info.isThrottled()).append(';');
336+ connectionStringBuilder.append("includeTime=").append(info.isTimeIncluded()).append(';');
337+ connectionStringBuilder.append("lagTime=").append(info.getLagTime()).append(';');
338+ connectionStringBuilder.append("leadTime=").append(info.getLeadTime()).append(';');
339+ connectionStringBuilder.append("useLocalClockAsRealTime=").append(info.isLocalClockAsRealTime()).append(';');
340+ connectionStringBuilder.append("processingInterval=").append(info.getProcessingInterval()).append(';');
341+ connectionStringBuilder.append("useMillisecondResolution=").append(info.isMillisecondResolution()).append(';');
342+ connectionStringBuilder.append("assemblyInfo={source=TSF Java Library;version=0.9.0;buildDate=April 2012};");
343+
344+ if (!StringExtensions.isNullOrWhitespace(info.getFilterExpression()))
345+ connectionStringBuilder.append("inputMeasurementKeys={").append(info.getFilterExpression()).append("};");
346+
347+ if (info.isUdpDataChannel())
348+ {
349+ m_dataChannelSocket = new DatagramSocket(info.getDataChannelLocalPort(), m_commandChannelSocket.getLocalAddress());
350+ startDataChannelResponseThread();
351+ connectionStringBuilder.append("dataChannel={localport=").append(info.getDataChannelLocalPort()).append("};");
352+ }
353+
354+ if (!StringExtensions.isNullOrWhitespace(info.getStartTime()))
355+ connectionStringBuilder.append("startTimeConstraint=").append(info.getStartTime()).append(';');
356+
357+ if (!StringExtensions.isNullOrWhitespace(info.getStopTime()))
358+ connectionStringBuilder.append("stopTimeConstraint=").append(info.getStopTime()).append(';');
359+
360+ if (!StringExtensions.isNullOrWhitespace(info.getConstraintParameters()))
361+ connectionStringBuilder.append("timeConstraintParameters=").append(info.getConstraintParameters()).append(';');
362+
363+ if (!StringExtensions.isNullOrWhitespace(info.getWaitHandleNames()))
364+ {
365+ connectionStringBuilder.append("waitHandleNames=").append(info.getWaitHandleNames()).append(';');
366+ connectionStringBuilder.append("waitHandleTimeout=").append(info.getWaitHandleTimeout()).append(';');
367+ }
368+
369+ if (!StringExtensions.isNullOrWhitespace(info.getExtraConnectionStringParameters()))
370+ connectionStringBuilder.append(info.getExtraConnectionStringParameters()).append(';');
371+
372+ connectionStringBytes = connectionStringBuilder.toString().getBytes(m_characterEncoding);
373+ packetDataSize = 5 + connectionStringBytes.length;
374+ packetData = ByteBuffer.allocate(packetDataSize);
375+
376+ packetData.put((byte)(DataPacketFlags.Compact | (info.isRemotelySynchronized() ? DataPacketFlags.Synchronized : DataPacketFlags.NoFlags)));
377+ packetData.putInt(connectionStringBytes.length);
378+ packetData.put(connectionStringBytes);
379+
380+ sendServerCommand(ServerCommand.Subscribe, packetData.array(), 0, packetDataSize);
381+ }
382+
383+ /**
384+ * Gets a copy of the subscription info currently in use by the subscriber.
385+ *
386+ * @return copy of the subscription info currently in use by the subscriber
387+ */
388+ public SubscriptionInfo getCurrentSubscription()
389+ {
390+ return new SubscriptionInfo(m_currentSubscription);
391+ }
392+
393+ /**
394+ * Unsubscribes to stop receiving data from the publisher.
395+ */
396+ public void unsubscribe()
397+ {
398+ // Notify data channel response
399+ // thread that we are unsubscribing
400+ m_unsubscribing = true;
401+
402+ // Close socket so that data channel
403+ // response thread can finish
404+ if (m_dataChannelSocket != null)
405+ m_dataChannelSocket.close();
406+
407+ // Join with data channel response thread to ensure
408+ // that it finishes before returning from this method
409+ joinThread(m_dataChannelResponseThread);
410+
411+ // Unsubscribe complete
412+ m_unsubscribing = false;
413+
414+ // Notify server to stop sending data
415+ sendServerCommand(ServerCommand.Unsubscribe);
416+ }
417+
418+ /**
419+ * Sends a command to the publisher.
420+ *
421+ * @param commandCode the {@link ServerCommand} code to be sent
422+ */
423+ public void sendServerCommand(byte commandCode)
424+ {
425+ sendServerCommand(commandCode, null, 0, 0);
426+ }
427+
428+ /**
429+ * Sends a command to the publisher over the command channel.
430+ *
431+ * @param commandCode the {@link ServerCommand} code to be sent
432+ * @param data packet data to be sent to the server with the command
433+ * @param offset offset in the buffer at which data sent to the server starts
434+ * @param length amount of data in buffer that gets sent to the server
435+ */
436+ public void sendServerCommand(byte commandCode, byte[] data, int offset, int length)
437+ {
438+ final int PayloadHeaderSize = 8;
439+
440+ int packetSize = 1 + length;
441+ int payloadSize = PayloadHeaderSize + packetSize;
442+ byte[] command = new byte[payloadSize];
443+
444+ // Insert payload marker
445+ command[0] = (byte)0xAA;
446+ command[1] = (byte)0xBB;
447+ command[2] = (byte)0xCC;
448+ command[3] = (byte)0xDD;
449+
450+ // Insert packet size
451+ command[4] = (byte)packetSize;
452+ command[5] = (byte)(packetSize >> 8);
453+ command[6] = (byte)(packetSize >> 16);
454+ command[7] = (byte)(packetSize >> 24);
455+
456+ // Insert command code
457+ command[8] = commandCode;
458+
459+ if (data != null)
460+ ArrayExtensions.blockCopy(data, offset, command, PayloadHeaderSize + 1, length);
461+
462+ m_commandQueue.add(command);
463+ }
464+
465+ /**
466+ * Sends operational modes to the server.
467+ *
468+ * @see #setOperationalModes(int)
469+ * @see #getOperationalModes()
470+ */
471+ public void sendOperationalModes()
472+ {
473+ byte[] commandData = ByteBuffer.allocate(4).putInt(m_operationalModes).array();
474+ sendServerCommand(ServerCommand.DefineOperationalModes, commandData, 0, 4);
475+ }
476+
477+ /**
478+ * Gets the total number of bytes received on
479+ * the command channel since last connection.
480+ *
481+ * @return the total number of bytes received on the command channel
482+ */
483+ public long getTotalCommandChannelBytesReceived()
484+ {
485+ return m_totalCommandChannelBytesReceived;
486+ }
487+
488+ /**
489+ * Gets the total number of bytes received on
490+ * the data channel since last connection.
491+ *
492+ * @return the total number of bytes received on the data channel
493+ */
494+ public long getTotalDataChannelBytesReceived()
495+ {
496+ return m_totalDataChannelBytesReceived;
497+ }
498+
499+ /**
500+ * Gets the total number of measurements
501+ * received since last subscription.
502+ *
503+ * @return the total number of measurements received
504+ */
505+ public long getTotalMeasurementsReceived()
506+ {
507+ return m_totalMeasurementsReceived;
508+ }
509+
510+ /**
511+ * Indicates whether the subscriber is
512+ * currently connected to the publisher.
513+ *
514+ * @return flag indicating whether subscriber is connected
515+ */
516+ public boolean isConnected()
517+ {
518+ return m_connected;
519+ }
520+
521+ /**
522+ * Indicates whether the subscriber is
523+ * currently subscribed to the publisher.
524+ *
525+ * @return flag indicating whether subscriber is subscribed
526+ */
527+ public boolean isSubscribed()
528+ {
529+ return m_subscribed;
530+ }
531+
532+ /**
533+ * Disconnects in case sockets are
534+ * open or threads are still running.
535+ */
536+ @Override
537+ protected void finalize() throws Throwable
538+ {
539+ if (m_connected)
540+ disconnect();
541+ }
542+
543+ // Joins with the given thread, checking for null
544+ // and ignoring possible InterruptedExceptions.
545+ private void joinThread(Thread th)
546+ {
547+ try
548+ {
549+ if (th != null)
550+ th.join();
551+ }
552+ catch(InterruptedException ex)
553+ {
554+ // Ignore exception and
555+ // continue shutdown procedure
556+ }
557+ }
558+
559+ // Creates and starts the command thread.
560+ private void startCommandThread()
561+ {
562+ m_commandThread = new Thread(new Runnable()
563+ {
564+ @Override
565+ public void run()
566+ {
567+ runCommandThread();
568+ }
569+ });
570+
571+ m_commandThread.start();
572+ }
573+
574+ // Creates and starts the callback thread.
575+ private void startCallbackThread()
576+ {
577+ m_callbackThread = new Thread(new Runnable()
578+ {
579+ @Override
580+ public void run()
581+ {
582+ runCallbackThread();
583+ }
584+ });
585+
586+ m_callbackThread.start();
587+ }
588+
589+ // Creates and starts the command channel response thread.
590+ private void startCommandChannelResponseThread()
591+ {
592+ m_commandChannelResponseThread = new Thread(new Runnable()
593+ {
594+ @Override
595+ public void run()
596+ {
597+ runCommandChannelResponseThread();
598+ }
599+ });
600+
601+ m_commandChannelResponseThread.start();
602+ }
603+
604+ // Creates and starts the data channel response thread.
605+ private void startDataChannelResponseThread()
606+ {
607+ m_dataChannelResponseThread = new Thread(new Runnable()
608+ {
609+ @Override
610+ public void run()
611+ {
612+ runDataChannelResponseThread();
613+ }
614+ });
615+
616+ m_dataChannelResponseThread.start();
617+ }
618+
619+ // Sends commands queued by other threads to the publisher.
620+ private void runCommandThread()
621+ {
622+ try
623+ {
624+ OutputStream out = m_commandChannelSocket.getOutputStream();
625+ byte[] command;
626+
627+ while (!m_disconnecting)
628+ {
629+ command = m_commandQueue.poll(PollTimeout, PollTimeoutUnit);
630+
631+ if (command != null)
632+ out.write(command);
633+ }
634+ }
635+ catch (InterruptedException ex)
636+ {
637+ // This thread is internal and
638+ // should never be interrupted
639+ throw new IllegalStateException(ex);
640+ }
641+ catch (IOException ex)
642+ {
643+ if (!m_disconnecting)
644+ dispatchConnectionTerminated(ex);
645+ }
646+ }
647+
648+ // Executes callbacks queued by other threads.
649+ private void runCallbackThread()
650+ {
651+ try
652+ {
653+ Runnable callback;
654+
655+ while (!m_disconnecting)
656+ {
657+ callback = m_callbackQueue.poll(PollTimeout, PollTimeoutUnit);
658+
659+ if (callback != null)
660+ {
661+ try
662+ {
663+ callback.run();
664+ }
665+ catch (Exception ex)
666+ {
667+ dispatchException(ex);
668+ }
669+ }
670+ }
671+ }
672+ catch (InterruptedException ex)
673+ {
674+ // This thread is internal and
675+ // should never be interrupted
676+ throw new IllegalStateException(ex);
677+ }
678+ }
679+
680+ // Processes data received from the publisher on the command channel.
681+ private void runCommandChannelResponseThread()
682+ {
683+ try
684+ {
685+ final int PayloadHeaderSize = 8;
686+
687+ InputStream in = m_commandChannelSocket.getInputStream();
688+
689+ ByteBuffer littleEndianBuffer = ByteBuffer.allocate(PayloadHeaderSize);
690+ ByteBuffer bigEndianBuffer = ByteBuffer.allocate(MaxPacketSize);
691+ int bytesRead;
692+
693+ int payloadBodySize;
694+
695+ littleEndianBuffer.order(ByteOrder.LITTLE_ENDIAN);
696+ bigEndianBuffer.order(ByteOrder.BIG_ENDIAN);
697+
698+ while (true)
699+ {
700+ // Read the payload header from the input stream
701+ bytesRead = InputStreamExtensions.read(in, littleEndianBuffer.array(), 0, PayloadHeaderSize);
702+ m_totalCommandChannelBytesReceived += bytesRead;
703+
704+ if (m_disconnecting || bytesRead < PayloadHeaderSize)
705+ break;
706+
707+ // Skip the 4-byte sync pattern
708+ payloadBodySize = littleEndianBuffer.getInt(4);
709+
710+ // Increase the buffer size, if necessary
711+ if (payloadBodySize > bigEndianBuffer.capacity())
712+ bigEndianBuffer = ByteBuffer.allocate(payloadBodySize);
713+
714+ // Read the packet from the input stream
715+ bytesRead = InputStreamExtensions.read(in, bigEndianBuffer.array(), 0, payloadBodySize);
716+ m_totalCommandChannelBytesReceived += bytesRead;
717+
718+ if (m_disconnecting || bytesRead < payloadBodySize)
719+ break;
720+
721+ // Set the limit on the buffer, process the
722+ // buffer, and then rewind the buffer
723+ bigEndianBuffer.limit(payloadBodySize);
724+ processServerResponse(bigEndianBuffer);
725+ bigEndianBuffer.rewind();
726+ }
727+ }
728+ catch (IOException ex)
729+ {
730+ if (!m_disconnecting)
731+ dispatchConnectionTerminated(ex);
732+ }
733+ }
734+
735+ // Processes data received by the publisher on the data channel.
736+ private void runDataChannelResponseThread()
737+ {
738+ DatagramPacket packet = new DatagramPacket(new byte[MaxPacketSize], MaxPacketSize);
739+
740+ try
741+ {
742+ while (true)
743+ {
744+ m_dataChannelSocket.receive(packet);
745+
746+ if (m_unsubscribing)
747+ break;
748+
749+ if (isValidHostAddress(packet.getAddress()))
750+ {
751+ m_totalDataChannelBytesReceived += packet.getLength();
752+ processServerResponse(ByteBuffer.wrap(packet.getData(), packet.getOffset(), packet.getLength()));
753+ }
754+ }
755+ }
756+ catch (IOException ex)
757+ {
758+ if (!m_unsubscribing)
759+ dispatchException(ex);
760+ }
761+ }
762+
763+ // Delegates data received from the publisher to the proper handler.
764+ private void processServerResponse(ByteBuffer buffer)
765+ {
766+ byte responseCode = buffer.get();
767+ byte commandCode = buffer.get();
768+
769+ // Skip length field in packet header,
770+ // as length has already been determined
771+ // by checking the payload header
772+ buffer.getInt();
773+
774+ switch (responseCode)
775+ {
776+ case ServerResponse.Succeeded:
777+ handleSucceeded(commandCode, buffer);
778+ break;
779+
780+ case ServerResponse.Failed:
781+ handleFailed(commandCode, buffer);
782+ break;
783+
784+ case ServerResponse.DataPacket:
785+ handleDataPacket(buffer);
786+ break;
787+
788+ case ServerResponse.DataStartTime:
789+ handleDataStartTime(buffer);
790+ break;
791+
792+ case ServerResponse.ProcessingComplete:
793+ handleProcessingComplete(buffer);
794+ break;
795+
796+ case ServerResponse.UpdateSignalIndexCache:
797+ handleUpdateSignalIndexCache(buffer);
798+ break;
799+
800+ case ServerResponse.UpdateBaseTimes:
801+ handleUpdateBaseTimes(buffer);
802+ break;
803+ }
804+ }
805+
806+ // Handle success messages from the publisher.
807+ private void handleSucceeded(byte commandCode, ByteBuffer buffer)
808+ {
809+ StringBuilder messageBuilder = new StringBuilder();
810+ String hexCommandCode = Integer.toHexString(commandCode & Masks.getIntMask(Byte.SIZE));
811+
812+ switch (commandCode)
813+ {
814+ case ServerCommand.MetadataRefresh:
815+ // Metadata refresh message is not sent with a
816+ // message, but rather the metadata itself
817+ handleMetadataRefresh(buffer);
818+ break;
819+
820+ case ServerCommand.Subscribe:
821+ case ServerCommand.Unsubscribe:
822+ // Do not break on these messages because there is
823+ // still an associated message to be processed
824+ m_subscribed = (commandCode == ServerCommand.Subscribe);
825+
826+ case ServerCommand.Authenticate:
827+ case ServerCommand.RotateCipherKeys:
828+ // Each of these responses comes with a message that will
829+ // be delivered to the user via the status message callback
830+ messageBuilder.append("Received success code in response to server command 0x").append(hexCommandCode).append(": ");
831+ messageBuilder.append(m_characterEncoding.decode(buffer));
832+
833+ dispatchStatusMessage(messageBuilder.toString());
834+ break;
835+
836+ default:
837+ // If we don't know what the message is, we can't interpret
838+ // the data sent with the packet. Deliver an error message
839+ // to the user via the exception encountered callback
840+ messageBuilder.append("Received success code in response to unknown server command 0x").append(hexCommandCode);
841+ dispatchException(new UnsupportedOperationException(messageBuilder.toString()));
842+ break;
843+ }
844+ }
845+
846+ // Handle failure messages from the publisher.
847+ private void handleFailed(byte commandCode, ByteBuffer buffer)
848+ {
849+ StringBuilder messageBuilder = new StringBuilder();
850+ String hexCommandCode = Integer.toHexString(commandCode & Masks.getIntMask(Byte.SIZE));
851+
852+ messageBuilder.append("Received failure code from server command 0x").append(hexCommandCode).append(": ");
853+ messageBuilder.append(m_characterEncoding.decode(buffer));
854+ dispatchException(new RuntimeException(messageBuilder.toString()));
855+ }
856+
857+ // Handle metadata received from the publisher.
858+ private void handleMetadataRefresh(ByteBuffer buffer)
859+ {
860+ ByteBuffer buf = buffer;
861+
862+ if ((m_operationalModes & OperationalModes.CompressMetadata) != 0)
863+ {
864+ if ((m_operationalModes & OperationalModes.CompressionModeMask) == CompressionMode.GZIP)
865+ {
866+ buf = decompress(buffer);
867+ }
868+ }
869+
870+ dispatchMetadata(m_characterEncoding.decode(buf).toString());
871+ }
872+
873+ // Handle data packets received from the publisher.
874+ private void handleDataPacket(ByteBuffer buffer)
875+ {
876+ GatewayMeasurementParser parser;
877+ Collection<Measurement> newMeasurements;
878+
879+ byte dataPacketFlags;
880+ boolean compactFlag;
881+ boolean syncFlag;
882+ long frameLevelTimestamp = 0L;
883+
884+ SubscriptionInfo info;
885+ boolean includeTime;
886+ boolean useMillisecondResolution;
887+
888+ // Get relevante information about the current subscription
889+ info = m_currentSubscription;
890+ includeTime = info.isTimeIncluded();
891+ useMillisecondResolution = info.isMillisecondResolution();
892+
893+ // Parse the data packet flags
894+ dataPacketFlags = buffer.get();
895+ compactFlag = (dataPacketFlags & DataPacketFlags.Compact) != 0;
896+ syncFlag = (dataPacketFlags & DataPacketFlags.Synchronized) != 0;
897+
898+ // Gather statistics
899+ m_totalMeasurementsReceived += buffer.getInt();
900+
901+ if (syncFlag)
902+ {
903+ frameLevelTimestamp = buffer.getLong();
904+ includeTime = false;
905+ }
906+
907+ if (compactFlag)
908+ {
909+ // If signal index cache is null, we
910+ // cannot parse compact measurements
911+ if (m_signalIndexCache == null)
912+ return;
913+
914+ parser = new CompactMeasurementParser(m_signalIndexCache, m_baseTimeOffsets, includeTime, useMillisecondResolution);
915+ }
916+ else
917+ {
918+ // Not supported; dispatch exception and give up
919+ dispatchException(new UnsupportedOperationException("Non-compact measurement format not supported"));
920+ return;
921+ }
922+
923+ try
924+ {
925+ // Parse measurements and expose them via listener
926+ newMeasurements = parser.parseMeasurements(buffer);
927+
928+ if (syncFlag)
929+ {
930+ // Apply frame-level timestamp
931+ for (Measurement newMeasurement : newMeasurements)
932+ newMeasurement.setTimestamp(frameLevelTimestamp);
933+ }
934+
935+ if (newMeasurements.size() > 0)
936+ dispatchNewMeasurements(newMeasurements);
937+ }
938+ catch (Exception ex)
939+ {
940+ // Notify of exceptions during parse
941+ dispatchException(ex);
942+ }
943+ }
944+
945+ // Handles data start time message received from publisher.
946+ private void handleDataStartTime(ByteBuffer buffer)
947+ {
948+ dispatchDataStartTime(buffer.getLong());
949+ }
950+
951+ // Handles processing complete message received from publisher.
952+ private void handleProcessingComplete(ByteBuffer buffer)
953+ {
954+ dispatchProcessingComplete(m_characterEncoding.decode(buffer).toString());
955+ }
956+
957+ // Updates the signal index cache with new values received from the publisher.
958+ private void handleUpdateSignalIndexCache(ByteBuffer buffer)
959+ {
960+ ByteBuffer buf = buffer;
961+ SignalIndexCache newCache = new SignalIndexCache();
962+ int referenceCount;
963+
964+ short signalIndex;
965+ UUID signalId;
966+ int sourceSize;
967+ String source;
968+ int id;
969+
970+ if ((m_operationalModes & OperationalModes.CompressSignalIndexCache) != 0)
971+ {
972+ if ((m_operationalModes & OperationalModes.CompressionModeMask) == CompressionMode.GZIP)
973+ {
974+ buf = decompress(buffer);
975+ }
976+ }
977+
978+ // Skip 4-byte length and 16-byte subscriber ID
979+ // We may need to parse these in the future...
980+ buf.position(buf.position() + 20);
981+
982+ referenceCount = buf.getInt();
983+
984+ for (int i = 0; i < referenceCount; i++)
985+ {
986+ signalIndex = buf.getShort();
987+ signalId = new UUID(buf.getLong(), buf.getLong());
988+ sourceSize = buf.getInt();
989+ source = m_characterEncoding.decode((ByteBuffer)buf.slice().limit(sourceSize)).toString();
990+ id = ((ByteBuffer)buf.position(buf.position() + sourceSize)).getInt();
991+
992+ newCache.addMeasurementKey(signalIndex, signalId, source, id);
993+ }
994+
995+ m_signalIndexCache = newCache;
996+ }
997+
998+ // Updates the base times with new values received from the publisher.
999+ private void handleUpdateBaseTimes(ByteBuffer buffer)
1000+ {
1001+ // Skip time index
1002+ buffer.getInt();
1003+
1004+ m_baseTimeOffsets = new long[] { buffer.getLong(), buffer.getLong() };
1005+ }
1006+
1007+ // Queues a status message callback.
1008+ private void dispatchStatusMessage(final String message)
1009+ {
1010+ m_callbackQueue.add(new Runnable()
1011+ {
1012+ @Override
1013+ public void run()
1014+ {
1015+ for (SubscriberListener listener : m_subscriberListeners)
1016+ listener.statusMessageReceived(new MessageEvent(DataSubscriber.this, message));
1017+ }
1018+ });
1019+ }
1020+
1021+ // Queues an exception encountered callback.
1022+ private void dispatchException(final Exception exception)
1023+ {
1024+ m_callbackQueue.add(new Runnable()
1025+ {
1026+ @Override
1027+ public void run()
1028+ {
1029+ for (SubscriberListener listener : m_subscriberListeners)
1030+ listener.exceptionEncountered(new MessageEvent(DataSubscriber.this, exception));
1031+ }
1032+ });
1033+ }
1034+
1035+ // Queues a data start time received callback.
1036+ private void dispatchDataStartTime(final long dataStartTime)
1037+ {
1038+ m_callbackQueue.add(new Runnable()
1039+ {
1040+ @Override
1041+ public void run()
1042+ {
1043+ for (SubscriberListener listener : m_subscriberListeners)
1044+ listener.dataStartTimeReceived(new StartTimeEvent(DataSubscriber.this, dataStartTime));
1045+ }
1046+ });
1047+ }
1048+
1049+ // Queues a metadata received callback.
1050+ private void dispatchMetadata(final byte[] compressedMetadata)
1051+ {
1052+ m_callbackQueue.add(new Runnable()
1053+ {
1054+ @Override
1055+ public void run()
1056+ {
1057+ for (SubscriberListener listener : m_subscriberListeners)
1058+ listener.metadataReceived(new MetadataEvent(DataSubscriber.this, compressedMetadata));
1059+ }
1060+ });
1061+ }
1062+
1063+ // Queues a metadata received callback.
1064+ private void dispatchMetadata(final String xmlMetadata)
1065+ {
1066+ m_callbackQueue.add(new Runnable()
1067+ {
1068+ @Override
1069+ public void run()
1070+ {
1071+ for (SubscriberListener listener : m_subscriberListeners)
1072+ listener.metadataReceived(new MetadataEvent(DataSubscriber.this, xmlMetadata));
1073+ }
1074+ });
1075+ }
1076+
1077+ // Queues a new measurements callback.
1078+ private void dispatchNewMeasurements(final Collection<Measurement> newMeasurements)
1079+ {
1080+ m_callbackQueue.add(new Runnable()
1081+ {
1082+ @Override
1083+ public void run()
1084+ {
1085+ for (SubscriberListener listener : m_subscriberListeners)
1086+ listener.newMeasurementsReceived(new MeasurementEvent(DataSubscriber.this, newMeasurements));
1087+ }
1088+ });
1089+ }
1090+
1091+ // Queues a processing complete callback.
1092+ private void dispatchProcessingComplete(final String message)
1093+ {
1094+ m_callbackQueue.add(new Runnable()
1095+ {
1096+ @Override
1097+ public void run()
1098+ {
1099+ for (SubscriberListener listener : m_subscriberListeners)
1100+ listener.processingCompleteCallback(new MessageEvent(DataSubscriber.this, message));
1101+ }
1102+ });
1103+ }
1104+
1105+ // Executes a connection terminated callback on a separate thread.
1106+ private void dispatchConnectionTerminated(final Exception ex)
1107+ {
1108+ Thread connectionTerminatedThread = new Thread()
1109+ {
1110+ @Override
1111+ public void run()
1112+ {
1113+ disconnect();
1114+
1115+ for (SubscriberListener listener : m_subscriberListeners)
1116+ listener.connectionTerminated(new MessageEvent(DataSubscriber.this, ex));
1117+ }
1118+ };
1119+
1120+ connectionTerminatedThread.start();
1121+ }
1122+
1123+ // Decompresses the data in the given buffer.
1124+ private ByteBuffer decompress(ByteBuffer buffer)
1125+ {
1126+ ByteArrayInputStream inputStream = null;
1127+ GZIPInputStream inflater = null;
1128+ ArrayList<Byte> byteList;
1129+ byte[] swap;
1130+ int bytesRead;
1131+
1132+ try
1133+ {
1134+ inputStream = new ByteArrayInputStream(buffer.array(), buffer.position() + buffer.arrayOffset(), buffer.remaining());
1135+ inflater = new GZIPInputStream(inputStream);
1136+ byteList = new ArrayList<Byte>((int)(buffer.remaining() * 1.5));
1137+ swap = new byte[1024];
1138+
1139+ do
1140+ {
1141+ // Decompress data and place it into swap array.
1142+ bytesRead = inflater.read(swap, 0, swap.length);
1143+
1144+ // Swap the decompressed data into the byte list.
1145+ for (int i = 0; i < bytesRead; i++)
1146+ byteList.add(swap[i]);
1147+ } while (bytesRead > 0);
1148+
1149+ // Increase swap size to contain the fully decompressed data.
1150+ swap = new byte[byteList.size()];
1151+
1152+ // Copy the data into the swap array.
1153+ for (int i = 0; i < swap.length; i++)
1154+ swap[i] = byteList.get(i);
1155+
1156+ return ByteBuffer.wrap(swap);
1157+ }
1158+ catch (IOException ex)
1159+ {
1160+
1161+ dispatchException(ex);
1162+ }
1163+ finally
1164+ {
1165+ try
1166+ {
1167+ // Attempt to close the input
1168+ // streams to release resources.
1169+ if (inflater != null)
1170+ inflater.close();
1171+
1172+ if (inputStream != null)
1173+ inputStream.close();
1174+ } catch (IOException ex)
1175+ {
1176+ dispatchException(ex);
1177+ }
1178+ }
1179+
1180+ return buffer;
1181+ }
1182+
1183+ // Determines whether the given IP address is
1184+ // valid for the currently connected host.
1185+ private boolean isValidHostAddress(InetAddress address)
1186+ {
1187+ // If it equals the cached host address, simply return
1188+ if (m_hostAddress.equals(address))
1189+ return true;
1190+
1191+ // Check all valid host addresses
1192+ for (InetAddress hostAddress : m_allHostAddresses)
1193+ {
1194+ if (hostAddress.equals(address))
1195+ {
1196+ // Cache this address so we hopefully
1197+ // don't have to loop every time
1198+ m_hostAddress = hostAddress;
1199+ return true;
1200+ }
1201+ }
1202+
1203+ // Address is not valid
1204+ return false;
1205+ }
1206+
1207+ // Maximum possible packet size to be received on the data channel.
1208+ private static final int MaxPacketSize = 32767;
1209+
1210+ private static final long PollTimeout = 1L;
1211+ private static final TimeUnit PollTimeoutUnit = TimeUnit.SECONDS;
1212+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/GatewayMeasurementParser.java+56−0
@@ -0,0 +1,56 @@
1+//******************************************************************************************************
2+// GatewayMeasurementParser.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/12/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport;
25+
26+import java.nio.ByteBuffer;
27+import java.util.Collection;
28+
29+import org.gpa.tsf.Measurement;
30+
31+/**
32+ * Represents the interface used by the {@link DataSubscriber} to parse
33+ * measurements from the publisher.
34+ */
35+public interface GatewayMeasurementParser
36+{
37+ /**
38+ * Parses a collection of serialized measurements from a byte array.
39+ *
40+ * @param serializedMeasurements the serialized measurements to be parsed
41+ * @param offset the offset into the array at which the collection starts
42+ * @param length the byte length of the collection of serialized measurements
43+ * @return the collection of parsed measurements
44+ */
45+ Collection<Measurement> parseMeasurements(byte[] serializedMeasurements, int offset, int length);
46+
47+ /**
48+ * Parses a collection of serialized measurements from a byte buffer.
49+ *
50+ * @param serializedMeasurementBuffer The serialized measurements to be parsed.
51+ * This method uses relative get operations on the buffer until there is
52+ * no longer enough data left to parse any more measurements.
53+ * @return the collection of parsed measurements
54+ */
55+ Collection<Measurement> parseMeasurements(ByteBuffer serializedMeasurementBuffer);
56+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/SignalIndexCache.java+128−0
@@ -0,0 +1,128 @@
1+//******************************************************************************************************
2+// SignalIndexCache.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/12/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport;
25+
26+import java.util.HashMap;
27+import java.util.Map;
28+import java.util.UUID;
29+
30+import org.gpa.tsf.MeasurementKey;
31+
32+/**
33+ * Represents a cache used to map 16-bit indexes to {@link MeasurementKey}s
34+ * in order to compact measurement IDs for the compact measurement format.
35+ */
36+public class SignalIndexCache
37+{
38+ private Map<Short, MeasurementKey> m_reference;
39+ private Map<UUID, Short> m_signalIdCache;
40+
41+ /**
42+ * Constructs a new signal index cache.
43+ */
44+ public SignalIndexCache()
45+ {
46+ m_reference = new HashMap<Short, MeasurementKey>();
47+ m_signalIdCache = new HashMap<UUID, Short>();
48+ }
49+
50+ /**
51+ * Adds a measurement key to the signal index
52+ * cache, identified by the given signal index.
53+ *
54+ * @param signalIndex the 16-bit index by which the
55+ * measurement key can be retrieved from the cache
56+ * @param signalId the measurement's globally unique identifier
57+ * @param source the measurement's source
58+ * @param id the measurement's simple numeric identifier
59+ * @throws IllegalArgumentException if the given {@code signalID} is
60+ * {@code null} or the given {@code source} is {@code null} or
61+ * empty
62+ */
63+ public void addMeasurementKey(short signalIndex, UUID signalId, String source, int id)
64+ {
65+ addMeasurementKey(signalIndex, new MeasurementKey(signalId, source, id));
66+ }
67+
68+ /**
69+ * Adds a measurement key to the signal index
70+ * cache, identified by the given signal index.
71+ *
72+ * @param signalIndex the 16-bit index by which the
73+ * measurement key can be retrieved from the cache
74+ * @param key the measurement key to be placed in the cache
75+ */
76+ public void addMeasurementKey(short signalIndex, MeasurementKey key)
77+ {
78+ m_reference.put(signalIndex, key);
79+ m_signalIdCache.put(key.getSignalId(), signalIndex);
80+ }
81+
82+ /**
83+ * Empties the signal index cache.
84+ */
85+ public void clear()
86+ {
87+ m_reference.clear();
88+ m_signalIdCache.clear();
89+ }
90+
91+ /**
92+ * Determines whether a measurement key exists
93+ * in the cache for the given signal index.
94+ *
95+ * @param signalIndex the signal index to be searched for
96+ * @return true if the signal index refers to
97+ * a measurement key; false otherwise
98+ */
99+ public boolean contains(short signalIndex)
100+ {
101+ return m_reference.containsKey(signalIndex);
102+ }
103+
104+ /**
105+ * Gets the measurement key identified by the given signal index.
106+ *
107+ * @param signalIndex the signal index which identifies the measurement key
108+ * @return the measurement key identified by the given signal index,
109+ * or {@code null} if no mapping exists for the signal index
110+ */
111+ public MeasurementKey getMeasurementKey(short signalIndex)
112+ {
113+ return m_reference.get(signalIndex);
114+ }
115+
116+ /**
117+ * Provides a backwards mapping from the globally unique identifiers
118+ * of the measurements whose keys are stored in the cache to the
119+ * signal indexes that refer to them.
120+ *
121+ * @param signalId the measurement's globally unique identifier
122+ * @return the signal index which identifies the measurement key
123+ */
124+ short getSignalIndex(UUID signalId)
125+ {
126+ return m_signalIdCache.get(signalId);
127+ }
128+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/SubscriberConnector.java+356−0
@@ -0,0 +1,356 @@
1+//******************************************************************************************************
2+// SubscriberConnector.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/23/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport;
25+
26+import java.util.ArrayList;
27+import java.util.Collection;
28+
29+import org.gpa.tsf.transport.event.MessageEvent;
30+import org.gpa.tsf.transport.event.SubscriberAdapter;
31+import org.gpa.tsf.transport.event.SubscriberConnectorListener;
32+import org.gpa.tsf.transport.event.SubscriberEvent;
33+import org.gpa.tsf.transport.event.SubscriberListener;
34+
35+/**
36+ * Helper class to provide retry and auto-reconnect
37+ * functionality to the subscriber.
38+ *
39+ * @see DataSubscriber
40+ */
41+public class SubscriberConnector
42+{
43+ Collection<SubscriberConnectorListener> m_listeners;
44+ private DataSubscriber m_subscriber;
45+ private SubscriberListener m_autoReconnectHandler;
46+
47+ private String m_hostname;
48+ private int m_port;
49+
50+ private int m_maxRetries;
51+ private int m_retryInterval;
52+ private boolean m_autoReconnect;
53+
54+ private boolean m_cancel;
55+
56+ /**
57+ * Constructs a new instance. The default configuration is infinite
58+ * retries on a 2-second interval, and auto-reconnect is on.
59+ */
60+ public SubscriberConnector()
61+ {
62+ m_maxRetries = -1;
63+ m_retryInterval = 2000;
64+ m_autoReconnect = true;
65+
66+ m_listeners = new ArrayList<SubscriberConnectorListener>();
67+ }
68+
69+ /**
70+ * Adds the given listener to receive events from this subscriber
71+ * connector. If the {@code listener} is {@code null}, no exception
72+ * is thrown and no action is performed.
73+ *
74+ * @param listener the listener to be added
75+ */
76+ public void addSubscriberConnectorListener(SubscriberConnectorListener listener)
77+ {
78+ if (listener != null)
79+ m_listeners.add(listener);
80+ }
81+
82+ /**
83+ * Removes the given listener so that it no longer receives events
84+ * from this subscriber connector. This method performs no function,
85+ * nor does it throw an exception, if {@code subscriberListener} was
86+ * not previously added to this component. If {@code subscriberListener}
87+ * is {@code null}, no exception is thrown and no action is performed.
88+ *
89+ * @param listener the listener to be removed
90+ */
91+ public void removeSubscriberConnectorListener(SubscriberConnectorListener listener)
92+ {
93+ if (listener != null)
94+ m_listeners.remove(listener);
95+ }
96+
97+ /**
98+ * Begins the connection sequence.
99+ *
100+ * @param subscriber the subscriber to be connected
101+ * @return connected status of the subscriber
102+ * @throws IllegalArgumentException if {@code subscriber} is {@code null}
103+ */
104+ public boolean connect(DataSubscriber subscriber)
105+ {
106+ if (subscriber == null)
107+ throw new IllegalArgumentException("subscriber must not be null");
108+
109+ // If we are no longer set to auto reconnect, we
110+ // may need to detach from an existing subscriber.
111+ if (!m_autoReconnect && m_subscriber != null)
112+ {
113+ m_subscriber.removeSubscriberListener(m_autoReconnectHandler);
114+ m_subscriber = null;
115+ }
116+
117+ // If we are set to auto reconnect and we are not currently
118+ // attached to the given subscriber, we need to attach to the
119+ // new subscriber.
120+ if (m_autoReconnect && m_subscriber != subscriber)
121+ {
122+ if (m_subscriber != null)
123+ m_subscriber.removeSubscriberListener(m_autoReconnectHandler);
124+
125+ if (m_autoReconnectHandler == null)
126+ m_autoReconnectHandler = getNewAutoReconnectHandler();
127+
128+ m_subscriber = subscriber;
129+ subscriber.addSubscriberListener(m_autoReconnectHandler);
130+ }
131+
132+ // Attempt to connect for the given number of retries.
133+ for (int i = 0; !m_cancel && (m_maxRetries == -1 || i < m_maxRetries); i++)
134+ {
135+ try
136+ {
137+ subscriber.connect(m_hostname, m_port);
138+ break;
139+ }
140+ catch (Exception ex)
141+ {
142+ triggerExceptionEncounteredAsync(ex);
143+ sleep(m_retryInterval);
144+ }
145+ }
146+
147+ // Return connection status of subscriber.
148+ return subscriber.isConnected();
149+ }
150+
151+ /**
152+ * Cancels all current and future connection sequences.
153+ */
154+ public void cancel()
155+ {
156+ m_cancel = true;
157+
158+ if (m_subscriber != null)
159+ m_subscriber.removeSubscriberListener(m_autoReconnectHandler);
160+ }
161+
162+ /**
163+ * Gets the hostname of the server this connector is connecting to.
164+ *
165+ * @return the hostname of the server
166+ */
167+ public String getHostname()
168+ {
169+ return m_hostname;
170+ }
171+
172+ /**
173+ * Sets the hostname of the server this connector is connecting to.
174+ *
175+ * @param hostname the new value for the hostname of the server
176+ */
177+ public void setHostname(String hostname)
178+ {
179+ m_hostname = hostname;
180+ }
181+
182+ /**
183+ * Gets the port that the publisher is listening on.
184+ *
185+ * @return the port that the publisher is listening on
186+ */
187+ public int getPort()
188+ {
189+ return m_port;
190+ }
191+
192+ /**
193+ * Sets the port that the publisher is listening on.
194+ *
195+ * @param port the new value for the port that the publisher
196+ * is listening on
197+ */
198+ public void setPort(int port)
199+ {
200+ m_port = port;
201+ }
202+
203+ /**
204+ * Gets the maximum number of connection attempts to be made before
205+ * giving up. A value of {@code -1} means an infinite number of retries.
206+ *
207+ * @return the maximum number of retries during a connection sequence
208+ */
209+ public int getMaxRetries()
210+ {
211+ return m_maxRetries;
212+ }
213+
214+ /**
215+ * Sets the maximum number of connection attempts to be made before
216+ * giving up. A value of {@code -1} means an infinite number of retries.
217+ *
218+ * @param maxRetries the new value for the maximum number of retries
219+ */
220+ public void setMaxRetries(int maxRetries)
221+ {
222+ m_maxRetries = maxRetries;
223+ }
224+
225+ /**
226+ * Gets the interval of time, in milliseconds, between
227+ * each connection attempt during a connection sequence.
228+ *
229+ * @return the retry interval, in milliseconds
230+ */
231+ public int getRetryInterval()
232+ {
233+ return m_retryInterval;
234+ }
235+
236+ /**
237+ * Sets the interval of time, in milliseconds, between
238+ * each connection attempt during a connection sequence.
239+ *
240+ * @param retryInterval the new value for the retry interval,
241+ * in milliseconds
242+ */
243+ public void setRetryInterval(int retryInterval)
244+ {
245+ m_retryInterval = retryInterval;
246+ }
247+
248+ /**
249+ * Gets the flag that indicates whether this connector should
250+ * automatically attempt to reconnect the subscriber when the
251+ * connection is terminated.
252+ *
253+ * @return the auto-reconnect flag
254+ */
255+ public boolean isAutoReconnect()
256+ {
257+ return m_autoReconnect;
258+ }
259+
260+ /**
261+ * Sets the flag that indicates whether this connector should
262+ * automatically attempt to reconnect the subscriber when the
263+ * connection is terminated.
264+ *
265+ * @param autoReconnect the new value for the auto-reconnect flag
266+ */
267+ public void setAutoReconnect(boolean autoReconnect)
268+ {
269+ m_autoReconnect = autoReconnect;
270+ }
271+
272+ // Creates and returns a new auto-reconnect handler.
273+ private SubscriberListener getNewAutoReconnectHandler()
274+ {
275+ return new SubscriberAdapter()
276+ {
277+ @Override
278+ public void connectionTerminated(MessageEvent evt)
279+ {
280+ if (m_autoReconnect)
281+ {
282+ if (!m_cancel)
283+ triggerExceptionEncountered(evt.getException());
284+
285+ connect(m_subscriber);
286+
287+ if (!m_cancel)
288+ triggerReconnected();
289+ }
290+ }
291+ };
292+ }
293+
294+ // Triggers the exceptionEncountered event for
295+ // all listeners subscribed to this connector.
296+ // The event is triggered on a separate thread.
297+ private void triggerExceptionEncounteredAsync(final Exception ex)
298+ {
299+ new Thread(new Runnable()
300+ {
301+ @Override
302+ public void run()
303+ {
304+ triggerExceptionEncountered(ex);
305+ }
306+ }).start();
307+ }
308+
309+ // Triggers the exceptionEncountered event for
310+ // all listeners subscribed to this connector.
311+ private void triggerExceptionEncountered(Exception encounteredException)
312+ {
313+ for (SubscriberConnectorListener listener : m_listeners)
314+ {
315+ try
316+ {
317+ listener.exceptionEncountered(new MessageEvent(this, encounteredException));
318+ }
319+ catch (Exception ex)
320+ {
321+ // Ignore exceptions encountered
322+ // while reporting exceptions
323+ }
324+ }
325+ }
326+
327+ // Triggers the reconnected event for all
328+ // listeners subscribed to this connector.
329+ private void triggerReconnected()
330+ {
331+ for (SubscriberConnectorListener listener : m_listeners)
332+ {
333+ try
334+ {
335+ listener.reconnected(new SubscriberEvent(this, m_subscriber));
336+ }
337+ catch (Exception ex)
338+ {
339+ triggerExceptionEncountered(ex);
340+ }
341+ }
342+ }
343+
344+ // Puts the current thread to sleep for the given period of time.
345+ private void sleep(long millis)
346+ {
347+ try
348+ {
349+ Thread.sleep(millis);
350+ }
351+ catch (InterruptedException ex)
352+ {
353+ triggerExceptionEncountered(ex);
354+ }
355+ }
356+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/SubscriptionInfo.java+563−0
@@ -0,0 +1,563 @@
1+//******************************************************************************************************
2+// SubscriptionInfo.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport;
25+
26+/**
27+ * Configuration object for data subscriptions.
28+ *
29+ * @see DataSubscriber
30+ * @see DataSubscriber#subscribe(SubscriptionInfo)
31+ */
32+public class SubscriptionInfo
33+{
34+ private String m_filterExpression;
35+
36+ private boolean m_remotelySynchronized;
37+ private boolean m_throttled;
38+
39+ private boolean m_udpDataChannel;
40+ private int m_dataChannelLocalPort;
41+
42+ private boolean m_timeIncluded;
43+ private double m_lagTime;
44+ private double m_leadTime;
45+ private boolean m_localClockAsRealTime;
46+ private boolean m_millisecondResolution;
47+
48+ private String m_startTime;
49+ private String m_stopTime;
50+ private String m_constraintParameters;
51+ private int m_processingInterval;
52+
53+ private String m_waitHandleNames;
54+ private int m_waitHandleTimeout;
55+
56+ private String m_extraConnectionStringParameters;
57+
58+ /**
59+ * Constructs a new subscription info.
60+ * The following default values have been overwritten.
61+ *
62+ * <ul>
63+ * <li>{@code DataChannelLocalPort = 9500}</li>
64+ * <li>{@code IncludeTime = true}</li>
65+ * <li>{@code LagTime = 10.0}</li>
66+ * <li>{@code LeadTime = 5.0}</li>
67+ * <li>{@code ProcessingInterval = -1}</li>
68+ * </ul>
69+ */
70+ public SubscriptionInfo()
71+ {
72+ m_dataChannelLocalPort = 9500;
73+ m_timeIncluded = true;
74+ m_lagTime = 10.0;
75+ m_leadTime = 5.0;
76+ m_processingInterval = -1;
77+ }
78+
79+ /**
80+ * Constructs a new subscription info object that
81+ * is a copy of an existing subscription info object.
82+ *
83+ * @param info the subscription info to be copied
84+ */
85+ public SubscriptionInfo(SubscriptionInfo info)
86+ {
87+ m_filterExpression = info.m_filterExpression;
88+
89+ m_remotelySynchronized = info.m_remotelySynchronized;
90+ m_throttled = info.m_throttled;
91+
92+ m_udpDataChannel = info.m_udpDataChannel;
93+ m_dataChannelLocalPort = info.m_dataChannelLocalPort;
94+
95+ m_timeIncluded = info.m_timeIncluded;
96+ m_lagTime = info.m_lagTime;
97+ m_leadTime = info.m_leadTime;
98+ m_localClockAsRealTime = info.m_localClockAsRealTime;
99+ m_millisecondResolution = info.m_millisecondResolution;
100+
101+ m_startTime = info.m_startTime;
102+ m_stopTime = info.m_stopTime;
103+ m_constraintParameters = info.m_constraintParameters;
104+ m_processingInterval = info.m_processingInterval;
105+
106+ m_waitHandleNames = info.m_waitHandleNames;
107+ m_waitHandleTimeout = info.m_waitHandleTimeout;
108+
109+ m_extraConnectionStringParameters = info.m_extraConnectionStringParameters;
110+ }
111+
112+ /**
113+ * Gets the filter expression used to define which
114+ * measurements are being requested by the subscriber.
115+ *
116+ * @return the filter expression
117+ * @see #setFilterExpression(String)
118+ */
119+ public String getFilterExpression()
120+ {
121+ return m_filterExpression;
122+ }
123+
124+ /**
125+ * Sets the filter expression used to define which
126+ * measurements are being requested by the subscriber.
127+ *
128+ * @param filterExpression the new value for the filter expression
129+ * @see #getFilterExpression()
130+ */
131+ public void setFilterExpression(String filterExpression)
132+ {
133+ m_filterExpression = filterExpression;
134+ }
135+
136+ /**
137+ * Gets the flag that indicates whether the subscriber is requesting
138+ * that its measurements be synchronized by the publisher.
139+ *
140+ * @return the flag that indicates whether the subscriber is requesting
141+ * that its measurements be synchronized by the publisher
142+ * @see #setRemotelySynchronized(boolean)
143+ */
144+ public boolean isRemotelySynchronized()
145+ {
146+ return m_remotelySynchronized;
147+ }
148+
149+ /**
150+ * Sets the flag that indicates whether the subscriber is requesting
151+ * that its measurements be synchronized by the publisher.
152+ *
153+ * @param remotelySynchronized the new value of the flag that indicates
154+ * whether the subscriber is requesting that its measurements be
155+ * synchronized by the publisher
156+ * @see #isRemotelySynchronized()
157+ */
158+ public void setRemotelySynchronized(boolean remotelySynchronized)
159+ {
160+ m_remotelySynchronized = remotelySynchronized;
161+ }
162+
163+ /**
164+ * Gets a flag indicating whether the
165+ * requested position is to be throttled.
166+ *
167+ * @return flag indicating whether the subscription is throttled
168+ * @see #setThrottled(boolean)
169+ */
170+ public boolean isThrottled()
171+ {
172+ return m_throttled;
173+ }
174+
175+ /**
176+ * Sets the flag which determines whether to
177+ * request that the subscription be throttled.
178+ *
179+ * @param throttled the new value for the flag
180+ * @see #isThrottled()
181+ */
182+ public void setThrottled(boolean throttled)
183+ {
184+ m_throttled = throttled;
185+ }
186+
187+ /**
188+ * Gets the flag which indicates whether the subscriber is
189+ * requesting its data over a separate UDP data channel.
190+ *
191+ * @return the flag which indicates whether the subscriber is
192+ * requesting its data over a separate UDP data channel
193+ * @see #setUdpDataChannel(boolean)
194+ */
195+ public boolean isUdpDataChannel()
196+ {
197+ return m_udpDataChannel;
198+ }
199+
200+ /**
201+ * Sets the flag which determines whether the subscriber is
202+ * requesting its data over a separate UDP data channel.
203+ *
204+ * @param udpDataChannel the new value for the flag
205+ * @see #isUdpDataChannel()
206+ */
207+ public void setUdpDataChannel(boolean udpDataChannel)
208+ {
209+ m_udpDataChannel = udpDataChannel;
210+ }
211+
212+ /**
213+ * Gets the port that the UDP data channel binds to. This value is
214+ * only used when the subscriber requests a separate UDP data channel.
215+ *
216+ * @return the local port that the UDP data channel binds to
217+ * @see #setDataChannelLocalPort(int)
218+ * @see #isUdpDataChannel()
219+ */
220+ public int getDataChannelLocalPort()
221+ {
222+ return m_dataChannelLocalPort;
223+ }
224+
225+ /**
226+ * Sets the port that the UDP data channel binds to. This value is
227+ * only used when the subscriber requests a separate UDP data channel.
228+ *
229+ * @param dataChannelLocalPort
230+ * @see #getDataChannelLocalPort()
231+ * @see #setUdpDataChannel(boolean)
232+ */
233+ public void setDataChannelLocalPort(int dataChannelLocalPort)
234+ {
235+ m_dataChannelLocalPort = dataChannelLocalPort;
236+ }
237+
238+ /**
239+ * Gets the flag indicating whether timestamps are included in the
240+ * data sent from the publisher. This value is ignored if the data
241+ * is remotely synchronized.
242+ *
243+ * @return the flag indicating whether timestamps are included
244+ * @see #setTimeIncluded(boolean)
245+ */
246+ public boolean isTimeIncluded()
247+ {
248+ return m_timeIncluded;
249+ }
250+
251+ /**
252+ * Sets the flag which determines whether timestamps are included in
253+ * the data sent from the publisher. This value is ignored if the data
254+ * is remotely synchronized.
255+ *
256+ * @param timeIncluded the new value for the flag
257+ * @see #isTimeIncluded()
258+ */
259+ public void setTimeIncluded(boolean timeIncluded)
260+ {
261+ m_timeIncluded = timeIncluded;
262+ }
263+
264+ /**
265+ * Gets the allowed past time deviation tolerance, in seconds.
266+ *
267+ * @return the allowed past time deviation tolerance
268+ * @see #setLagTime(double)
269+ */
270+ public double getLagTime()
271+ {
272+ return m_lagTime;
273+ }
274+
275+ /**
276+ * Sets the allowed past time deviation
277+ * tolerance, in seconds (can be subscecond).
278+ *
279+ * @param lagTime the new value for the allowed
280+ * past time deviation tolerance
281+ * @see #getLagTime()
282+ */
283+ public void setLagTime(double lagTime)
284+ {
285+ m_lagTime = lagTime;
286+ }
287+
288+ /**
289+ * Gets the allowed future time deviation tolerance, in seconds.
290+ *
291+ * @return the allowed future time deviation tolerance
292+ * @see #setLeadTime(double)
293+ */
294+ public double getLeadTime()
295+ {
296+ return m_leadTime;
297+ }
298+
299+ /**
300+ * Sets the allowed future time deviation
301+ * tolerance, in seconds (can be subsecond).
302+ *
303+ * @param leadTime the new value for the allowed
304+ * future time deviation tolerance
305+ * @see #getLeadTime()
306+ */
307+ public void setLeadTime(double leadTime)
308+ {
309+ m_leadTime = leadTime;
310+ }
311+
312+ /**
313+ * Gets the flag that indicates whether the server's local clock is
314+ * used as real-time. Otherwise, the timestamps of the measurements
315+ * will be used as real-time.
316+ *
317+ * @return the flag that indicates whether the server's local clock
318+ * is used as real-time
319+ * @see #setLocalClockAsRealTime(boolean)
320+ */
321+ public boolean isLocalClockAsRealTime()
322+ {
323+ return m_localClockAsRealTime;
324+ }
325+
326+ /**
327+ * Sets the flag which determines whether the server's local clock is
328+ * used as real-time. Otherwise, the timestamps of the measurements
329+ * will be used as real-time.
330+ *
331+ * @param localClockAsRealTime the new value for the flag
332+ * @see #isLocalClockAsRealTime()
333+ */
334+ public void setLocalClockAsRealTime(boolean localClockAsRealTime)
335+ {
336+ m_localClockAsRealTime = localClockAsRealTime;
337+ }
338+
339+ /**
340+ * Gets the flag that indicates whether measurement timestamps use
341+ * millisecond resolution. Otherwise, they will use 100-nanosecond
342+ * resolution.
343+ * <p>
344+ * This flag determines the size of the timestamps transmitted as
345+ * part of the compact measurement format when the server is using
346+ * base time offsets.
347+ *
348+ * @return the flag that indicates whether measurement timestamps use
349+ * millisecond resolution
350+ * @see #setMillisecondResolution(boolean)
351+ */
352+ public boolean isMillisecondResolution()
353+ {
354+ return m_millisecondResolution;
355+ }
356+
357+ /**
358+ * Gets the flag that indicates whether measurement timestamps use
359+ * millisecond resolution. Otherwise, they will use 100-nanosecond
360+ * resolution.
361+ * <p>
362+ * This flag determines the size of the timestamps transmitted as
363+ * part of the compact measurement format when the server is using
364+ * base time offsets.
365+ *
366+ * @param millisecondResolution the new value for the flag
367+ * @see #isMillisecondResolution()
368+ */
369+ public void setMillisecondResolution(boolean millisecondResolution)
370+ {
371+ m_millisecondResolution = millisecondResolution;
372+ }
373+
374+ /**
375+ * Gets the start time of the requested temporal
376+ * session for streaming historic data.
377+ *
378+ * @return the start time of the requested temporal session
379+ * @see #setStartTime(String)
380+ * @see #getStopTime()
381+ * @see #getConstraintParameters()
382+ */
383+ public String getStartTime()
384+ {
385+ return m_startTime;
386+ }
387+
388+ /**
389+ * Sets the start time of the requested temporal
390+ * session for streaming historic data.
391+ *
392+ * @param startTime the new value for the start time
393+ * @see #getStartTime()
394+ * @see #setStopTime(String)
395+ * @see #setConstraintParameters(String)
396+ */
397+ public void setStartTime(String startTime)
398+ {
399+ m_startTime = startTime;
400+ }
401+
402+ /**
403+ * Gets the stop time of the requested temporal
404+ * session for streaming historic data.
405+ *
406+ * @return the stop time of the requested temporal session
407+ * @see #setStopTime(String)
408+ * @see #getStartTime()
409+ * @see #getConstraintParameters()
410+ */
411+ public String getStopTime()
412+ {
413+ return m_stopTime;
414+ }
415+
416+ /**
417+ * Sets the stop time of the requested temporal
418+ * session for streaming historic data.
419+ *
420+ * @param stopTime the new value for the stop time
421+ * @see #getStopTime()
422+ * @see #setStartTime(String)
423+ * @see #setConstraintParameters(String)
424+ */
425+ public void setStopTime(String stopTime)
426+ {
427+ m_stopTime = stopTime;
428+ }
429+
430+ /**
431+ * Gets the additional constraint parameters supplied
432+ * to temporal adapters in a temporal session.
433+ *
434+ * @return the additional constraint parameters for temporal adapters
435+ * @see #setConstraintParameters(String)
436+ * @see #getStartTime()
437+ * @see #getStopTime()
438+ */
439+ public String getConstraintParameters()
440+ {
441+ return m_constraintParameters;
442+ }
443+
444+ /**
445+ * Sets the additional constraint parameters supplied
446+ * to temporal adapters in a temporal session.
447+ *
448+ * @param constraintParameters the new value for the additional parameters
449+ * @see #getConstraintParameters()
450+ * @see #setStartTime(String)
451+ * @see #setStopTime(String)
452+ */
453+ public void setConstraintParameters(String constraintParameters)
454+ {
455+ m_constraintParameters = constraintParameters;
456+ }
457+
458+ /**
459+ * Gets the processing interval requested by the subscriber. A value
460+ * of {@code -1} indicates the default processing interval. A value
461+ * of {@code 0} indicates data will be processed as fast as possible.
462+ *
463+ * @return the processing interval requested by the subscriber
464+ * @see #setProcessingInterval(int)
465+ */
466+ public int getProcessingInterval()
467+ {
468+ return m_processingInterval;
469+ }
470+
471+ /**
472+ * Sets the processing interval requested by the subscriber. A value
473+ * of {@code -1} indicates the default processing interval. A value
474+ * of {@code 0} indicates data will be processed as fast as possible.
475+ *
476+ * @param processingInterval the new value for the processing interval
477+ * @see #getProcessingInterval()
478+ */
479+ public void setProcessingInterval(int processingInterval)
480+ {
481+ m_processingInterval = processingInterval;
482+ }
483+
484+ /**
485+ * Gets the wait handle names used to deterministically wait for data
486+ * to become available on the server side.
487+ *
488+ * @return the wait handle names
489+ * @see #setWaitHandleNames(String)
490+ * @see #getWaitHandleTimeout()
491+ */
492+ public String getWaitHandleNames()
493+ {
494+ return m_waitHandleNames;
495+ }
496+
497+ /**
498+ * Sets the wait handle names used to deterministically wait for data
499+ * to become available on the server side.
500+ *
501+ * @param waitHandleNames the new value for the wait handle names
502+ * @see #getWaitHandleNames()
503+ * @see #setWaitHandleTimeout(int)
504+ */
505+ public void setWaitHandleNames(String waitHandleNames)
506+ {
507+ m_waitHandleNames = waitHandleNames;
508+ }
509+
510+ /**
511+ * Gets the amount of time to wait on the wait handles identified by
512+ * the wait handle names before the operation times out.
513+ *
514+ * @return the amount of time to wait on the wait handles before timing out
515+ * @see #setWaitHandleTimeout(int)
516+ * @see #getWaitHandleNames()
517+ */
518+ public int getWaitHandleTimeout()
519+ {
520+ return m_waitHandleTimeout;
521+ }
522+
523+ /**
524+ * Sets the amount of time to wait on the wait handle identified by
525+ * the wait handle names before the operation times out.
526+ *
527+ * @param waitHandleTimeout the new value for the amount of time to
528+ * wait on the wait handles before timing out
529+ * @see #getWaitHandleTimeout()
530+ * @see #setWaitHandleNames(String)
531+ */
532+ public void setWaitHandleTimeout(int waitHandleTimeout)
533+ {
534+ m_waitHandleTimeout = waitHandleTimeout;
535+ }
536+
537+ /**
538+ * Gets the additional connection string parameters to be applied
539+ * to the connection string sent to the publisher during subscription.
540+ *
541+ * @return the additional connection string parameters sent to the
542+ * publisher during subscription
543+ * @see #setExtraConnectionStringParameters(String)
544+ */
545+ public String getExtraConnectionStringParameters()
546+ {
547+ return m_extraConnectionStringParameters;
548+ }
549+
550+ /**
551+ * Sets the additional connection string parameters to be applied
552+ * to the connection string sent to the publisher during subscription.
553+ *
554+ * @param extraConnectionStringParameters the new value for the addtional
555+ * connection string parameters sent to the publisher during
556+ * subscription
557+ * @see #getExtraConnectionStringParameters()
558+ */
559+ public void setExtraConnectionStringParameters(String extraConnectionStringParameters)
560+ {
561+ m_extraConnectionStringParameters = extraConnectionStringParameters;
562+ }
563+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/CompressionMode.java+40−0
@@ -0,0 +1,40 @@
1+//******************************************************************************************************
2+// CompressionMode.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 09/14/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.constant;
25+
26+/**
27+ * Defines character encodings supported by the Gateway Exchange Protocol.
28+ */
29+public class CompressionMode
30+{
31+ /**
32+ * GZIP compression.
33+ */
34+ public static final int GZIP = 0x00000020;
35+
36+ /**
37+ * No compression.
38+ */
39+ public static final int None = 0x00000000;
40+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/DataPacketFlags.java+52−0
@@ -0,0 +1,52 @@
1+//******************************************************************************************************
2+// DataPacketFlags.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.constant;
25+
26+/**
27+ * Defines the flags used for compact measurement data packets.
28+ */
29+public class DataPacketFlags
30+{
31+ /**
32+ * Attached to packets which are remotely synchronized.
33+ */
34+ public static final byte Synchronized = 0x01;
35+
36+ /**
37+ * Attached to packets which are serialized
38+ * using the compact measurement format.
39+ */
40+ public static final byte Compact = 0x02;
41+
42+ /**
43+ * Indicates the index which identifies the cryptography
44+ * key used to encrypt the data in the packet.
45+ */
46+ public static final byte CipherIndex = 0x03;
47+
48+ /**
49+ * No flags.
50+ */
51+ public static final byte NoFlags = 0x00;
52+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/OperationalEncoding.java+54−0
@@ -0,0 +1,54 @@
1+//******************************************************************************************************
2+// OperationalEncoding.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.constant;
25+
26+/**
27+ * Defines character encodings supported by the Gateway Exchange Protocol.
28+ */
29+public class OperationalEncoding
30+{
31+ /**
32+ * Little-endian UTF-16.
33+ */
34+ public static final int Unicode = 0x00000000;
35+
36+ /**
37+ * Big-endian UTF-16.
38+ */
39+ public static final int BigEndianUnicode = 0x00000100;
40+
41+ /**
42+ * UTF-8
43+ */
44+ public static final int UTF8 = 0x00000200;
45+
46+ /**
47+ * The default character encoding used by the operating system.
48+ * This option may not work properly if the two systems that
49+ * are communicating are not using the same operating system default.
50+ * On Windows systems, this will often be compatible with the ANSI
51+ * option defined in the C# implementation of the Publisher API.
52+ */
53+ public static final int OperatingSystemDefault = 0x00000300;
54+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/OperationalModes.java+78−0
@@ -0,0 +1,78 @@
1+//******************************************************************************************************
2+// OperationalModes.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.constant;
25+
26+/**
27+ * Defines flags and bitmasks used in the operational modes
28+ * that define how the subscriber and publisher communicate.
29+ * Operational modes are the first things that get transmitted
30+ * to the publisher after a successful connection.
31+ */
32+public class OperationalModes
33+{
34+ /**
35+ * Bitmask to extract the protocol version from the operational modes.
36+ */
37+ public static final int VersionMask = 0x0000001F;
38+
39+ /**
40+ * Bitmask to extract the compression mode from the operational modes.
41+ * Compression is currently not supported; these bits are reserved.
42+ */
43+ public static final int CompressionModeMask = 0x000000E0;
44+
45+ /**
46+ * Bitmask to extract the operational encoding from the operational modes.
47+ *
48+ * @see OperationalEncoding
49+ */
50+ public static final int EncodingMask = 0x00000300;
51+
52+ /**
53+ * Flag that determines whether to use the common serialization format.
54+ * If the bit is set, the common serialization format is used. If the
55+ * flag is unset, the .NET serialization format is used. This Java
56+ * implementation of the Subscriber API only supports the common
57+ * serialization format.
58+ */
59+ public static final int UseCommonSerializationFormat = 0x01000000;
60+
61+ /**
62+ * Flag that determines whether to compress the signal index cache.
63+ * This Java implementation of the Subscriber API does not yet support
64+ * compression of the signal index cache.
65+ */
66+ public static final int CompressSignalIndexCache = 0x40000000;
67+
68+ /**
69+ * Flag that determines whether to compress the metadata transmitted
70+ * from the publisher to the subscriber.
71+ */
72+ public static final int CompressMetadata = 0x80000000;
73+
74+ /**
75+ * No flags.
76+ */
77+ public static final int NoFlags = 0x00000000;
78+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/ServerCommand.java+82−0
@@ -0,0 +1,82 @@
1+//******************************************************************************************************
2+// ServerCommand.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.constant;
25+
26+/**
27+ * Defines command codes for the commands that can
28+ * be sent to the publisher via the command channel.
29+ */
30+public class ServerCommand
31+{
32+ /**
33+ * Indicates that the subscriber would like to authenticate.
34+ * <p>
35+ * The data that accompanies this message is the encrypted
36+ * authentication string prefixed with its byte length. The
37+ * byte length should be unencrypted. The authentication
38+ * string consists of the subscriber's authentication ID
39+ * prefixed with a random, 8-byte salt.
40+ */
41+ public static final byte Authenticate = 0x00;
42+
43+ /**
44+ * Indicates that the subscriber would like
45+ * to receive metadata from the publisher.
46+ */
47+ public static final byte MetadataRefresh = 0x01;
48+
49+ /**
50+ * Indicates that the subscriber would like
51+ * to receive measurements from the publisher.
52+ * <p>
53+ * The data that accompanies this message is the connection string
54+ * which defines several configuration options that can be asked
55+ * of the publisher.
56+ */
57+ public static final byte Subscribe = 0x02;
58+
59+ /**
60+ * Indicates that the subscriber would like to stop
61+ * receiving measurements from the publisher.
62+ */
63+ public static final byte Unsubscribe = 0x03;
64+
65+ /**
66+ * Indicates that the subscriber would
67+ * like to initiate a cipher key rotation.
68+ */
69+ public static final byte RotateCipherKeys = 0x04;
70+
71+ /**
72+ * Indicates that the subscriber would like
73+ * to change its measurement processing interval.
74+ */
75+ public static final byte UpdateProcessingInterval = 0x05;
76+
77+ /**
78+ * Indicates that the subscriber would like to define
79+ * or change the way it is communicating with the publisher.
80+ */
81+ public static final byte DefineOperationalModes = 0x06;
82+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/constant/ServerResponse.java+86−0
@@ -0,0 +1,86 @@
1+//******************************************************************************************************
2+// ServerResponse.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.constant;
25+
26+/**
27+ * Defines response codes that can be sent by the publisher back to the
28+ * subscriber.
29+ */
30+public class ServerResponse
31+{
32+ /**
33+ * Indicates that a command sent by the subscriber has been successfully
34+ * processed and handled.
35+ */
36+ public static final byte Succeeded = (byte) 0x80;
37+
38+ /**
39+ * Indicates that the publisher was unable to properly process and handle a
40+ * command sent by the publisher.
41+ */
42+ public static final byte Failed = (byte) 0x81;
43+
44+ /**
45+ * Indicates that the packet sent with this code contains measurement data.
46+ */
47+ public static final byte DataPacket = (byte) 0x82;
48+
49+ /**
50+ * Indicates that the packet sent with this code contains the serialized
51+ * signal index cache.
52+ */
53+ public static final byte UpdateSignalIndexCache = (byte) 0x83;
54+
55+ /**
56+ * Indicates that the packet sent with this code contains the serialized
57+ * base time offsets.
58+ */
59+ public static final byte UpdateBaseTimes = (byte) 0x84;
60+
61+ /**
62+ * Indicates that the packet sent with this code contains the cipher keys
63+ * used for encryption.
64+ */
65+ public static final byte UpdateCipherKeys = (byte) 0x85;
66+
67+ /**
68+ * Indicates that the publisher has started sending measurement data, and
69+ * the message includes the server's local time taken when the data stream
70+ * was started.
71+ */
72+ public static final byte DataStartTime = (byte) 0x86;
73+
74+ /**
75+ * Indicates that a temporal session has been completed.
76+ */
77+ public static final byte ProcessingComplete = (byte) 0x87;
78+
79+ /**
80+ * Indicates that no action should be taken by the subscriber.
81+ * This message is sent periodically by the publisher over the
82+ * command channel in order to verify that the connection is
83+ * still open.
84+ */
85+ public static final byte NoOP = (byte) 0xFF;
86+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/MeasurementEvent.java+66−0
@@ -0,0 +1,66 @@
1+//******************************************************************************************************
2+// MeasurementEvent.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+import java.util.Collection;
27+import java.util.Collections;
28+import java.util.EventObject;
29+
30+import org.gpa.tsf.Measurement;
31+
32+/**
33+ * Event that occurs when new measurements are received from the publisher.
34+ */
35+public class MeasurementEvent extends EventObject
36+{
37+ private Collection<Measurement> m_measurements;
38+
39+ /**
40+ * Constructs a new instance.
41+ *
42+ * @param source the source of the event
43+ * @param measurements the new measurements received from the publisher
44+ */
45+ public MeasurementEvent(Object source, Collection<Measurement> measurements)
46+ {
47+ super(source);
48+
49+ if (measurements == null)
50+ throw new IllegalArgumentException("measurements cannot be null");
51+
52+ m_measurements = Collections.unmodifiableCollection(measurements);
53+ }
54+
55+ /**
56+ * Gets the measurements that were received from the publisher.
57+ *
58+ * @return the measurements received from the publisher
59+ */
60+ public Collection<Measurement> getMeasurements()
61+ {
62+ return m_measurements;
63+ }
64+
65+ private static final long serialVersionUID = 5788181880673812873L;
66+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/MessageEvent.java+86−0
@@ -0,0 +1,86 @@
1+//******************************************************************************************************
2+// MessageEvent.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+import java.util.EventObject;
27+
28+/**
29+ * Event that occurs when the subscriber
30+ * needs to expose a message to the user.
31+ */
32+public class MessageEvent extends EventObject
33+{
34+ private String m_message;
35+ private Exception m_exception;
36+
37+ /**
38+ * Constructs a new instance.
39+ *
40+ * @param source the source of the message
41+ * @param message the message to be exposed
42+ */
43+ public MessageEvent(Object source, String message)
44+ {
45+ super(source);
46+ m_message = message;
47+ }
48+
49+ /**
50+ * Constructs a new instance associated with an exception.
51+ *
52+ * @param source the source of the exception
53+ * @param exception the exception to be exposed
54+ */
55+ public MessageEvent(Object source, Exception exception)
56+ {
57+ this(source, exception.getMessage());
58+ m_exception = exception;
59+ }
60+
61+ /**
62+ * Gets the message to be exposed to the user. If this
63+ * {@code MessageEvent} is associated with an exception,
64+ * this is equivalent to calling {@code getException().getMessage()}.
65+ *
66+ * @return the message to be exposed to the user
67+ */
68+ public String getMessage()
69+ {
70+ return m_message;
71+ }
72+
73+ /**
74+ * Gets the exception associated with this
75+ * message event, or null if there is none.
76+ *
77+ * @return the exception associated with the message event,
78+ * if there is one
79+ */
80+ public Exception getException()
81+ {
82+ return m_exception;
83+ }
84+
85+ private static final long serialVersionUID = -6228918892670504322L;
86+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/MetadataEvent.java+91−0
@@ -0,0 +1,91 @@
1+//******************************************************************************************************
2+// MetadataEvent.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+import java.util.EventObject;
27+
28+/**
29+ * Event that occurs when the subscriber receives metadata from the publisher.
30+ */
31+public class MetadataEvent extends EventObject
32+{
33+ private byte[] m_compressedMetadata;
34+ private String m_xmlMetadata;
35+
36+ /**
37+ * Constructs a new instance.
38+ *
39+ * @param source the source of the event
40+ * @param compressedMetadata the compressed metadata
41+ */
42+ public MetadataEvent(Object source, byte[] compressedMetadata)
43+ {
44+ super(source);
45+
46+ if (compressedMetadata == null)
47+ throw new IllegalArgumentException("compressedMetadata cannot be null");
48+
49+ m_compressedMetadata = compressedMetadata;
50+ }
51+
52+ /**
53+ * Constructs a new instance.
54+ *
55+ * @param source the source of the event
56+ * @param xmlMetadata the uncompressed metadata
57+ */
58+ public MetadataEvent(Object source, String xmlMetadata)
59+ {
60+ super(source);
61+
62+ if (xmlMetadata == null)
63+ throw new IllegalArgumentException("xmlMetadata cannot be null");
64+
65+ m_xmlMetadata = xmlMetadata;
66+ }
67+
68+ /**
69+ * Gets the compressed metadata received from the publisher.
70+ * If the metadata received was uncompressed, this will return null.
71+ *
72+ * @return byte array containing the compressed metadata
73+ */
74+ public byte[] getCompressedMetadata()
75+ {
76+ return m_compressedMetadata;
77+ }
78+
79+ /**
80+ * Gets the uncompressed metadata received from the publisher.
81+ * If the metadata received was compressed, this will return null.
82+ *
83+ * @return the uncompressed XML metadata
84+ */
85+ public String getXmlMetadata()
86+ {
87+ return m_xmlMetadata;
88+ }
89+
90+ private static final long serialVersionUID = -1703909541078304245L;
91+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/StartTimeEvent.java+59−0
@@ -0,0 +1,59 @@
1+//******************************************************************************************************
2+// SubscriberEvent.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+import java.util.EventObject;
27+
28+/**
29+ * Event that occurs when the subscriber receives
30+ * the data start time from the publisher.
31+ */
32+public class StartTimeEvent extends EventObject
33+{
34+ private long m_dataStartTime;
35+
36+ /**
37+ * Constructs a new instance with the given data start time.
38+ *
39+ * @param source the source of the event
40+ * @param dataStartTime the data start time received from the publisher
41+ */
42+ public StartTimeEvent(Object source, long dataStartTime)
43+ {
44+ super(source);
45+ m_dataStartTime = dataStartTime;
46+ }
47+
48+ /**
49+ * Gets the data start time received from the publisher.
50+ *
51+ * @return the data start time
52+ */
53+ public long getDataStartTime()
54+ {
55+ return m_dataStartTime;
56+ }
57+
58+ private static final long serialVersionUID = -3551015702900244809L;
59+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberAdapter.java+69−0
@@ -0,0 +1,69 @@
1+//******************************************************************************************************
2+// SubscriberAdapter.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+/**
27+ * An abstract adapter class for receiving subscriber events. The
28+ * methods in this class are empty. This class exists as convenience
29+ * for creating listener objects.
30+ */
31+public class SubscriberAdapter implements SubscriberListener
32+{
33+
34+ @Override
35+ public void statusMessageReceived(MessageEvent evt)
36+ {
37+ }
38+
39+ @Override
40+ public void exceptionEncountered(MessageEvent evt)
41+ {
42+ }
43+
44+ @Override
45+ public void dataStartTimeReceived(StartTimeEvent evt)
46+ {
47+ }
48+
49+ @Override
50+ public void metadataReceived(MetadataEvent evt)
51+ {
52+ }
53+
54+ @Override
55+ public void newMeasurementsReceived(MeasurementEvent evt)
56+ {
57+ }
58+
59+ @Override
60+ public void processingCompleteCallback(MessageEvent evt)
61+ {
62+ }
63+
64+ @Override
65+ public void connectionTerminated(MessageEvent evt)
66+ {
67+ }
68+
69+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberConnectorAdapter.java+44−0
@@ -0,0 +1,44 @@
1+//******************************************************************************************************
2+// SubscriberConnectorAdapter.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/23/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+/**
27+ * An abstract adapter class for receiving subscriber connector events.
28+ * The methods in this class are empty. This class exists as convenience
29+ * for creating listener objects.
30+ */
31+public class SubscriberConnectorAdapter implements SubscriberConnectorListener
32+{
33+
34+ @Override
35+ public void exceptionEncountered(MessageEvent evt)
36+ {
37+ }
38+
39+ @Override
40+ public void reconnected(SubscriberEvent evt)
41+ {
42+ }
43+
44+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberConnectorListener.java+47−0
@@ -0,0 +1,47 @@
1+//******************************************************************************************************
2+// SubscriberConnectorListener.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/23/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+/**
27+ * Interface which defines callbacks for the {@link SubscriberConnector}.
28+ */
29+public interface SubscriberConnectorListener
30+{
31+ /**
32+ * Called when an exception is encountered
33+ * by the {@code SubscriberConnector}.
34+ *
35+ * @param evt the event which contains the exception
36+ */
37+ void exceptionEncountered(MessageEvent evt);
38+
39+ /**
40+ * Occurs when the subscriber is automatically
41+ * reconnected by the {@code SubscriberConnector}.
42+ *
43+ * @param evt the event which contains the subscriber
44+ * that was reconnected
45+ */
46+ void reconnected(SubscriberEvent evt);
47+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberEvent.java+60−0
@@ -0,0 +1,60 @@
1+//******************************************************************************************************
2+// SubscriberEvent.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/23/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+import java.util.EventObject;
27+
28+import org.gpa.tsf.transport.DataSubscriber;
29+
30+/**
31+ * Generic event associated with a subscriber.
32+ */
33+public class SubscriberEvent extends EventObject
34+{
35+ private DataSubscriber m_subscriber;
36+
37+ /**
38+ * Constructs a new instance.
39+ *
40+ * @param source the source of the event
41+ * @param subscriber the subscriber associated with the event
42+ */
43+ public SubscriberEvent(Object source, DataSubscriber subscriber)
44+ {
45+ super(source);
46+ m_subscriber = subscriber;
47+ }
48+
49+ /**
50+ * Gets the subscriber associated with the event.
51+ *
52+ * @return the subscriber associated with the event
53+ */
54+ public DataSubscriber getSubscriber()
55+ {
56+ return m_subscriber;
57+ }
58+
59+ private static final long serialVersionUID = -1854428244027543102L;
60+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/transport/event/SubscriberListener.java+90−0
@@ -0,0 +1,90 @@
1+//******************************************************************************************************
2+// SubscriberListener.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.transport.event;
25+
26+import org.gpa.tsf.transport.DataSubscriber;
27+
28+/**
29+ * Interface which defines the callbacks
30+ * used by the subscriber to handle events.
31+ *
32+ * @see DataSubscriber
33+ * @see DataSubscriber#addSubscriberListener(SubscriberListener)
34+ */
35+public interface SubscriberListener
36+{
37+ /**
38+ * Occurs when the subscriber wishes to
39+ * expose a status message to the user.
40+ *
41+ * @param evt the message event which contains the status message
42+ */
43+ void statusMessageReceived(MessageEvent evt);
44+
45+ /**
46+ * Occurs when the subscriber encounters an exception.
47+ *
48+ * @param evt the message event which contains the exception encountered
49+ */
50+ void exceptionEncountered(MessageEvent evt);
51+
52+ /**
53+ * Occurs when the data start time is received from the publisher.
54+ *
55+ * @param evt the event which contains the data start time received
56+ */
57+ void dataStartTimeReceived(StartTimeEvent evt);
58+
59+ /**
60+ * Occurs when metadata is received from the publisher.
61+ *
62+ * @param evt the metadata event which contains the metadata received
63+ */
64+ void metadataReceived(MetadataEvent evt);
65+
66+ /**
67+ * Occurs when a new collection of measurements
68+ * are received from the publisher.
69+ *
70+ * @param evt the collection of measurements received
71+ */
72+ void newMeasurementsReceived(MeasurementEvent evt);
73+
74+ /**
75+ * Occurs when the publisher notifies the subscriber
76+ * that a temporal session has been completed.
77+ *
78+ * @param evt the event which contains a message from the publisher
79+ */
80+ void processingCompleteCallback(MessageEvent evt);
81+
82+ /**
83+ * Occurs when the TCP connection between the publisher
84+ * and subscriber is terminated unexpectedly.
85+ *
86+ * @param evt the event which contains an exception that occurred as
87+ * a result of the connection termination
88+ */
89+ void connectionTerminated(MessageEvent evt);
90+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/ArrayExtensions.java+195−0
@@ -0,0 +1,195 @@
1+//******************************************************************************************************
2+// ArrayExtensions.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/18/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.util;
25+
26+/**
27+ * Utility class that provides additional functionality for arrays.
28+ */
29+public class ArrayExtensions
30+{
31+ /**
32+ * Copies the specified number of bytes from the source array to the
33+ * destination array, starting from the given offsets in each array.
34+ *
35+ * @param source the source array
36+ * @param srcOffset the offset into the source array where the data
37+ * to be copied starts
38+ * @param dest the destination array
39+ * @param destOffset the offset into the destination array where the
40+ * data is to be copied
41+ * @param length the amount of data to be copied
42+ */
43+ public static void blockCopy(byte[] source, int srcOffset, byte[] dest, int destOffset, int length)
44+ {
45+ for (int i = 0; i < length; i++)
46+ dest[destOffset + i] = source[srcOffset + i];
47+ }
48+
49+ /**
50+ * Copies the specified number of short integers from the source array
51+ * to the destination array, starting from the given offsets in each
52+ * array.
53+ *
54+ * @param source the source array
55+ * @param srcOffset the offset into the source array where the data
56+ * to be copied starts
57+ * @param dest the destination array
58+ * @param destOffset the offset into the destination array where the
59+ * data is to be copied
60+ * @param length the amount of data to be copied
61+ */
62+ public static void blockCopy(short[] source, int srcOffset, short[] dest, int destOffset, int length)
63+ {
64+ for (int i = 0; i < length; i++)
65+ dest[destOffset + i] = source[srcOffset + i];
66+ }
67+
68+ /**
69+ * Copies the specified number of integers from the source array to the
70+ * destination array, starting from the given offsets in each array.
71+ *
72+ * @param source the source array
73+ * @param srcOffset the offset into the source array where the data
74+ * to be copied starts
75+ * @param dest the destination array
76+ * @param destOffset the offset into the destination array where the
77+ * data is to be copied
78+ * @param length the amount of data to be copied
79+ */
80+ public static void blockCopy(int[] source, int srcOffset, int[] dest, int destOffset, int length)
81+ {
82+ for (int i = 0; i < length; i++)
83+ dest[destOffset + i] = source[srcOffset + i];
84+ }
85+
86+ /**
87+ * Copies the specified number of long integers from the source array
88+ * to the destination array, starting from the given offsets in each
89+ * array.
90+ *
91+ * @param source the source array
92+ * @param srcOffset the offset into the source array where the data
93+ * to be copied starts
94+ * @param dest the destination array
95+ * @param destOffset the offset into the destination array where the
96+ * data is to be copied
97+ * @param length the amount of data to be copied
98+ */
99+ public static void blockCopy(long[] source, int srcOffset, long[] dest, int destOffset, int length)
100+ {
101+ for (int i = 0; i < length; i++)
102+ dest[destOffset + i] = source[srcOffset + i];
103+ }
104+
105+ /**
106+ * Copies the specified number of floats from the source array to the
107+ * destination array, starting from the given offsets in each array.
108+ *
109+ * @param source the source array
110+ * @param srcOffset the offset into the source array where the data
111+ * to be copied starts
112+ * @param dest the destination array
113+ * @param destOffset the offset into the destination array where the
114+ * data is to be copied
115+ * @param length the amount of data to be copied
116+ */
117+ public static void blockCopy(float[] source, int srcOffset, float[] dest, int destOffset, int length)
118+ {
119+ for (int i = 0; i < length; i++)
120+ dest[destOffset + i] = source[srcOffset + i];
121+ }
122+
123+ /**
124+ * Copies the specified number of doubles from the source array to the
125+ * destination array, starting from the given offsets in each array.
126+ *
127+ * @param source the source array
128+ * @param srcOffset the offset into the source array where the data
129+ * to be copied starts
130+ * @param dest the destination array
131+ * @param destOffset the offset into the destination array where the
132+ * data is to be copied
133+ * @param length the amount of data to be copied
134+ */
135+ public static void blockCopy(double[] source, int srcOffset, double[] dest, int destOffset, int length)
136+ {
137+ for (int i = 0; i < length; i++)
138+ dest[destOffset + i] = source[srcOffset + i];
139+ }
140+
141+ /**
142+ * Copies the specified number of boolean values from the source array
143+ * to the destination array, starting from the given offsets in each
144+ * array.
145+ *
146+ * @param source the source array
147+ * @param srcOffset the offset into the source array where the data
148+ * to be copied starts
149+ * @param dest the destination array
150+ * @param destOffset the offset into the destination array where the
151+ * data is to be copied
152+ * @param length the amount of data to be copied
153+ */
154+ public static void blockCopy(boolean[] source, int srcOffset, boolean[] dest, int destOffset, int length)
155+ {
156+ for (int i = 0; i < length; i++)
157+ dest[destOffset + i] = source[srcOffset + i];
158+ }
159+
160+ /**
161+ * Copies the specified number of characters from the source array to the
162+ * destination array, starting from the given offsets in each array.
163+ *
164+ * @param source the source array
165+ * @param srcOffset the offset into the source array where the data
166+ * to be copied starts
167+ * @param dest the destination array
168+ * @param destOffset the offset into the destination array where the
169+ * data is to be copied
170+ * @param length the amount of data to be copied
171+ */
172+ public static void blockCopy(char[] source, int srcOffset, char[] dest, int destOffset, int length)
173+ {
174+ for (int i = 0; i < length; i++)
175+ dest[destOffset + i] = source[srcOffset + i];
176+ }
177+
178+ /**
179+ * Copies the specified number of objects from the source array to the
180+ * destination array, starting from the given offsets in each array.
181+ *
182+ * @param source the source array
183+ * @param srcOffset the offset into the source array where the data
184+ * to be copied starts
185+ * @param dest the destination array
186+ * @param destOffset the offset into the destination array where the
187+ * data is to be copied
188+ * @param length the amount of data to be copied
189+ */
190+ public static <T> void blockCopy(T[] source, int srcOffset, T[] dest, int destOffset, int length)
191+ {
192+ for (int i = 0; i < length; i++)
193+ dest[destOffset + i] = source[srcOffset + i];
194+ }
195+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/InputStreamExtensions.java+73−0
@@ -0,0 +1,73 @@
1+//******************************************************************************************************
2+// InputStreamExtensions.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/16/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.util;
25+
26+import java.io.BufferedInputStream;
27+import java.io.IOException;
28+import java.io.InputStream;
29+
30+/**
31+ * Utility class that provides additional functionality for input streams.
32+ *
33+ * @author Stephen C. Wills
34+ */
35+public class InputStreamExtensions
36+{
37+ /**
38+ * This read method works approximately the same as the
39+ * {@link BufferedInputStream#read(byte[], int, int)} method.
40+ * The main difference is that this method will block until the
41+ * requested amount of data is read from the input stream or the
42+ * end of the stream has been reached, whereas BufferedInputStream
43+ * will try to avoid blocking by checking the {@code available()}
44+ * method of the underlying stream.
45+ *
46+ * @param stream source of the data
47+ * @param buffer destination buffer
48+ * @param offset offset at which to start storing bytes
49+ * @param length requested number of bytes
50+ * @return the number of bytes read from the stream, or -1 if the end of the stream has been reached
51+ * @throws IOException if this input stream has been closed by invoking its
52+ * {@link InputStream#close()} method, or an I/O error occurs
53+ * @see java.io.BufferedInputStream
54+ */
55+ public static int read(InputStream stream, byte[] buffer, int offset, int length) throws IOException
56+ {
57+ int index = offset;
58+ int readAmount = 0;
59+ int totalReadAmount = 0;
60+
61+ while (readAmount >= 0 && totalReadAmount < length)
62+ {
63+ readAmount = stream.read(buffer, index, length - readAmount);
64+ index += readAmount;
65+ totalReadAmount += readAmount;
66+ }
67+
68+ if (readAmount < 0 && totalReadAmount == 0)
69+ totalReadAmount = -1;
70+
71+ return totalReadAmount;
72+ }
73+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/Masks.java+92−0
@@ -0,0 +1,92 @@
1+//******************************************************************************************************
2+// Masks.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/12/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.util;
25+
26+/**
27+ * Utility class to properly generate masks for different sizes of integers.
28+ *
29+ * @author Stephen C. Wills
30+ */
31+public class Masks
32+{
33+ /**
34+ * Gets a 64-bit integer mask with the given
35+ * number of least significant bits turned on.
36+ *
37+ * @param numberOfOnBits The number of bits to be turned on.
38+ * @return a 64-bit integer mask
39+ */
40+ public static long getLongMask(int numberOfOnBits)
41+ {
42+ if(numberOfOnBits < 0 || numberOfOnBits > Long.SIZE)
43+ throw new IllegalArgumentException("Number of masked bits must be between 0 and " + Long.SIZE);
44+
45+ return ~(~0L << numberOfOnBits);
46+ }
47+
48+ /**
49+ * Gets a 32-bit integer mask with the given
50+ * number of least significant bits turned on.
51+ *
52+ * @param numberOfOnBits The number of bits to be turned on.
53+ * @return a 32-bit integer mask
54+ */
55+ public static int getIntMask(int numberOfOnBits)
56+ {
57+ if(numberOfOnBits < 0 || numberOfOnBits > Integer.SIZE)
58+ throw new IllegalArgumentException("Number of masked bits must be between 0 and " + Integer.SIZE);
59+
60+ return ~(~0 << numberOfOnBits);
61+ }
62+
63+ /**
64+ * Gets a 16-bit integer mask with the given
65+ * number of least significant bits turned on.
66+ *
67+ * @param numberOfOnBits The number of bits to be turned on.
68+ * @return a 16-bit integer mask
69+ */
70+ public static short getShortMask(int numberOfOnBits)
71+ {
72+ if(numberOfOnBits < 0 || numberOfOnBits > Short.SIZE)
73+ throw new IllegalArgumentException("Number of masked bits must be between 0 and " + Short.SIZE);
74+
75+ return (short)getIntMask(numberOfOnBits);
76+ }
77+
78+ /**
79+ * Gets a 8-bit integer mask with the given
80+ * number of least significant bits turned on.
81+ *
82+ * @param numberOfOnBits The number of bits to be turned on.
83+ * @return a 8-bit integer mask
84+ */
85+ public static byte getByteMask(int numberOfOnBits)
86+ {
87+ if(numberOfOnBits < 0 || numberOfOnBits > Byte.SIZE)
88+ throw new IllegalArgumentException("Number of masked bits must be between 0 and " + Byte.SIZE);
89+
90+ return (byte)getIntMask(numberOfOnBits);
91+ }
92+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/NumberExtensions.java+132−0
@@ -0,0 +1,132 @@
1+//******************************************************************************************************
2+// NumberExtensions.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/12/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.util;
25+
26+import java.math.BigInteger;
27+
28+/**
29+ * Utility class that provides additional functionality for numbers.
30+ *
31+ * @author Stephen C. Wills
32+ */
33+public class NumberExtensions
34+{
35+ /**
36+ * Gets a string representation of a long integer
37+ * in base 10 as if it were an unsigned long integer.
38+ *
39+ * @param num the long integer to be converted to a string
40+ * @return a string representation of the given long integer
41+ * @see Long#toString(long)
42+ */
43+ public static String toUnsignedString(long num)
44+ {
45+ return toUnsignedString(num, 10);
46+ }
47+
48+ /**
49+ * Gets a string representation of a long integer
50+ * as if it were an unsigned long integer.
51+ *
52+ * @param num the long integer to be converted to a string
53+ * @param radix the radix to use in the string representation
54+ * @return a string representation of the given long integer
55+ * @see Long#toString(long, int)
56+ */
57+ public static String toUnsignedString(long num, int radix)
58+ {
59+ BigInteger bigNum;
60+ BigInteger bigMod;
61+
62+ if (num > 0L)
63+ return Long.toString(radix);
64+
65+ bigNum = BigInteger.valueOf(num >>> 1);
66+ bigMod = BigInteger.valueOf(num & 1L);
67+
68+ return bigNum.shiftLeft(1).add(bigMod).toString(radix);
69+ }
70+
71+ /**
72+ * Gets a string representation of an integer in
73+ * base 10 as if it were an unsigned integer.
74+ *
75+ * @param num the integer to be converted to a string
76+ * @return a string representation of the given integer
77+ * @see Integer#toString(int)
78+ */
79+ public static String toUnsignedString(int num)
80+ {
81+ return toUnsignedString(num, 10);
82+ }
83+
84+ /**
85+ * Gets a string representation of an integer
86+ * as if it were an unsigned integer.
87+ *
88+ * @param num the integer to be converted to a string
89+ * @param radix the radix to use in the string representation
90+ * @return a string representation of the given integer
91+ * @see Integer#toString(int, int)
92+ */
93+ public static String toUnsignedString(int num, int radix)
94+ {
95+ if (num > 0)
96+ return Integer.toString(num, radix);
97+
98+ return Long.toString(num & Masks.getLongMask(Integer.SIZE), radix);
99+ }
100+
101+ /**
102+ * Gets a string representation of a short integer
103+ * in base 10 as if it were an unsigned short integer.
104+ *
105+ * @param num the short integer to be converted to a string
106+ * @return a string representation of the given short integer
107+ * @see Short#toString(short)
108+ */
109+ public static String toUnsignedString(short num)
110+ {
111+ if (num > 0)
112+ return Short.toString(num);
113+
114+ return Integer.toString(num & Masks.getIntMask(Short.SIZE));
115+ }
116+
117+ /**
118+ * Gets a string representation of a byte in
119+ * base 10 as if it were an unsigned byte.
120+ *
121+ * @param num the byte to be converted to a string
122+ * @return a string representation of the given byte
123+ * @see Byte#toString(byte)
124+ */
125+ public static String toUnsignedString(byte num)
126+ {
127+ if (num > 0)
128+ return Byte.toString(num);
129+
130+ return Integer.toString(num & Masks.getIntMask(Byte.SIZE));
131+ }
132+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/StringExtensions.java+88−0
@@ -0,0 +1,88 @@
1+//******************************************************************************************************
2+// StringExtensions.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/18/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.util;
25+
26+/**
27+ * Utility class that provides additional functionality for strings.
28+ */
29+public class StringExtensions
30+{
31+ /**
32+ * Determines whether the given string is null or the empty string.
33+ *
34+ * @param str the string to be checked
35+ * @return true if the string is null or empty; false otherwise
36+ */
37+ public static boolean isNullOrEmpty(String str)
38+ {
39+ return (str == null) || str.isEmpty();
40+ }
41+
42+ /**
43+ * Determines whether the given string is null or contains
44+ * nothing but whitespace characters.
45+ *
46+ * @param str the string to be checked
47+ * @return true if the string is null or whitespace; false otherwise
48+ */
49+ public static boolean isNullOrWhitespace(String str)
50+ {
51+ return (str == null) || str.trim().isEmpty();
52+ }
53+
54+ /**
55+ * Converts null strings to the empty string. If a string is provided
56+ * which is not null, no operation is performed and the string is
57+ * returned as-is.
58+ *
59+ * @param str the string to be checked
60+ * @return the empty string if the parameter is null; otherwise the
61+ * parameter itself is returned
62+ */
63+ public static String toNonNull(String str)
64+ {
65+ return toNonNull(str, "");
66+ }
67+
68+ /**
69+ * Converts null strings to the given default string value. If a
70+ * string is provided which is not null, no operation is performed
71+ * and the string is returned as-is.
72+ *
73+ * @param str the string to be checked
74+ * @param defaultValue the default value to return if the provided
75+ * string happens to be null
76+ * @return the default value if the first parameter is null; otherwise
77+ * the first parameter itself is returned
78+ */
79+ public static String toNonNull(String str, String defaultValue)
80+ {
81+ if (str != null)
82+ return str;
83+ else if (defaultValue != null)
84+ return defaultValue;
85+ else
86+ return "";
87+ }
88+}
Source/Libraries/TSFJavaLibrary/src/org/gpa/tsf/util/TimeExtensions.java+65−0
@@ -0,0 +1,65 @@
1+//******************************************************************************************************
2+// TimeExtensions.java - Gbtc
3+//
4+// Copyright � 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 04/23/2012 - Stephen C. Wills
20+// Generated original version of source code.
21+//
22+//******************************************************************************************************
23+
24+package org.gpa.tsf.util;
25+
26+import java.util.Calendar;
27+
28+/**
29+ * Utility class which provides additional
30+ * functionality for time representations.
31+ */
32+public class TimeExtensions
33+{
34+ /**
35+ * Converts a value in ticks (100-nanosecond intervals since midnight,
36+ * January 1, 0001) into a {@link Calendar} instance. Some loss of
37+ * precision is incurred as {@code Calendar}s store up to millisecond
38+ * precision.
39+ *
40+ * @param ticks the value in ticks to be converted
41+ * @return the equivalent {@code Calendar} instance
42+ * @see #toTicks(Calendar)
43+ */
44+ public static Calendar fromTicks(long ticks)
45+ {
46+ Calendar calendar = Calendar.getInstance();
47+ calendar.setTimeInMillis((ticks - TicksAtEpoch) / TicksPerMillisecond);
48+ return calendar;
49+ }
50+
51+ /**
52+ * Converts a {@link Calendar} instance into a value in ticks.
53+ *
54+ * @param calendar the {@code Calendar} instance to be converted
55+ * @return the equivalent value in ticks
56+ * @see #fromTicks(long)
57+ */
58+ public static long toTicks(Calendar calendar)
59+ {
60+ return (calendar.getTimeInMillis() * TicksPerMillisecond) + TicksAtEpoch;
61+ }
62+
63+ private static final long TicksAtEpoch = 621355968000000000L;
64+ private static final long TicksPerMillisecond = 10000L;
65+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t