Skip to content
This repository was archived by the owner on Feb 19, 2025. It is now read-only.

Commit 563c4c4

Browse files
author
Konstantina Chremmou
committed
Improved parsing of SMAPIv3 errors. Deprecated Failure method that should not be used directly by the implementation.
Signed-off-by: Konstantina Chremmou <[email protected]>
1 parent c4c427e commit 563c4c4

File tree

1 file changed

+117
-102
lines changed

1 file changed

+117
-102
lines changed

csharp/autogen/src/Failure.cs

Lines changed: 117 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@
3030

3131
using System;
3232
using System.Collections.Generic;
33-
using System.Text;
33+
using System.Linq;
3434
using System.Resources;
35-
using System.Collections;
35+
using System.Runtime.Serialization;
3636
using System.Text.RegularExpressions;
3737
using System.Xml;
38-
using System.Runtime.Serialization;
38+
using Newtonsoft.Json.Linq;
39+
3940

4041
namespace XenAPI
4142
{
@@ -45,47 +46,46 @@ public partial class Failure : Exception
4546
public const string INTERNAL_ERROR = "INTERNAL_ERROR";
4647
public const string MESSAGE_PARAMETER_COUNT_MISMATCH = "MESSAGE_PARAMETER_COUNT_MISMATCH";
4748

48-
private static ResourceManager errorDescriptions = XenAPI.FriendlyErrorNames.ResourceManager;
49+
private static ResourceManager errorDescriptions = FriendlyErrorNames.ResourceManager;
4950

5051
private readonly List<string> errorDescription;
5152
private string errorText;
5253
private string shortError;
5354

54-
public List<string> ErrorDescription
55+
public List<string> ErrorDescription
5556
{
56-
get
57-
{
58-
return errorDescription;
59-
}
57+
get { return errorDescription; }
6058
}
6159

6260
public string ShortMessage
6361
{
64-
get
65-
{
66-
return shortError;
67-
}
62+
get { return shortError; }
6863
}
6964

7065
public override string Message
7166
{
72-
get
73-
{
74-
return errorText;
75-
}
67+
get { return errorText; }
7668
}
7769

70+
#region Constructors
71+
7872
public Failure() : base() { }
7973

8074
public Failure(params string[] err)
8175
: this(new List<string>(err))
8276
{}
8377

78+
public Failure(List<string> errDescription)
79+
{
80+
errorDescription = errDescription;
81+
ParseExceptionMessage();
82+
}
83+
8484
public Failure(string message, Exception exception)
8585
: base(message, exception)
8686
{
87-
errorDescription = new List<string>() { message };
88-
Setup();
87+
errorDescription = new List<string> {message};
88+
ParseExceptionMessage();
8989
}
9090

9191
protected Failure(SerializationInfo info, StreamingContext context)
@@ -96,95 +96,112 @@ protected Failure(SerializationInfo info, StreamingContext context)
9696
shortError = info.GetString("shortError");
9797
}
9898

99-
public Failure(List<string> errDescription)
100-
{
101-
errorDescription = errDescription;
102-
Setup();
103-
}
99+
#endregion
104100

105-
public void Setup()
101+
private void ParseExceptionMessage()
106102
{
107-
if (ErrorDescription.Count > 0)
103+
if (ErrorDescription.Count <= 0)
104+
return;
105+
106+
try
108107
{
108+
string formatString;
109109
try
110110
{
111-
string formatString;
112-
try
113-
{
114-
formatString = errorDescriptions.GetString(ErrorDescription[0]);
115-
}
116-
catch
117-
{
118-
formatString = null;
119-
}
120-
121-
if (formatString == null)
122-
{
123-
// If we don't have a translation, just combine all the error results from the server
124-
List<string> cleanBits = new List<string>();
125-
foreach (string s in ErrorDescription)
126-
{
127-
// Only show non-empty bits of ErrorDescription.
128-
// Also, trim the bits, since the server occasionally sends spurious newlines.
129-
if (s.Trim().Length > 0)
130-
{
131-
cleanBits.Add(s.Trim());
132-
}
133-
}
134-
135-
this.errorText = string.Join(" - ", cleanBits.ToArray());
136-
}
137-
else
138-
{
139-
140-
// We need a string array to pass to String.Format, and it must not contain the 0th element.
141-
142-
string[] objects = new string[ErrorDescription.Count - 1];
143-
144-
for (int i = 1; i < ErrorDescription.Count; i++)
145-
objects[i - 1] = ErrorDescription[i];
146-
147-
this.errorText = String.Format(formatString, objects);
148-
}
111+
formatString = errorDescriptions.GetString(ErrorDescription[0]);
149112
}
150-
catch (Exception)
113+
catch
151114
{
152-
this.errorText = ErrorDescription[0];
115+
formatString = null;
153116
}
154117

155-
try
118+
if (formatString == null)
156119
{
157-
shortError = errorDescriptions.GetString(ErrorDescription[0] + "-SHORT") ?? errorText;
120+
// If we don't have a translation, just combine all the error results from the server
121+
// Only show non-empty bits of ErrorDescription.
122+
// Also, trim the bits because the server occasionally sends spurious newlines.
123+
124+
var cleanBits = (from string s in ErrorDescription
125+
let trimmed = s.Trim()
126+
where trimmed.Length > 0
127+
select trimmed).ToArray();
128+
129+
errorText = string.Join(" - ", cleanBits);
158130
}
159-
catch (Exception)
131+
else
160132
{
161-
shortError = this.errorText;
133+
// We need a string array to pass to String.Format, and it must not contain the 0th element
134+
errorText = string.Format(formatString, ErrorDescription.Skip(1));
162135
}
136+
}
137+
catch (Exception)
138+
{
139+
errorText = ErrorDescription[0];
140+
}
141+
142+
//call these before setting the shortError because they modify the errorText
143+
ParseSmapiV3Failures();
144+
ParseCslgFailures();
163145

164-
// now try and parse CSLG failures (these have embedded xml)
165-
TryParseCslg();
146+
try
147+
{
148+
shortError = errorDescriptions.GetString(ErrorDescription[0] + "-SHORT") ?? errorText;
149+
}
150+
catch (Exception)
151+
{
152+
shortError = errorText;
166153
}
167154
}
168155

