History

Renamed folders and separated GSF.Media and GSF.Net into separate projects.

StephenCWills committed 14 years ago

Commit ac1ef661 parent 45bce55628 files · +733 −461Browse files

Showing the changes to Source/Libraries/GSF.ServiceProcess/ClientHelper.cs (1 of 628 files). Show all

Unified · Split

Source/Libraries/GSF.ServiceProcess/ClientHelper.cs+1013−0
@@ -0,0 +1,1013 @@
1+//*******************************************************************************************************
2+// ClientHelper.cs - Gbtc
3+//
4+// Tennessee Valley Authority, 2009
5+// No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
6+//
7+// This software is made freely available under the TVA Open Source Agreement (see below).
8+//
9+// Code Modification History:
10+// -----------------------------------------------------------------------------------------------------
11+// 08/29/2006 - Pinal C. Patel
12+// Original version of source code generated.
13+// 11/30/2007 - Pinal C. Patel
14+// Modified the "design time" check in EndInit() method to use LicenseManager.UsageMode property
15+// instead of DesignMode property as the former is more accurate than the latter.
16+// 09/30/2008 - J. Ritchie Carroll
17+// Convert to C#.
18+// 07/15/2009 - Pinal C. Patel
19+// Added AuthenticationMethod, AuthenticationUsername and AuthenticationPassword properties to
20+// provision for the authentication process as part of security.
21+// Added ISupportLifecycle, ISupportInitialize and IPersistSettings interface implementations
22+// to support the persistance and retrieval of settings from the config file.
23+// 07/17/2009 - Pinal C. Patel
24+// Added static PretendRequest() method that can be used to create pretend request for manually
25+// invoking request handlers registered with the ServiceHelper.
26+// 07/21/2009 - Pinal C. Patel
27+// Replace AuthenticationUsername and AuthenticationPassword properties with AuthenticationInput
28+// to allow for input text to be specified for any AuthenticationMethod instead of just Ntml.
29+// 07/23/2009 - Pinal C. Patel
30+// ReceivedServiceResponse is now raised only for custom service responses instead of all.
31+// 09/14/2009 - Stephen C. Wills
32+// Added new header and license agreement.
33+// 10/23/2009 - Pinal C. Patel
34+// Modified ReceivedServiceUpdate event to support the change in ServiceHelper.UpdateStatus().
35+// 06/16/2010 - Pinal C. Patel
36+// Made changes necessary to implement role-based security.
37+// 04/14/2011 - Pinal C. Patel
38+// Updated to use new deserialization methods in GSF.Serialization class.
39+//
40+//*******************************************************************************************************
41+
42+#region [ TVA Open Source Agreement ]
43+/*
44+
45+ THIS OPEN SOURCE AGREEMENT ("AGREEMENT") DEFINES THE RIGHTS OF USE,REPRODUCTION, DISTRIBUTION,
46+ MODIFICATION AND REDISTRIBUTION OF CERTAIN COMPUTER SOFTWARE ORIGINALLY RELEASED BY THE
47+ TENNESSEE VALLEY AUTHORITY, A CORPORATE AGENCY AND INSTRUMENTALITY OF THE UNITED STATES GOVERNMENT
48+ ("GOVERNMENT AGENCY"). GOVERNMENT AGENCY IS AN INTENDED THIRD-PARTY BENEFICIARY OF ALL SUBSEQUENT
49+ DISTRIBUTIONS OR REDISTRIBUTIONS OF THE SUBJECT SOFTWARE. ANYONE WHO USES, REPRODUCES, DISTRIBUTES,
50+ MODIFIES OR REDISTRIBUTES THE SUBJECT SOFTWARE, AS DEFINED HEREIN, OR ANY PART THEREOF, IS, BY THAT
51+ ACTION, ACCEPTING IN FULL THE RESPONSIBILITIES AND OBLIGATIONS CONTAINED IN THIS AGREEMENT.
52+
53+ Original Software Designation: openPDC
54+ Original Software Title: The GSF Open Source Phasor Data Concentrator
55+ User Registration Requested. Please Visit https://naspi.tva.com/Registration/
56+ Point of Contact for Original Software: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>
57+
58+ 1. DEFINITIONS
59+
60+ A. "Contributor" means Government Agency, as the developer of the Original Software, and any entity
61+ that makes a Modification.
62+
63+ B. "Covered Patents" mean patent claims licensable by a Contributor that are necessarily infringed by
64+ the use or sale of its Modification alone or when combined with the Subject Software.
65+
66+ C. "Display" means the showing of a copy of the Subject Software, either directly or by means of an
67+ image, or any other device.
68+
69+ D. "Distribution" means conveyance or transfer of the Subject Software, regardless of means, to
70+ another.
71+
72+ E. "Larger Work" means computer software that combines Subject Software, or portions thereof, with
73+ software separate from the Subject Software that is not governed by the terms of this Agreement.
74+
75+ F. "Modification" means any alteration of, including addition to or deletion from, the substance or
76+ structure of either the Original Software or Subject Software, and includes derivative works, as that
77+ term is defined in the Copyright Statute, 17 USC § 101. However, the act of including Subject Software
78+ as part of a Larger Work does not in and of itself constitute a Modification.
79+
80+ G. "Original Software" means the computer software first released under this Agreement by Government
81+ Agency entitled openPDC, including source code, object code and accompanying documentation, if any.
82+
83+ H. "Recipient" means anyone who acquires the Subject Software under this Agreement, including all
84+ Contributors.
85+
86+ I. "Redistribution" means Distribution of the Subject Software after a Modification has been made.
87+
88+ J. "Reproduction" means the making of a counterpart, image or copy of the Subject Software.
89+
90+ K. "Sale" means the exchange of the Subject Software for money or equivalent value.
91+
92+ L. "Subject Software" means the Original Software, Modifications, or any respective parts thereof.
93+
94+ M. "Use" means the application or employment of the Subject Software for any purpose.
95+
96+ 2. GRANT OF RIGHTS
97+
98+ A. Under Non-Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor,
99+ with respect to its own contribution to the Subject Software, hereby grants to each Recipient a
100+ non-exclusive, world-wide, royalty-free license to engage in the following activities pertaining to
101+ the Subject Software:
102+
103+ 1. Use
104+
105+ 2. Distribution
106+
107+ 3. Reproduction
108+
109+ 4. Modification
110+
111+ 5. Redistribution
112+
113+ 6. Display
114+
115+ B. Under Patent Rights: Subject to the terms and conditions of this Agreement, each Contributor, with
116+ respect to its own contribution to the Subject Software, hereby grants to each Recipient under Covered
117+ Patents a non-exclusive, world-wide, royalty-free license to engage in the following activities
118+ pertaining to the Subject Software:
119+
120+ 1. Use
121+
122+ 2. Distribution
123+
124+ 3. Reproduction
125+
126+ 4. Sale
127+
128+ 5. Offer for Sale
129+
130+ C. The rights granted under Paragraph B. also apply to the combination of a Contributor's Modification
131+ and the Subject Software if, at the time the Modification is added by the Contributor, the addition of
132+ such Modification causes the combination to be covered by the Covered Patents. It does not apply to
133+ any other combinations that include a Modification.
134+
135+ D. The rights granted in Paragraphs A. and B. allow the Recipient to sublicense those same rights.
136+ Such sublicense must be under the same terms and conditions of this Agreement.
137+
138+ 3. OBLIGATIONS OF RECIPIENT
139+
140+ A. Distribution or Redistribution of the Subject Software must be made under this Agreement except for
141+ additions covered under paragraph 3H.
142+
143+ 1. Whenever a Recipient distributes or redistributes the Subject Software, a copy of this Agreement
144+ must be included with each copy of the Subject Software; and
145+
146+ 2. If Recipient distributes or redistributes the Subject Software in any form other than source code,
147+ Recipient must also make the source code freely available, and must provide with each copy of the
148+ Subject Software information on how to obtain the source code in a reasonable manner on or through a
149+ medium customarily used for software exchange.
150+
151+ B. Each Recipient must ensure that the following copyright notice appears prominently in the Subject
152+ Software:
153+
154+ No copyright is claimed pursuant to 17 USC § 105. All Other Rights Reserved.
155+
156+ C. Each Contributor must characterize its alteration of the Subject Software as a Modification and
157+ must identify itself as the originator of its Modification in a manner that reasonably allows
158+ subsequent Recipients to identify the originator of the Modification. In fulfillment of these
159+ requirements, Contributor must include a file (e.g., a change log file) that describes the alterations
160+ made and the date of the alterations, identifies Contributor as originator of the alterations, and
161+ consents to characterization of the alterations as a Modification, for example, by including a
162+ statement that the Modification is derived, directly or indirectly, from Original Software provided by
163+ Government Agency. Once consent is granted, it may not thereafter be revoked.
164+
165+ D. A Contributor may add its own copyright notice to the Subject Software. Once a copyright notice has
166+ been added to the Subject Software, a Recipient may not remove it without the express permission of
167+ the Contributor who added the notice.
168+
169+ E. A Recipient may not make any representation in the Subject Software or in any promotional,
170+ advertising or other material that may be construed as an endorsement by Government Agency or by any
171+ prior Recipient of any product or service provided by Recipient, or that may seek to obtain commercial
172+ advantage by the fact of Government Agency's or a prior Recipient's participation in this Agreement.
173+
174+ F. In an effort to track usage and maintain accurate records of the Subject Software, each Recipient,
175+ upon receipt of the Subject Software, is requested to register with Government Agency by visiting the
176+ following website: https://naspi.tva.com/Registration/. Recipient's name and personal information
177+ shall be used for statistical purposes only. Once a Recipient makes a Modification available, it is
178+ requested that the Recipient inform Government Agency at the web site provided above how to access the
179+ Modification.
180+
181+ G. Each Contributor represents that that its Modification does not violate any existing agreements,
182+ regulations, statutes or rules, and further that Contributor has sufficient rights to grant the rights
183+ conveyed by this Agreement.
184+
185+ H. A Recipient may choose to offer, and to charge a fee for, warranty, support, indemnity and/or
186+ liability obligations to one or more other Recipients of the Subject Software. A Recipient may do so,
187+ however, only on its own behalf and not on behalf of Government Agency or any other Recipient. Such a
188+ Recipient must make it absolutely clear that any such warranty, support, indemnity and/or liability
189+ obligation is offered by that Recipient alone. Further, such Recipient agrees to indemnify Government
190+ Agency and every other Recipient for any liability incurred by them as a result of warranty, support,
191+ indemnity and/or liability offered by such Recipient.
192+
193+ I. A Recipient may create a Larger Work by combining Subject Software with separate software not
194+ governed by the terms of this agreement and distribute the Larger Work as a single product. In such
195+ case, the Recipient must make sure Subject Software, or portions thereof, included in the Larger Work
196+ is subject to this Agreement.
197+
198+ J. Notwithstanding any provisions contained herein, Recipient is hereby put on notice that export of
199+ any goods or technical data from the United States may require some form of export license from the
200+ U.S. Government. Failure to obtain necessary export licenses may result in criminal liability under
201+ U.S. laws. Government Agency neither represents that a license shall not be required nor that, if
202+ required, it shall be issued. Nothing granted herein provides any such export license.
203+
204+ 4. DISCLAIMER OF WARRANTIES AND LIABILITIES; WAIVER AND INDEMNIFICATION
205+
206+ A. No Warranty: THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY KIND, EITHER
207+ EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY THAT THE SUBJECT
208+ SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
209+ PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL BE ERROR
210+ FREE, OR ANY WARRANTY THAT DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. THIS
211+ AGREEMENT DOES NOT, IN ANY MANNER, CONSTITUTE AN ENDORSEMENT BY GOVERNMENT AGENCY OR ANY PRIOR
212+ RECIPIENT OF ANY RESULTS, RESULTING DESIGNS, HARDWARE, SOFTWARE PRODUCTS OR ANY OTHER APPLICATIONS
213+ RESULTING FROM USE OF THE SUBJECT SOFTWARE. FURTHER, GOVERNMENT AGENCY DISCLAIMS ALL WARRANTIES AND
214+ LIABILITIES REGARDING THIRD-PARTY SOFTWARE, IF PRESENT IN THE ORIGINAL SOFTWARE, AND DISTRIBUTES IT
215+ "AS IS."
216+
217+ B. Waiver and Indemnity: RECIPIENT AGREES TO WAIVE ANY AND ALL CLAIMS AGAINST GOVERNMENT AGENCY, ITS
218+ AGENTS, EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT. IF RECIPIENT'S USE
219+ OF THE SUBJECT SOFTWARE RESULTS IN ANY LIABILITIES, DEMANDS, DAMAGES, EXPENSES OR LOSSES ARISING FROM
220+ SUCH USE, INCLUDING ANY DAMAGES FROM PRODUCTS BASED ON, OR RESULTING FROM, RECIPIENT'S USE OF THE
221+ SUBJECT SOFTWARE, RECIPIENT SHALL INDEMNIFY AND HOLD HARMLESS GOVERNMENT AGENCY, ITS AGENTS,
222+ EMPLOYEES, CONTRACTORS AND SUBCONTRACTORS, AS WELL AS ANY PRIOR RECIPIENT, TO THE EXTENT PERMITTED BY
223+ LAW. THE FOREGOING RELEASE AND INDEMNIFICATION SHALL APPLY EVEN IF THE LIABILITIES, DEMANDS, DAMAGES,
224+ EXPENSES OR LOSSES ARE CAUSED, OCCASIONED, OR CONTRIBUTED TO BY THE NEGLIGENCE, SOLE OR CONCURRENT, OF
225+ GOVERNMENT AGENCY OR ANY PRIOR RECIPIENT. RECIPIENT'S SOLE REMEDY FOR ANY SUCH MATTER SHALL BE THE
226+ IMMEDIATE, UNILATERAL TERMINATION OF THIS AGREEMENT.
227+
228+ 5. GENERAL TERMS
229+
230+ A. Termination: This Agreement and the rights granted hereunder will terminate automatically if a
231+ Recipient fails to comply with these terms and conditions, and fails to cure such noncompliance within
232+ thirty (30) days of becoming aware of such noncompliance. Upon termination, a Recipient agrees to
233+ immediately cease use and distribution of the Subject Software. All sublicenses to the Subject
234+ Software properly granted by the breaching Recipient shall survive any such termination of this
235+ Agreement.
236+
237+ B. Severability: If any provision of this Agreement is invalid or unenforceable under applicable law,
238+ it shall not affect the validity or enforceability of the remainder of the terms of this Agreement.
239+
240+ C. Applicable Law: This Agreement shall be subject to United States federal law only for all purposes,
241+ including, but not limited to, determining the validity of this Agreement, the meaning of its
242+ provisions and the rights, obligations and remedies of the parties.
243+
244+ D. Entire Understanding: This Agreement constitutes the entire understanding and agreement of the
245+ parties relating to release of the Subject Software and may not be superseded, modified or amended
246+ except by further written agreement duly executed by the parties.
247+
248+ E. Binding Authority: By accepting and using the Subject Software under this Agreement, a Recipient
249+ affirms its authority to bind the Recipient to all terms and conditions of this Agreement and that
250+ Recipient hereby agrees to all terms and conditions herein.
251+
252+ F. Point of Contact: Any Recipient contact with Government Agency is to be directed to the designated
253+ representative as follows: J. Ritchie Carroll <mailto:jrcarrol@tva.gov>.
254+
255+*/
256+#endregion
257+
258+using GSF.Communication;
259+using GSF.Configuration;
260+using System;
261+using System.ComponentModel;
262+using System.Configuration;
263+using System.Drawing;
264+using System.Text;
265+using System.Threading;
266+
267+namespace GSF.ServiceProcess
268+{
269+ /// <summary>
270+ /// Component that provides client-side functionality to <see cref="ServiceHelper"/>.
271+ /// </summary>
272+ [ToolboxBitmap(typeof(ClientHelper))]
273+ public class ClientHelper : Component, ISupportLifecycle, ISupportInitialize, IPersistSettings
274+ {
275+ #region [ Members ]
276+
277+ // Constants
278+
279+ /// <summary>
280+ /// Specifies the default value for the <see cref="Username"/> property.
281+ /// </summary>
282+ public const string DefaultUsername = "";
283+
284+ /// <summary>
285+ /// Specifies the default value for the <see cref="Password"/> property.
286+ /// </summary>
287+ public const string DefaultPassword = "";
288+
289+ /// <summary>
290+ /// Specifies the default value for the <see cref="PersistSettings"/> property.
291+ /// </summary>
292+ public const bool DefaultPersistSettings = false;
293+
294+ /// <summary>
295+ /// Specifies the default value for the <see cref="SettingsCategory"/> property.
296+ /// </summary>
297+ public const string DefaultSettingsCategory = "ClientHelper";
298+
299+ // Events
300+
301+ /// <summary>
302+ /// Occurs when a status update is received from the <see cref="ServiceHelper"/>.
303+ /// </summary>
304+ [Category("Client"),
305+ Description("Occurs when a status update is received from the ServiceHelper.")]
306+ public event EventHandler<EventArgs<UpdateType, string>> ReceivedServiceUpdate;
307+
308+ /// <summary>
309+ /// Occurs when a custom <see cref="ServiceResponse"/> is received from the <see cref="ServiceHelper"/>.
310+ /// </summary>
311+ [Category("Service"),
312+ Description("Occurs when a ServiceResponse is received from the ServiceHelper.")]
313+ public event EventHandler<EventArgs<ServiceResponse>> ReceivedServiceResponse;
314+
315+ /// <summary>
316+ /// Occurs when the state of the <see cref="ServiceHelper"/> is changed.
317+ /// </summary>
318+ [Category("Service"),
319+ Description("Occurs when the state of the ServiceHelper is changed.")]
320+ public event EventHandler<EventArgs<ObjectState<ServiceState>>> ServiceStateChanged;
321+
322+ /// <summary>
323+ /// Occurs when the state of a <see cref="ServiceProcess"/> is changed.
324+ /// </summary>
325+ [Category("Service"),
326+ Description("Occurs when the state of a ServiceProcess is changed.")]
327+ public event EventHandler<EventArgs<ObjectState<ServiceProcessState>>> ProcessStateChanged;
328+
329+ /// <summary>
330+ /// Occurs when the <see cref="ServiceHelper"/> successfully authenticates the <see cref="ClientHelper"/>.
331+ /// </summary>
332+ [Category("Security"),
333+ Description("Occurs when the ServiceHelper successfully authenticates the ClientHelper.")]
334+ public event EventHandler AuthenticationSuccess;
335+
336+ /// <summary>
337+ /// Occurs when the <see cref="ServiceHelper"/> fails to authenticate the <see cref="ClientHelper"/>.
338+ /// </summary>
339+ /// <remarks>
340+ /// Set <see cref="CancelEventArgs.Cancel"/> to <b>true</b> to continue with connection attempts even after authentication fails.
341+ /// This can be useful for re-authenticating the <see cref="ClientHelper"/> using different <see cref="Username"/> and <see cref="Password"/>.
342+ /// </remarks>
343+ [Category("Security"),
344+ Description("Occurs when the ServiceHelper fails to authenticate the ClientHelper.")]
345+ public event EventHandler<CancelEventArgs> AuthenticationFailure;
346+
347+ /// <summary>
348+ /// Occurs when a telnet session has been established.
349+ /// </summary>
350+ [Category("Command"),
351+ Description("Occurs when a telnet session has been established.")]
352+ public event EventHandler TelnetSessionEstablished;
353+
354+ /// <summary>
355+ /// Occurs when a telnet session has been terminated.
356+ /// </summary>
357+ [Category("Command"),
358+ Description("Occurs when a telnet session has been terminated.")]
359+ public event EventHandler TelnetSessionTerminated;
360+
361+ // Fields
362+ private ClientBase m_remotingClient;
363+ private string m_username;
364+ private string m_password;
365+ private bool m_persistSettings;
366+ private string m_settingsCategory;
367+ private bool m_attemptReconnection;
368+ private bool m_authenticationComplete;
369+ private bool m_disposed;
370+ private bool m_initialized;
371+
372+ #endregion
373+
374+ #region [ Constructors ]
375+
376+ /// <summary>
377+ /// Initializes a new instance of the <see cref="ClientHelper"/> class.
378+ /// </summary>
379+ public ClientHelper()
380+ : base()
381+ {
382+ m_username = DefaultUsername;
383+ m_password = DefaultPassword;
384+ m_persistSettings = DefaultPersistSettings;
385+ m_settingsCategory = DefaultSettingsCategory;
386+ }
387+
388+ /// <summary>
389+ /// Initializes a new instance of the <see cref="ClientHelper"/> class.
390+ /// </summary>
391+ /// <param name="container"><see cref="IContainer"/> object that contains the <see cref="ClientHelper"/>.</param>
392+ public ClientHelper(IContainer container)
393+ : this()
394+ {
395+ if (container != null)
396+ container.Add(this);
397+ }
398+
399+ #endregion
400+
401+ #region [ Properties ]
402+
403+ /// <summary>
404+ /// Gets or sets the <see cref="ClientBase"/> object used for communicating with the <see cref="ServiceHelper"/>.
405+ /// </summary>
406+ [Category("Components"),
407+ Description("ClientBase object used for communicating with the ServiceHelper.")]
408+ public ClientBase RemotingClient
409+ {
410+ get
411+ {
412+ return m_remotingClient;
413+ }
414+ set
415+ {
416+ if (m_remotingClient != null)
417+ {
418+ // Detach events from any existing instance
419+ m_remotingClient.ConnectionEstablished -= RemotingClient_ConnectionEstablished;
420+ m_remotingClient.ConnectionAttempt -= RemotingClient_ConnectionAttempt;
421+ m_remotingClient.ConnectionTerminated -= RemotingClient_ConnectionTerminated;
422+ m_remotingClient.ReceiveDataComplete -= RemotingClient_ReceiveDataComplete;
423+ }
424+
425+ m_remotingClient = value;
426+
427+ if (m_remotingClient != null)
428+ {
429+ // Attach events to new instance
430+ m_remotingClient.ConnectionEstablished += RemotingClient_ConnectionEstablished;
431+ m_remotingClient.ConnectionAttempt += RemotingClient_ConnectionAttempt;
432+ m_remotingClient.ConnectionTerminated += RemotingClient_ConnectionTerminated;
433+ m_remotingClient.ReceiveDataComplete += RemotingClient_ReceiveDataComplete;
434+ }
435+ }
436+ }
437+
438+ /// <summary>
439+ /// Gets or sets the username of the <see cref="ClientHelper"/>'s user to be used for authenticating with the <see cref="ServiceHelper"/>.
440+ /// </summary>
441+ /// <exception cref="ArgumentNullException">The value being specified is a null string.</exception>
442+ [Category("Security"),
443+ DefaultValue(DefaultUsername),
444+ Description("Username of the ClientHelper's user to be used for authenticating with the ServiceHelper.")]
445+ public string Username
446+ {
447+ get
448+ {
449+ return m_username;
450+ }
451+ set
452+ {
453+ if (value == null)
454+ throw new ArgumentNullException("value");
455+
456+ m_username = value;
457+ }
458+ }
459+
460+ /// <summary>
461+ /// Gets or sets the password of the <see cref="ClientHelper"/>'s user to be used for authenticating with the <see cref="ServiceHelper"/>.
462+ /// </summary>
463+ /// <exception cref="ArgumentNullException">The value being specified is a null string.</exception>
464+ [Category("Security"),
465+ DefaultValue(DefaultPassword),
466+ Description("Password of the ClientHelper's user to be used for authenticating with the ServiceHelper.")]
467+ public string Password
468+ {
469+ get
470+ {
471+ return m_password;
472+ }
473+ set
474+ {
475+ if (value == null)
476+ throw new ArgumentNullException("value");
477+
478+ m_password = value;
479+ }
480+ }
481+
482+ /// <summary>
483+ /// Gets or sets a boolean value that indicates whether the settings of <see cref="ClientHelper"/> are to be saved to the config file.
484+ /// </summary>
485+ [Category("Persistance"),
486+ DefaultValue(DefaultPersistSettings),
487+ Description("Indicates whether the settings of ClientHelper are to be saved to the config file.")]
488+ public bool PersistSettings
489+ {
490+ get
491+ {
492+ return m_persistSettings;
493+ }
494+ set
495+ {
496+ m_persistSettings = value;
497+ }
498+ }
499+
500+ /// <summary>
501+ /// Gets or sets the category under which the settings of <see cref="ClientHelper"/> are to be saved to the config file if the <see cref="PersistSettings"/> property is set to true.
502+ /// </summary>
503+ /// <exception cref="ArgumentNullException">The value being assigned is a null or empty string.</exception>
504+ [Category("Persistance"),
505+ DefaultValue(DefaultSettingsCategory),
506+ Description("Category under which the settings of ClientHelper are to be saved to the config file if the PersistSettings property is set to true.")]
507+ public string SettingsCategory
508+ {
509+ get
510+ {
511+ return m_settingsCategory;
512+ }
513+ set
514+ {
515+ if (string.IsNullOrEmpty(value))
516+ throw new ArgumentNullException("value");
517+
518+ m_settingsCategory = value;
519+ }
520+ }
521+
522+ /// <summary>
523+ /// Gets or sets a boolean value that indicates whether the <see cref="ClientHelper"/> is currently enabled.
524+ /// </summary>
525+ /// <remarks>
526+ /// <see cref="Enabled"/> property is not be set by user-code directly.
527+ /// </remarks>
528+ [Browsable(false),
529+ EditorBrowsable(EditorBrowsableState.Never),
530+ DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
531+ public bool Enabled
532+ {
533+ get
534+ {
535+ if (m_remotingClient == null)
536+ return false;
537+ else
538+ return m_remotingClient.Enabled;
539+ }
540+ set
541+ {
542+ if (m_remotingClient != null)
543+ m_remotingClient.Enabled = value;
544+ }
545+ }
546+
547+
548+ #endregion
549+
550+ #region [ Methods ]
551+
552+ /// <summary>
553+ /// Initializes the <see cref="ClientHelper"/>.
554+ /// </summary>
555+ /// <remarks>
556+ /// <see cref="Initialize()"/> is to be called by user-code directly only if the <see cref="ClientHelper"/> is not consumed through the designer surface of the IDE.
557+ /// </remarks>
558+ public void Initialize()
559+ {
560+ if (!m_initialized)
561+ {
562+ LoadSettings(); // Load settings from the config file.
563+ m_initialized = true; // Initialize only once.
564+ }
565+ }
566+
567+ /// <summary>
568+ /// Performs necessary operations before the <see cref="ClientHelper"/> properties are initialized.
569+ /// </summary>
570+ /// <remarks>
571+ /// <see cref="BeginInit()"/> should never be called by user-code directly. This method exists solely for use
572+ /// by the designer if the <see cref="ClientHelper"/> is consumed through the designer surface of the IDE.
573+ /// </remarks>
574+ [EditorBrowsable(EditorBrowsableState.Never)]
575+ public void BeginInit()
576+ {
577+ if (!DesignMode)
578+ {
579+ try
580+ {
581+ // Nothing needs to be done before component is initialized.
582+ }
583+ catch (Exception)
584+ {
585+ // Prevent the IDE from crashing when component is in design mode.
586+ }
587+ }
588+ }
589+
590+ /// <summary>
591+ /// Performs necessary operations after the <see cref="ClientHelper"/> properties are initialized.
592+ /// </summary>
593+ /// <remarks>
594+ /// <see cref="EndInit()"/> should never be called by user-code directly. This method exists solely for use
595+ /// by the designer if the <see cref="ClientHelper"/> is consumed through the designer surface of the IDE.
596+ /// </remarks>
597+ [EditorBrowsable(EditorBrowsableState.Never)]
598+ public void EndInit()
599+ {
600+ if (!DesignMode)
601+ {
602+ try
603+ {
604+ Initialize();
605+ }
606+ catch (Exception)
607+ {
608+ // Prevent the IDE from crashing when component is in design mode.
609+ }
610+ }
611+ }
612+
613+ /// <summary>
614+ /// Saves settings for the <see cref="ClientHelper"/> to the config file if the <see cref="PersistSettings"/> property is set to true.
615+ /// </summary>
616+ /// <exception cref="ConfigurationErrorsException"><see cref="SettingsCategory"/> has a value of null or empty string.</exception>
617+ public void SaveSettings()
618+ {
619+ if (m_persistSettings)
620+ {
621+ // Ensure that settings category is specified.
622+ if (string.IsNullOrEmpty(m_settingsCategory))
623+ throw new ConfigurationErrorsException("SettingsCategory property has not been set");
624+
625+ // Save settings under the specified category.
626+ ConfigurationFile config = ConfigurationFile.Current;
627+ CategorizedSettingsElementCollection settings = config.Settings[m_settingsCategory];
628+ settings["Username", true].Update(m_username);
629+ settings["Password", true].Update(m_password);
630+ config.Save();
631+ }
632+ }
633+
634+ /// <summary>
635+ /// Loads saved settings for the <see cref="ClientHelper"/> from the config file if the <see cref="PersistSettings"/> property is set to true.
636+ /// </summary>
637+ /// <exception cref="ConfigurationErrorsException"><see cref="SettingsCategory"/> has a value of null or empty string.</exception>
638+ public void LoadSettings()
639+ {
640+ if (m_persistSettings)
641+ {
642+ // Ensure that settings category is specified.
643+ if (string.IsNullOrEmpty(m_settingsCategory))
644+ throw new ConfigurationErrorsException("SettingsCategory property has not been set");
645+
646+ // Load settings from the specified category.
647+ ConfigurationFile config = ConfigurationFile.Current;
648+ CategorizedSettingsElementCollection settings = config.Settings[m_settingsCategory];
649+ settings.Add("Username", m_username, "Username to be used for authentication with the service.");
650+ settings.Add("Password", m_password, "Password to be used for authentication with the service.", true);
651+ Username = settings["Username"].ValueAs(m_username);
652+ Password = settings["Password"].ValueAs(m_password);
653+ }
654+ }
655+
656+ /// <summary>
657+ /// Connects <see cref="RemotingClient"/> to <see cref="ServiceHelper.RemotingServer"/> and wait until authentication is complete.
658+ /// </summary>
659+ public void Connect()
660+ {
661+ if (m_remotingClient == null)
662+ throw new InvalidOperationException("RemotingClient property of ClientHelper component is not set");
663+
664+ m_attemptReconnection = true;
665+ m_authenticationComplete = false;
666+ m_remotingClient.Connect(); // Wait for connection.
667+
668+ while (!m_authenticationComplete && m_remotingClient.Enabled)
669+ {
670+ Thread.Sleep(100);
671+ } // Wait for authentication.
672+ }
673+
674+ /// <summary>
675+ /// Disconnects <see cref="RemotingClient"/> from <see cref="ServiceHelper.RemotingServer"/>.
676+ /// </summary>
677+ public void Disconnect()
678+ {
679+ m_attemptReconnection = false;
680+
681+ if (m_remotingClient != null)
682+ m_remotingClient.Disconnect();
683+ }
684+
685+ /// <summary>
686+ /// Sends a request to the <see cref="ServiceHelper"/> using <see cref="RemotingClient"/>.
687+ /// </summary>
688+ /// <param name="request">Request text to be sent.</param>
689+ public void SendRequest(string request)
690+ {
691+ ClientRequest requestInstance = ClientRequest.Parse(request);
692+
693+ if (requestInstance != null)
694+ SendRequest(requestInstance);
695+ else
696+ UpdateStatus(UpdateType.Warning, string.Format("Request command \"{0}\" is invalid\r\n\r\n", request));
697+ }
698+
699+ /// <summary>
700+ /// Sends a request to the <see cref="ServiceHelper"/> using <see cref="RemotingClient"/>.
701+ /// </summary>
702+ /// <param name="request"><see cref="ClientRequest"/> object to be sent.</param>
703+ public void SendRequest(ClientRequest request)
704+ {
705+ m_remotingClient.SendAsync(request);
706+ }
707+
708+ /// <summary>
709+ /// Raises the <see cref="ReceivedServiceUpdate"/> event.
710+ /// </summary>
711+ /// <param name="type">One of the <see cref="UpdateType"/> values.</param>
712+ /// <param name="update">Update message received.</param>
713+ protected virtual void OnReceivedServiceUpdate(UpdateType type, string update)
714+ {
715+ if (ReceivedServiceUpdate != null)
716+ ReceivedServiceUpdate(this, new EventArgs<UpdateType, string>(type, update));
717+ }
718+
719+ /// <summary>
720+ /// Raises the <see cref="ReceivedServiceResponse"/> event.
721+ /// </summary>
722+ /// <param name="response"><see cref="ServiceResponse"/> received.</param>
723+ protected virtual void OnReceivedServiceResponse(ServiceResponse response)
724+ {
725+ if (ReceivedServiceResponse != null)
726+ ReceivedServiceResponse(this, new EventArgs<ServiceResponse>(response));
727+ }
728+
729+ /// <summary>
730+ /// Raises the <see cref="ServiceStateChanged"/> event.
731+ /// </summary>
732+ /// <param name="state">New <see cref="ServiceState"/>.</param>
733+ protected virtual void OnServiceStateChanged(ObjectState<ServiceState> state)
734+ {
735+ if (ServiceStateChanged != null)
736+ ServiceStateChanged(this, new EventArgs<ObjectState<ServiceState>>(state));
737+ }
738+
739+ /// <summary>
740+ /// Raises the <see cref="ProcessStateChanged"/> event.
741+ /// </summary>
742+ /// <param name="state">New <see cref="ServiceProcessState"/>.</param>
743+ protected virtual void OnProcessStateChanged(ObjectState<ServiceProcessState> state)
744+ {
745+ if (ProcessStateChanged != null)
746+ ProcessStateChanged(this, new EventArgs<ObjectState<ServiceProcessState>>(state));
747+ }
748+
749+ /// <summary>
750+ /// Raises the <see cref="AuthenticationSuccess"/> event.
751+ /// </summary>
752+ protected virtual void OnAuthenticationSuccess()
753+ {
754+ m_authenticationComplete = true;
755+ if (AuthenticationSuccess != null)
756+ AuthenticationSuccess(this, EventArgs.Empty);
757+ }
758+
759+ /// <summary>
760+ /// Raises the <see cref="AuthenticationFailure"/> event.
761+ /// </summary>
762+ protected virtual void OnAuthenticationFailure()
763+ {
764+ CancelEventArgs args = new CancelEventArgs(true);
765+ if (AuthenticationFailure != null)
766+ AuthenticationFailure(this, args);
767+
768+ // Continue connection attempts if requested.
769+ if (args.Cancel)
770+ {
771+ m_attemptReconnection = false;
772+ m_authenticationComplete = true;
773+ }
774+ }
775+
776+ /// <summary>
777+ /// Raises the <see cref="TelnetSessionEstablished"/> event.
778+ /// </summary>
779+ protected virtual void OnTelnetSessionEstablished()
780+ {
781+ if (TelnetSessionEstablished != null)
782+ TelnetSessionEstablished(this, EventArgs.Empty);
783+ }
784+
785+ /// <summary>
786+ /// Raises the <see cref="TelnetSessionTerminated"/> event.
787+ /// </summary>
788+ protected virtual void OnTelnetSessionTerminated()
789+ {
790+ if (TelnetSessionTerminated != null)
791+ TelnetSessionTerminated(this, EventArgs.Empty);
792+ }
793+
794+ /// <summary>
795+ /// Releases the unmanaged resources used by the <see cref="ClientHelper"/> object and optionally releases the managed resources.
796+ /// </summary>
797+ /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
798+ protected override void Dispose(bool disposing)
799+ {
800+ if (!m_disposed)
801+ {
802+ try
803+ {
804+ // This will be done regardless of whether the object is finalized or disposed.
805+ if (disposing)
806+ {
807+ // This will be done only when the object is disposed by calling Dispose().
808+ Disconnect();
809+ SaveSettings();
810+ RemotingClient = null;
811+ }
812+ }
813+ finally
814+ {
815+ m_disposed = true; // Prevent duplicate dispose.
816+ base.Dispose(disposing); // Call base class Dispose().
817+ }
818+ }
819+ }
820+
821+ private void UpdateStatus(UpdateType type, string message, params object[] args)
822+ {
823+ OnReceivedServiceUpdate(type, string.Format(message, args));
824+ }
825+
826+ private void RemotingClient_ConnectionAttempt(object sender, System.EventArgs e)
827+ {
828+ UpdateStatus(UpdateType.Information, "Connecting to {0}...\r\n\r\n", m_remotingClient.ServerUri);
829+ }
830+
831+ private void RemotingClient_ConnectionEstablished(object sender, System.EventArgs e)
832+ {
833+ // Upon establishing connection with the service's communication client, we'll send our information to the
834+ // service so the service can keep track of all the client that are connected to its communication server.
835+ m_remotingClient.SendAsync(new ClientInfo(this));
836+
837+ StringBuilder status = new StringBuilder();
838+ status.AppendFormat("Connected to {0}:", m_remotingClient.ServerUri);
839+ status.AppendLine();
840+ status.AppendLine();
841+ status.Append(m_remotingClient.Status);
842+ status.AppendLine();
843+ UpdateStatus(UpdateType.Information, status.ToString());
844+ }
845+
846+ private void RemotingClient_ConnectionTerminated(object sender, System.EventArgs e)
847+ {
848+ StringBuilder status = new StringBuilder();
849+ status.AppendFormat("Disconnected from {0}:", m_remotingClient.ServerUri);
850+ status.AppendLine();
851+ status.AppendLine();
852+ status.Append(m_remotingClient.Status);
853+ status.AppendLine();
854+ UpdateStatus(UpdateType.Warning, status.ToString());
855+
856+ // Attempt reconnection on a seperate thread.
857+ if (m_attemptReconnection)
858+ new Thread((ThreadStart)delegate()
859+ {
860+ Connect();
861+ }).Start();
862+ }
863+
864+ private void RemotingClient_ReceiveDataComplete(object sender, EventArgs<byte[], int> e)
865+ {
866+ ServiceResponse response = null;
867+ Serialization.TryDeserialize<ServiceResponse>(e.Argument1.BlockCopy(0, e.Argument2), SerializationFormat.Binary, out response);
868+ if (response != null)
869+ {
870+ switch (response.Type)
871+ {
872+ case "UPDATECLIENTSTATUS-INFORMATION":
873+ UpdateStatus(UpdateType.Information, response.Message);
874+ break;
875+ case "UPDATECLIENTSTATUS-WARNING":
876+ UpdateStatus(UpdateType.Warning, response.Message);
877+ break;
878+ case "UPDATECLIENTSTATUS-ALARM":
879+ UpdateStatus(UpdateType.Alarm, response.Message);
880+ break;
881+ case "AUTHENTICATIONSUCCESS":
882+ OnAuthenticationSuccess();
883+ break;
884+ case "AUTHENTICATIONFAILURE":
885+ OnAuthenticationFailure();
886+ break;
887+ case "SERVICESTATECHANGED":
888+ if (response.Attachments.Count > 0)
889+ {
890+ ObjectState<ServiceState> state = response.Attachments[0] as ObjectState<ServiceState>;
891+
892+ if (state != null)
893+ {
894+ // Notify change in service state by raising an event.
895+ OnServiceStateChanged(state);
896+
897+ // Provide a status update for change in state of the service.
898+ UpdateType type = UpdateType.Information;
899+ switch (state.CurrentState)
900+ {
901+ case ServiceState.Stopped:
902+ case ServiceState.Paused:
903+ case ServiceState.Shutdown:
904+ type = UpdateType.Warning;
905+ break;
906+ }
907+ UpdateStatus(type, string.Format("State of service \"{0}\" has changed to \"{1}\".\r\n\r\n", state.ObjectName, state.CurrentState));
908+ }
909+ }
910+ break;
911+ case "PROCESSSTATECHANGED":
912+ if (response.Attachments.Count > 0)
913+ {
914+ ObjectState<ServiceProcessState> state = response.Attachments[0] as ObjectState<ServiceProcessState>;
915+
916+ if (state != null)
917+ {
918+ // Notify change in process state by raising an event.
919+ OnProcessStateChanged(state);
920+
921+ // Provide a status update for change in state of the service process.
922+ UpdateType type = UpdateType.Information;
923+ switch (state.CurrentState)
924+ {
925+ case ServiceProcessState.Aborted:
926+ case ServiceProcessState.Exception:
927+ type = UpdateType.Alarm;
928+ break;
929+
930+ }
931+ UpdateStatus(type, string.Format("State of process \"{0}\" has changed to \"{1}\".\r\n\r\n", state.ObjectName, state.CurrentState));
932+ }
933+ }
934+ break;
935+ case "TELNETSESSION":
936+ switch (response.Message.ToUpper())
937+ {
938+ case "ESTABLISHED":
939+ OnTelnetSessionEstablished();
940+ break;
941+ case "TERMINATED":
942+ OnTelnetSessionTerminated();
943+ break;
944+ }
945+ break;
946+ default:
947+ OnReceivedServiceResponse(response);
948+ break;
949+ }
950+ }
951+ }
952+
953+ #endregion
954+
955+ #region [ Static ]
956+
957+ /// <summary>
958+ /// Returns an <see cref="ClientRequestInfo"/> object for the specified <paramref name="requestCommand"/> that can be used
959+ /// to invoke <see cref="ServiceHelper.ClientRequestHandlers"/> manually as if the request was sent by a <see cref="ClientHelper"/> remotely.
960+ /// </summary>
961+ /// <param name="requestCommand">Command for which an <see cref="ClientRequestInfo"/> object is to be created.</param>
962+ /// <returns>An <see cref="ClientRequestInfo"/> object.</returns>
963+ public static ClientRequestInfo PretendRequest(string requestCommand)
964+ {
965+ ClientRequest request = ClientRequest.Parse(requestCommand);
966+ ClientRequestInfo requestInfo = new ClientRequestInfo(new ClientInfo(), request);
967+
968+ return requestInfo;
969+ }
970+
971+ /// <summary>
972+ /// Attempts to parse an actionable reponse sent from the service.
973+ /// </summary>
974+ /// <param name="serviceResponse"><see cref="ServiceResponse"/> to test for actionable response.</param>
975+ /// <param name="sourceCommand">Command that invoked <paramref name="serviceResponse"/>.</param>
976+ /// <param name="responseSuccess">Boolean success state of <paramref name="serviceResponse"/>.</param>
977+ /// <returns><c>true</c> if actionable response was able to be parsed successfully; otherwise <c>false</c>.</returns>
978+ public static bool TryParseActionableResponse(ServiceResponse serviceResponse, out string sourceCommand, out bool responseSuccess)
979+ {
980+ bool parseSucceeded = false;
981+
982+ sourceCommand = null;
983+ responseSuccess = false;
984+
985+ try
986+ {
987+ string response = serviceResponse.Type;
988+
989+ // Attempt to parse response message
990+ if (!string.IsNullOrWhiteSpace(response))
991+ {
992+ // Reponse types are formatted as "Command:Success" or "Command:Failure"
993+ string[] parts = response.Split(':');
994+
995+ if (parts.Length > 1)
996+ {
997+ sourceCommand = parts[0].Trim().ToTitleCase();
998+ responseSuccess = (string.Compare(parts[1].Trim(), "Success", true) == 0);
999+ parseSucceeded = true;
1000+ }
1001+ }
1002+ }
1003+ catch
1004+ {
1005+ parseSucceeded = false;
1006+ }
1007+
1008+ return parseSucceeded;
1009+ }
1010+
1011+ #endregion
1012+ }
1013+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

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

Repository code

Go to file
t