Showing the changes to Source/Libraries/TSFJavaLibrary/src/org (33 of 915 files). Show all
Unified · Split
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |
| @@ -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 | +} | |