169156
/// <summary>
170-
/// Tries the parse CSLG failures. These have embedded xml. The useful part (from the user's perspective) is copied to errorText.
157+
/// The ErrorDescription[2] of SmapiV3 failures contains embedded json.
158+
/// This method parses it and copies the user friendly part to errorText.
171159
/// </summary>
172-
/// <returns>A value specifying whether a CSLG error was found.</returns>
173-
private bool TryParseCslg()
160+
private void ParseSmapiV3Failures()
174161
{
175-
//failure.ErrorDescription[2]:
176-
//<StorageLinkServiceError>
177-
// <Fault>Host ivory has not yet been added to the service. [err=Object was not found]</Fault>
178-
// <Detail>
179-
// <errorCode>6</errorCode>
180-
// <messageId></messageId>
181-
// <defaultMessage>Host ivory has not yet been added to the service. [err=Object was not found]</defaultMessage>
182-
// <severity>2</severity>
183-
// <errorFunction>CXSSHostUtil::getHost</errorFunction>
184-
// <errorLine>113</errorLine>
185-
// <errorFile>.\\xss_util_host.cpp</errorFile>
186-
// </Detail>
187-
// </StorageLinkServiceError>
162+
/* Example ErrorDescription:
163+
* [
164+
* "SR_BACKEND_FAILURE",
165+
* "TransportException",
166+
* "{\"error\": \"Unable to connect to iSCSI service on target\"}"
167+
* ]
168+
*/
169+
170+
if (ErrorDescription.Count < 3 || string.IsNullOrEmpty(ErrorDescription[0]) || !ErrorDescription[0].StartsWith("SR_BACKEND_FAILURE"))
171+
return;
172+
173+
try
174+
{
175+
var obj = JObject.Parse(ErrorDescription[2]); //will throw exception if ErrorDescription[2] is a simple string
176+
errorText = (string)obj.SelectToken("error") ?? errorText;
177+
}
178+
catch
179+
{
180+
//ignore
181+
}
182+
}
183+
184+
/// <summary>
185+
/// The ErrorDescription[2] of Cslg failures contains embedded xml.
186+
/// This method parses it and copies the user friendly part to errorText.
187+
/// </summary>
188+
private void ParseCslgFailures()
189+
{
190+
/* ErrorDescription[2] example:
191+
192+
<StorageLinkServiceError>
193+
<Fault>Host ivory has not yet been added to the service. [err=Object was not found]</Fault>
194+
<Detail>
195+
<errorCode>6</errorCode>
196+
<messageId></messageId>
197+
<defaultMessage>Host ivory has not yet been added to the service. [err=Object was not found]</defaultMessage>
198+
<severity>2</severity>
199+
<errorFunction>CXSSHostUtil::getHost</errorFunction>
200+
<errorLine>113</errorLine>
201+
<errorFile>.\\xss_util_host.cpp</errorFile>
202+
</Detail>
203+
</StorageLinkServiceError>
204+
*/
188205

189206
if (ErrorDescription.Count > 2 && ErrorDescription[2] != null && ErrorDescription[0] != null && ErrorDescription[0].StartsWith("SR_BACKEND_FAILURE"))
190207
{
@@ -200,26 +217,26 @@ private bool TryParseCslg()
200217
}
201218
catch (XmlException)
202219
{
203-
return false;
220+
return;
204221
}
205222

206223
XmlNodeList nodes = doc.SelectNodes("/StorageLinkServiceError/Fault");
207224

208225
if (nodes != null && nodes.Count > 0 && !string.IsNullOrEmpty(nodes[0].InnerText))
209226
{
210-
if (string.IsNullOrEmpty(errorText))
211-
{
212-
errorText = nodes[0].InnerText;
213-
}
214-
else
215-
{
216-
errorText = string.Format("{0} ({1})", errorText, nodes[0].InnerText);
217-
}
218-
return true;
227+
errorText = string.IsNullOrEmpty(errorText)
228+
? nodes[0].InnerText
229+
: string.Format("{0} ({1})", errorText, nodes[0].InnerText);
219230
}
220231
}
221232
}
222-
return false;
233+
}
234+
235+
[Obsolete("This method is used internally and should not be called directly from the implementing code. "+
236+
"If you need to modify this instance's fields, construct a new instance instead.")]
237+
public void Setup()
238+
{
239+
ParseExceptionMessage();
223240
}
224241

225242
public override string ToString()
@@ -230,9 +247,7 @@ public override string ToString()
230247
public override void GetObjectData(SerializationInfo info, StreamingContext context)
231248
{
232249
if (info == null)
233-
{
234250
throw new ArgumentNullException("info");
235-
}
236251

237252
info.AddValue("errorDescription", errorDescription, typeof(List<string>));
238253
info.AddValue("errorText", errorText);
@@ -241,4 +256,4 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont
241256
base.GetObjectData(info, context);
242257
}
243258
}
244-
}
259+
}

0 commit comments

Comments
 (0)