Created
September 26, 2010 03:08
-
-
Save nimms/597553 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using DDSGpsNav.ServiceLayer.Invoker; | |
namespace DDSGpsNav.ServiceLayer.Invoker.MFData | |
{ | |
/// <summary> | |
/// Class which gets the latest Truck Master file from the server | |
/// </summary> | |
public class MasterFileUpdateCommand : ICommand | |
{ | |
private readonly string startRecord; | |
private readonly MasterFileType mfType; | |
private readonly OperationType opType; | |
public MasterFileUpdateCommand(MasterFileType mfType, OperationType opType, string startRecord) | |
{ | |
this.startRecord = startRecord; | |
this.mfType = mfType; | |
this.opType = opType; | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="T:System.Object"></see> class. | |
/// </summary> | |
public string execute() | |
{ | |
var invoker = new InvokerFactory().BuildHttpInvoker(); | |
var CommandBody = String.Format("[" + opType + "][" + mfType + "][{0}]", startRecord); | |
return invoker.DoPut(CommandBody, 1); | |
} | |
} | |
public enum OperationType | |
{ | |
SYNC, TABLE | |
} | |
public enum MasterFileType | |
{ | |
TRUCK, RUN, WAYPOINTS, EMP, BINS, PREMISES, COLL_ISSUE, PREMISES_NORFID, AREA_NOTES, MAP_REGIONS, COORDINATES, | |
MISSED_SERVICE | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Net; | |
using DDSGpsNav.Classes; | |
using DDSGpsNav.ServiceLayer.NetworkInfo; | |
using DDSGpsNav.Services.Network.Invoker; | |
namespace DDSGpsNav.ServiceLayer.Invoker | |
{ | |
/// <summary> | |
/// A HttpInvoker is used to send http requests to a given url. The Url is immutable and is provided | |
/// via the constructor so that each HttpInvoker object is threadsafe and can be safely used | |
/// in concurrent environments | |
/// </summary> | |
public class HttpInvoker : IHttpInvoker | |
{ | |
private readonly string serverUrl; | |
private readonly NetworkInfo.NetworkConnectionInfo networkConnectionInfo; | |
private Dictionary<string, string> Parameters; | |
//private DateTime RequestStartedAt; | |
public HttpInvoker(string serverUrl) | |
{ | |
this.serverUrl = serverUrl; | |
} | |
public HttpInvoker(string serverUrl, NetworkInfo.NetworkConnectionInfo networkConnectionInfo) | |
{ | |
this.serverUrl = serverUrl; | |
this.networkConnectionInfo = networkConnectionInfo; | |
} | |
public void AddParam(string key, string value) | |
{ | |
if (Parameters == null) | |
{ | |
Parameters = new Dictionary<string, string>(); | |
} | |
Parameters.Add(key, value); | |
} | |
/// <summary> | |
/// Convenience method for a put request | |
/// </summary> | |
public string DoPut(string body, int timeOut) | |
{ | |
return DoRequest(body, timeOut, HttpMethod.PUT); | |
} | |
/// <summary> | |
/// Performs a http request using the url assigned to this invoker | |
/// </summary> | |
/// | |
/// <param name="body"> | |
/// The request body | |
/// </param> | |
/// | |
/// <param name="method"> | |
/// The Http Method to Use | |
/// </param> | |
/// | |
/// <param name="timeOut"> | |
/// The time out for this request, in minutes | |
/// </param> | |
public string DoRequest(string body, int timeOut, HttpMethod method) | |
{ | |
var result = ""; | |
var url = BuildQueryString(serverUrl); | |
//submit request and get the response object | |
try | |
{ | |
var req = (HttpWebRequest) WebRequest.Create(url); | |
req.Method = method.ToString(); | |
req.AllowWriteStreamBuffering = true; | |
//make the request time out a little bit longer than expected | |
//to give the server time to timeout the request itself, which | |
//will give us more informative logging ie, we will be able to | |
//ascertain if the server has recieved the request but decided not to act on it | |
//this is because we set a TTL parameter on AUTD requests | |
req.Timeout = 1001*60*timeOut; | |
//retrieve request stream and wrap in streamwriter | |
Stream reqStream = req.GetRequestStream(); | |
var wrtr = new StreamWriter(reqStream); | |
//Write message body to the request buffer | |
wrtr.Write(body); | |
wrtr.Close(); | |
var resp = (HttpWebResponse) req.GetResponse(); | |
result = ReadResponseStream(resp); | |
} | |
catch (WebException we) | |
{ | |
var logger = FileLogManager.Instance; | |
if (!(url.Contains("AUTD") && we.Message == "The operation has timed out")) | |
{ | |
logger.Debug(string.Format("{0}\r\n{1}", we.Status, we.Message)); | |
} | |
else | |
{ | |
logger.Debug("AUTD connection has timed out. Request Status: {0}, Exception Message: {1}", we.Status, we.Message); | |
} | |
var response = ReadResponseStream(we.Response); | |
if (!String.IsNullOrEmpty(response)) | |
{ | |
logger.Debug("exception response text: {0}", response); | |
} | |
} | |
catch (Exception e) | |
{ | |
var logger = FileLogManager.Instance; | |
logger.Error("Error in request: " + e); | |
return ""; | |
} | |
return result; | |
} | |
private string ReadResponseStream(WebResponse resp) | |
{ | |
if (resp != null && resp.GetResponseStream() != null) | |
{ | |
//retrieve the response stream and wrap in a streamreader | |
var respStream = resp.GetResponseStream(); | |
var rdr = new StreamReader(respStream); | |
var result = ""; | |
//read through the response line-by-line | |
var inLine = rdr.ReadLine(); | |
while (inLine != null) | |
{ | |
//process the response data | |
//for simplicity write to form list box | |
result += inLine + "\n"; | |
inLine = rdr.ReadLine(); | |
} | |
rdr.Close(); | |
return result; | |
} else | |
{ | |
return String.Empty; | |
} | |
} | |
private string BuildQueryString(string requestUrl) | |
{ | |
//add query string if needed (?DEV=deviceId has already been added to the url in the invokerfactory) | |
if(Parameters != null) | |
{ | |
foreach (KeyValuePair<string, string> pair in Parameters) | |
{ | |
requestUrl += "&" + pair.Key + "=" + pair.Value; | |
} | |
} | |
return requestUrl; | |
} | |
public string ServerUrl | |
{ | |
get | |
{ | |
return serverUrl; | |
} | |
} | |
public string Url | |
{ | |
get | |
{ | |
return BuildQueryString(serverUrl); | |
} | |
} | |
public NetworkConnectionInfo NetworkConnectionInfo | |
{ | |
get { return networkConnectionInfo; } | |
} | |
} | |
/// <summary> | |
/// Enum describing the possible http methods | |
/// </summary> | |
public enum HttpMethod | |
{ | |
GET, POST, PUT, HEAD, DELETE, OPTIONS, TRACE, CONNECT | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Data; | |
using DDSGpsNav.Classes; | |
using DDSGpsNav.DB; | |
using DDSGpsNav.ServiceLayer.Invoker.MFData; | |
using DDSGpsNav.ServiceLayer.NetworkInfo; | |
using DDSGpsNav.ServiceLayer.UtilityClasses; | |
namespace DDSGpsNav.ServiceLayer | |
{ | |
public class MasterFileManager | |
{ | |
//since multiple threads could be running a MF Update at the same time. We keep track of | |
//the total number of MF updates in progress so we can ascertain if there are any mf updates | |
//in progress | |
protected static volatile int numberOfMFUpdateInProgress; | |
private const string truckIdOpParamFormat = "{0}][{1}"; | |
private string TruckId; | |
public void UpdateMasterFileTable(MasterFileType mfType, OperationType opType, IMasterFileDAO dao) | |
{ | |
var opParam = GetLastSyncUpdate(opType, dao); | |
UpdateMasterFileTable(mfType, opType, dao, opParam); | |
} | |
private static string GetLastSyncUpdate(OperationType opType, IMasterFileDAO dao) | |
{ | |
var opParam = "0"; | |
if(opType == OperationType.SYNC) | |
{ | |
opParam = new MasterFileDAO().GetLastSyncUpdate(dao); | |
} | |
return opParam; | |
} | |
public void SyncForTruckId(MasterFileType mfType, IMasterFileDAO dao, string truckId) | |
{ | |
//this is a kludgy hack to get around the fact that the dds service data structure | |
//was originally built so that it took either a last change date or a optional param | |
//yay for future proofing | |
TruckId = truckId; //global variable so it can be resent down the wire if there are more than 100 records | |
var opParam = string.Format(truckIdOpParamFormat, new MasterFileDAO().GetLastSyncUpdate(dao), truckId); | |
UpdateMasterFileTable(mfType, OperationType.SYNC, dao, opParam); | |
} | |
public void UpdateMasterFileTable(MasterFileType mfType, OperationType opType, IMasterFileDAO dao, string opParam) | |
{ | |
numberOfMFUpdateInProgress++; | |
var connectionInfo = new NetworkMonitor().GetConnectionInfo(); | |
if (connectionInfo.GetConnectionType() != ConnectionTypeEnum.NONE) | |
{ | |
var mfDAO = new MasterFileDAO(); | |
var results = new MasterFileUpdateCommand(mfType, opType, opParam).execute(); | |
if (results != "[0x]\n" && opType == OperationType.TABLE && !(String.IsNullOrEmpty(results))) | |
{ | |
mfDAO.ClearMFTable(dao.GetTableName()); | |
} | |
var recordsRemaining = true; | |
while (results != "[0x]\n" && !String.IsNullOrEmpty(results) && recordsRemaining) | |
{ | |
//The server will only send data in chunks of 100 (or thereabouts) records, so we don't | |
//overwhelm the RAM on our devices with huge datasets. If the server has decided to break | |
//this transmission into chunks, the first character of the result string that is returned | |
//will be a plus sign (+) | |
if (!(results.StartsWith("+"))) recordsRemaining = false; | |
char[] delims = { '[', ']' }; | |
var dcns = results.Split(delims); | |
try | |
{ | |
results = results.Substring(results.IndexOf('<')); | |
//escapes apostrophe characters (') in the response for insertion into a mysql database | |
results = results.Replace("'", @"\'"); | |
var resultsSet = XmlUtils.DeserialiseDataSetFromXml(results); | |
var lastRecordId = dao.UpdateMFTable(resultsSet); | |
if (recordsRemaining && opType == OperationType.TABLE) | |
{ | |
results = new MasterFileUpdateCommand(mfType, opType, lastRecordId).execute(); | |
} | |
if(recordsRemaining && opType == OperationType.SYNC) | |
{ | |
string newOpParam; | |
newOpParam = !string.IsNullOrEmpty(TruckId) ? string.Format(truckIdOpParamFormat, dcns[1], TruckId) : dcns[1]; | |
results = new MasterFileUpdateCommand(mfType, opType, newOpParam).execute(); | |
} | |
mfDAO.RecordLastSyncUpdate(dcns[1], dao); | |
} | |
catch (ArgumentOutOfRangeException) | |
{ | |
//no xml returned, meaning there are no results for this MF update | |
FileLogManager.Instance.Info("No master file records for " + mfType.ToString() + | |
". Paramter was " + opParam); | |
} | |
} | |
// Remove any rows that are marked for removal in the master file database | |
if(opType == OperationType.SYNC) | |
{ | |
mfDAO.FlushRemovedRecords(dao); | |
} | |
} | |
numberOfMFUpdateInProgress--; | |
} | |
public static bool MfUpdateInProgress | |
{ | |
get { | |
return numberOfMFUpdateInProgress > 0; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment