/// <summary> /// Parse a transaction out of the XML file. /// </summary> /// <param name="xmlNode">The node where the transaction has been found.</param> private void ParseTransaction(XmlNode xmlNode) { // Create an explicit transaction for the methods found at this node. this.transaction = this.batch.Transactions.Add(); // The <Method> tag specifies the name assembly, type and method name for this operation. The parameters to the method // call will be nested under this heading. foreach (XmlNode methodNode in xmlNode.SelectNodes("method")) { ParseMethod(methodNode); } }
static int Main(string[] args) { // If this flag is set during the processing of the file, the program will exit with an error code. bool hasErrors = false; try { // Defaults batchSize = 100; assemblyName = "External Service"; nameSpaceName = "MarkThree.Quasar.External"; // The command line parser is driven by different states that are triggered by the flags read. Unless a flag has been // read, the command line parser assumes that it's reading the file name from the command line. argumentState = ArgumentState.FileName; // Parse the command line for arguments. foreach (string argument in args) { // Decode the current argument into a state change (or some other action). if (argument == "-a") { argumentState = ArgumentState.Assembly; continue; } if (argument == "-b") { argumentState = ArgumentState.BatchSize; continue; } if (argument == "-n") { argumentState = ArgumentState.NameSpace; continue; } if (argument == "-i") { argumentState = ArgumentState.FileName; continue; } // The parsing state will determine which variable is read next. switch (argumentState) { case ArgumentState.Assembly: assemblyName = argument; break; case ArgumentState.BatchSize: batchSize = Convert.ToInt32(argument); break; case ArgumentState.FileName: fileName = argument; break; case ArgumentState.NameSpace: nameSpaceName = argument; break; } // The default state is to look for the input file name on the command line. argumentState = ArgumentState.FileName; } // Throw a usage message back at the user if no file name was given. if (fileName == null) { throw new Exception("Usage: Loader.Algorithm -i <FileName>"); } // Open up the file containing all the broker. BrokerReader brokerReader = new BrokerReader(fileName); // Loading the database involves creating a batch of commands and sending them off as a transaction. This gives // the server a chance to pipeline a large chunk of processing, without completely locking up the server for the // entire set of data. This will construct a header for the command batch which gives information about which // assembly contains the class that is used to load the data. Batch batch = new Batch(); TransactionPlan transactionPlan = batch.Transactions.Add(); AssemblyPlan assemblyPlan = batch.Assemblies.Add(assemblyName); TypePlan typePlan = assemblyPlan.Types.Add(string.Format("{0}.{1}", nameSpaceName, "Broker")); // Read the file until an EOF is reached. while (true) { // This counter keeps track of the number of records sent. When the batch is full, it's sent to the server to be // executed as a single transaction. int batchCounter = 0; // Read the next broker from the input stream. A 'null' is returned when we've read past the end of file. Broker broker = brokerReader.ReadBroker(); if (broker != null) { // Create a new method from the type information and the name found in the XML file. MethodPlan methodPlan = new MethodPlan("Load"); // Construct a call to the 'Load' method to populate the broker record. methodPlan.Parameters.Add(new InputParameter("brokerId", broker.Symbol)); methodPlan.Parameters.Add(new InputParameter("name", broker.Name)); methodPlan.Parameters.Add(new InputParameter("symbol", broker.Symbol)); // Create a method from the XML data and add it to the transaction. transactionPlan.Methods.Add(typePlan, methodPlan); } // This will check to see if it's time to send the batch. A batch is sent when the 'batchSize' has been // reached, or if the last record has just been converted into a command. if (++batchCounter % batchSize == 0 || broker == null) { WebTransactionProtocol.Execute(batch); batch = new Batch(); transactionPlan = batch.Transactions.Add(); assemblyPlan = batch.Assemblies.Add(assemblyName); typePlan = assemblyPlan.Types.Add(string.Format("{0}.{1}", nameSpaceName, "Broker")); } // If the end of file was reached, break out of the loop and exit the application. if (broker == null) { break; } } } catch (BatchException batchException) { foreach (Exception exception in batchException.Exceptions) { Console.WriteLine(exception.Message); } hasErrors = true; } catch (Exception exception) { // Show the system error and exit with an error. Console.WriteLine(exception.Message); hasErrors = true; } // Any errors will cause an abnormal exit. if (hasErrors) { return(1); } // Write a status message when a the file is loaded successfully. Console.WriteLine(String.Format("{0} Data: Brokers, Loaded", DateTime.Now.ToString("u"))); // If we reached here, the file was imported without issue. return(0); }
/// <summary> /// Begins the task of applying the changes in the form to the data model. /// </summary> private void PostThread(object parameter) { // Extract the parameters from the threads parameter. object[] parameters = (object[])parameter; bool exitDialog = (bool)parameters[0]; SourceOrder sourceOrder = (SourceOrder)parameters[1]; // This batch will collect the information needed to execute a complex transaction on the server. The first part of // the batch sets up the transaction: the assembly where the types and methods are found. It also sets up a // transaction for a complex operation. In this case, the transaction is not that complex, just a single method to be // executed. Batch batch = new Batch(); AssemblyPlan assembly = batch.Assemblies.Add("Trading Service"); TypePlan type = assembly.Types.Add("MarkThree.Guardian.Trading.SourceOrder"); TransactionPlan transaction = batch.Transactions.Add(); MethodPlan methodPlan = transaction.Methods.Add(type, "Insert"); // These are the parameters used to create a Source Order. The Working Order will be created implicitly. methodPlan.Parameters.Add(new InputParameter("blotterId", this.blotter.BlotterId)); methodPlan.Parameters.Add(new InputParameter("isBrokerMatch", sourceOrder.IsBrokerMatch)); methodPlan.Parameters.Add(new InputParameter("isHedgeMatch", sourceOrder.IsHedgeMatch)); methodPlan.Parameters.Add(new InputParameter("isInstitutionMatch", sourceOrder.IsInstitutionMatch)); methodPlan.Parameters.Add(new InputParameter("submissionTypeCode", SubmissionType.UsePeferences)); if (sourceOrder.MaximumVolatility != DBNull.Value) { methodPlan.Parameters.Add(new InputParameter("maximumVolatility", sourceOrder.MaximumVolatility)); } if (sourceOrder.NewsFreeTime != DBNull.Value) { methodPlan.Parameters.Add(new InputParameter("newsFreeTime", sourceOrder.NewsFreeTime)); } methodPlan.Parameters.Add(new InputParameter("orderedQuantity", sourceOrder.Quantity)); methodPlan.Parameters.Add(new InputParameter("orderTypeCode", sourceOrder.OrderTypeCode)); methodPlan.Parameters.Add(new InputParameter("priceTypeCode", PriceType.Market)); methodPlan.Parameters.Add(new InputParameter("securityId", sourceOrder.SecurityId)); methodPlan.Parameters.Add(new InputParameter("settlementId", sourceOrder.SettlementId)); if (sourceOrder.StartTime != DBNull.Value) { methodPlan.Parameters.Add(new InputParameter("startTime", sourceOrder.StartTime)); } if (sourceOrder.StopTime != DBNull.Value) { methodPlan.Parameters.Add(new InputParameter("stopTime", sourceOrder.StopTime)); } methodPlan.Parameters.Add(new InputParameter("timeInForceCode", TimeInForce.Day)); // This will execute the command on the server and return any exceptions. BatchException batchException = null; try { // Execute the batch. ClientMarketData.Execute(batch); } catch (BatchException exception) { // Any exceptions will be captured here and passed on to the foreground. batchException = exception; } // Call the foreground thread with the results of executing the batch on the server. Also, in some cases the dialog is // going to be dismissed when the server data model has finished updating successfully. Pass on the flag to the // foreground that will indicate whether the form is closed once the results are processed. BeginInvoke(this.postEndDelegate, new object[] { exitDialog, batchException }); }
private void DeclineTrade(object parameter) { bool isBatchValid = true; Batch batch = new Batch(); MethodPlan method = null; try { // Lock the tables. System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); ClientMarketData.MatchLock.AcquireReaderLock(ClientTimeout.LockWait); ClientMarketData.OrderTypeLock.AcquireReaderLock(ClientTimeout.LockWait); ClientMarketData.SecurityLock.AcquireReaderLock(ClientTimeout.LockWait); ClientMarketData.WorkingOrderLock.AcquireReaderLock(ClientTimeout.LockWait); // Find the Match record. ClientMarketData.MatchRow matchRow = ClientMarketData.Match.FindByMatchId(this.matchId); AssemblyPlan assembly = batch.Assemblies.Add("Core Service"); TypePlan type = assembly.Types.Add("MarkThree.Guardian.Core.Negotiation"); TransactionPlan transaction = batch.Transactions.Add(); method = transaction.Methods.Add(type, "Insert"); method.Parameters.Add(new InputParameter("matchId", matchId)); method.Parameters.Add(new InputParameter("quantity", 0.0m)); method.Parameters.Add(new InputParameter("statusCode", Status.Declined)); } catch (Exception exception) { // Write the error and stack trace out to the debug listener EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace); // This indicates that the batch shouldn't be executed. isBatchValid = false; } finally { // Release the locks. if (ClientMarketData.MatchLock.IsReaderLockHeld) { ClientMarketData.MatchLock.ReleaseReaderLock(); } if (ClientMarketData.OrderTypeLock.IsReaderLockHeld) { ClientMarketData.OrderTypeLock.ReleaseReaderLock(); } if (ClientMarketData.SecurityLock.IsReaderLockHeld) { ClientMarketData.SecurityLock.ReleaseReaderLock(); } if (ClientMarketData.WorkingOrderLock.IsReaderLockHeld) { ClientMarketData.WorkingOrderLock.ReleaseReaderLock(); } System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); } // If the command batch was built successfully, then execute it. If any part of it should fail, cancel the edit and // display the server errors. if (isBatchValid) { try { // Call the web server to rename the object on the database. Note that this method must be called when there // are no locks to prevent deadlocking. That is why it appears in it's own 'try/catch' block. ClientMarketData.Execute(batch); this.negotiationId = (int)method.Parameters.Return.Value; } catch (BatchException batchException) { // Display each error in the batch. foreach (Exception exception in batchException.Exceptions) { Invoke(new MessageDelegate(ShowMessage), exception.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } } } }
/// <summary> /// Moves a child object from one parent to another. /// </summary> /// <param name="parameter">An array consiting of the target parent, the current parent and the child to be moved.</param> private void MoveChild(object parameter) { // Extract the objects selected by the drag-and-drop operation. object[] parameters = (object[])parameter; MarkThree.Guardian.Object toObject = (MarkThree.Guardian.Object)parameters[0]; MarkThree.Guardian.Object fromObject = (MarkThree.Guardian.Object)parameters[1]; MarkThree.Guardian.Object childObject = (MarkThree.Guardian.Object)parameters[2]; try { // Lock the tables needed for this operation. System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait); ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait); // It's critical that circular references aren't created, either by accident or design. First, find the object // record associated with the destination node. ClientMarketData.ObjectRow parentRow = ClientMarketData.Object.FindByObjectId(toObject.ObjectId); if (parentRow == null) { throw new Exception("This object has been deleted"); } // This is the object that is being dragged. Find the row ClientMarketData.ObjectRow childRow = ClientMarketData.Object.FindByObjectId(childObject.ObjectId); if (childRow == null) { throw new Exception("This object has been deleted"); } // This will remove the possibility of a circular relationship. if (MarkThree.Guardian.Relationship.IsChildObject(childRow, parentRow)) { Invoke(new MessageDelegate(ShowMessage), Properties.Resources.CircularReferenceError, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } catch (Exception exception) { // Write the error and stack trace out to the debug listener EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace); } finally { // Release table locks. if (ClientMarketData.ObjectLock.IsReaderLockHeld) { ClientMarketData.ObjectLock.ReleaseReaderLock(); } if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld) { ClientMarketData.ObjectTreeLock.ReleaseReaderLock(); } System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); } // Any commands created below will be constructed in this object and sent to the server for execution. bool isBatchValid = true; Batch batch = new Batch(); // If we made it here, the drag-and-drop is interpreted as a command to move a child from one parent to another. try { // Lock the tables needed for this operation. System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait); ClientMarketData.ObjectTreeLock.AcquireReaderLock(CommonTimeout.LockWait); // Extract the primary identifiers from the user interface nodes. // This is the object that is being dragged. Find the row ClientMarketData.ObjectRow childRow = ClientMarketData.Object.FindByObjectId(childObject.ObjectId); if (childRow == null) { throw new Exception("This object has been deleted"); } // Find the object in the data model and make sure it still exists. ClientMarketData.ObjectTreeRow objectTreeRow = null; foreach (ClientMarketData.ObjectTreeRow innerObjectTreeRow in childRow.GetObjectTreeRowsByObjectObjectTreeChildId()) { if (innerObjectTreeRow.ParentId == fromObject.ObjectId) { objectTreeRow = innerObjectTreeRow; } } if (objectTreeRow == null) { throw new Exception("This relationship has been deleted by someone else."); } // Moving a child object from one parent to another must be accomplished as a transaction. Otherwise, an // orhpan object will be created if the operation fails midway through. TransactionPlan transaction = batch.Transactions.Add(); AssemblyPlan assembly = batch.Assemblies.Add("Core Service"); TypePlan type = assembly.Types.Add("MarkThree.Guardian.Core.ObjectTree"); // Construct a command delete the old parent relation. MethodPlan deleteObjectTree = transaction.Methods.Add(type, "Update"); deleteObjectTree.Parameters.Add(new InputParameter("objectTreeId", objectTreeRow.ObjectTreeId)); deleteObjectTree.Parameters.Add(new InputParameter("parentId", toObject.ObjectId)); deleteObjectTree.Parameters.Add(new InputParameter("childId", childObject.ObjectId)); deleteObjectTree.Parameters.Add(new InputParameter("rowVersion", objectTreeRow.RowVersion)); } catch (Exception exception) { // Write the error and stack trace out to the debug listener EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace); // This indicates that the batch shouldn't be executed. isBatchValid = false; } finally { // Release table locks. if (ClientMarketData.ObjectLock.IsReaderLockHeld) { ClientMarketData.ObjectLock.ReleaseReaderLock(); } if (ClientMarketData.ObjectTreeLock.IsReaderLockHeld) { ClientMarketData.ObjectTreeLock.ReleaseReaderLock(); } System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); } // If the command batch was built successfully, then execute it. if (isBatchValid) { try { // Call the web server to rename the object on the database. Note that this method must be called when there are // no locks to prevent deadlocking. That is why it appears in it's own 'try/catch' block. ClientMarketData.Execute(batch); } catch (BatchException batchException) { // Display each error in the batch. foreach (Exception exception in batchException.Exceptions) { MessageBox.Show(exception.Message, "Guardian Error"); } } } }
/// <summary> /// Rename the object. /// </summary> /// <param name="parameters">The object to be renamed.</param> private void RenameObject(object parameter) { // Extract the thread arguments object[] parameters = (object[])parameter; TreeNode treeNode = (TreeNode)parameters[0]; string name = (string)parameters[1]; // Extract the object that is associated with the TreeView node. MarkThree.Guardian.Object commonObject = (MarkThree.Guardian.Object)treeNode.Tag; // This command batch is constructed below and sent to the server for execution. Note that the batch is designed to // live beyond the block of code that locks the data model. This is to prevent the data model from being locked while // a relatively long server database operation is underway. bool isBatchValid = true; Batch batch = new Batch(); try { // Lock the table System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); ClientMarketData.ObjectLock.AcquireReaderLock(CommonTimeout.LockWait); // Find the object in the data model and make sure it still exists. ClientMarketData.ObjectRow objectRow = ClientMarketData.Object.FindByObjectId(commonObject.ObjectId); if (objectRow == null) { throw new Exception("This object has been deleted."); } // Construct a command to rename the object. AssemblyPlan assembly = batch.Assemblies.Add("Core Service"); TypePlan type = assembly.Types.Add("MarkThree.Guardian.Core.Object"); TransactionPlan transaction = batch.Transactions.Add(); MethodPlan method = transaction.Methods.Add(type, "Update"); method.Parameters.Add(new InputParameter("rowVersion", objectRow.RowVersion)); method.Parameters.Add(new InputParameter("objectId", objectRow.ObjectId)); method.Parameters.Add(new InputParameter("name", name)); } catch (Exception exception) { // This serves as an indication that the batch couldn't be constructed. isBatchValid = false; // Write the error and stack trace out to the debug listener EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace); } finally { // Release table locks. if (ClientMarketData.ObjectLock.IsReaderLockHeld) { ClientMarketData.ObjectLock.ReleaseReaderLock(); } System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); } // If the command batch was built successfully, then execute it. If any part of it should fail, cancel the edit and // display the server errors. if (isBatchValid) { try { // Call the web server to rename the object on the database. Note that this method must be called when there // are no locks to prevent deadlocking. That is why it appears in it's own 'try/catch' block. ClientMarketData.Execute(batch); } catch (BatchException batchException) { // Display each error in the batch. foreach (Exception exception in batchException.Exceptions) { Invoke(new MessageDelegate(ShowMessage), exception.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } } } }
/// <summary> /// Execute a command batch and synchronizes the client data model with the newer records from the server. /// </summary> public static void Execute(Batch batch) { // This 'try' block will insure that the mutual exclusion locks are released. try { // Make sure only one thread at a time tries to refresh the data model. ClientMarketData.clientDataMutex.WaitOne(); // Switching credentials without exiting the application will force the data model to be cleared and the row // counting to begin at zero again. That is, it effectively resets the client data model. if (ClientMarketData.isReset) { ClientMarketData.isReset = false; ClientMarketData.rowVersion = 0; ClientMarketData.Clear(); } // IMPORTANT CONCEPT: The rowVersion keeps track of the state of the client in-memory database. The server // returns a value for us to use on the next cycle. long rowVersion = ClientMarketData.rowVersion; // IMPORTANT CONCEPT: Executing the 'GetClientMarketData' with a rowVersion returns to the client a DataSet // with only records that are the same age or younger than the rowVersion. This reduces the traffic on the // network to include only the essential records. We are also merging it with the current ClientMarketData, // which adds new records and records that were deleted by the server. AssemblyPlan assembly = batch.Assemblies.Add("Server Market Data"); TypePlan type = assembly.Types.Add("MarkThree.Guardian.Server.ServerMarketData"); TransactionPlan transaction = batch.Transactions.Add(); MethodPlan method = transaction.Methods.Add(type, "Reconcile"); Parameter rowVersionParameter = method.Parameters.Add(new InputParameter("rowVersion", rowVersion)); // Execute the the command to get the incremental changes from the server. WebTransactionProtocol.Execute(batch); // This is the updated data model information returned from the server. ArrayList reconciledData = (ArrayList)method.Parameters.Return.Value; // Optimization: Don't merge the results if there's nothing to merge. if (reconciledData != null) { // IMPORTANT CONCEPT: Since the results will still be on the server if the client misses a refresh // cycle, we take the attitude that thBzis update process doesn't have to wait for locks. That is, if we // can't get all the tables locked quickly, we'll just wait until the next refresh period to get the // results. This effectively prevents deadlocking on the client. Make sure all the tables are locked // before populating them. foreach (TableLock tableLock in ClientMarketData.TableLocks) { tableLock.AcquireWriterLock(ClientTimeout.LockWait); } // IMPORTANT CONCEPT: This broadcast can be used to set up conditions for the data event handlers. Often, // optimizing algorithms will be used to consolidate the results of a merge. This will allow the event // driven logic to clear previous results and set up initial states for handling the bulk update of data. ClientMarketData.OnBeginMerge(typeof(ClientMarketData)); // IMPORANT CONCEPT: Once all the write locks have been obtained, we can merge the results. This will // trigger the events associated with the tables for updated and deleted rows. Note that this 'Merge' // method has different characteristics than the original one provided by Microsoft (that is, this one // works). ClientMarketData.rowVersion = MarketData.Merge(reconciledData); // IMPORTANT CONCEPT: When the merge is complete, this will broadcast an event which allows optimization code // to consolidate the results, examine the changed values and update reports based on the changed data. ClientMarketData.OnEndMerge(typeof(ClientMarketData)); } } finally { // No matter what happens above, we need to release the locks acquired above. foreach (TableLock tableLock in ClientMarketData.TableLocks) { if (tableLock.IsWriterLockHeld) { tableLock.ReleaseWriterLock(); } } // Other threads can now request a refresh of the data model. ClientMarketData.clientDataMutex.ReleaseMutex(); } // Throw a specialized exception if the server returned any errors in the Batch structure. if (batch.HasExceptions) { throw new BatchException(batch); } }
/// <summary> /// Load the XML script. /// </summary> public void Load() { // This flag is set when an error occurs anywhere in the processing of the XML file. this.HasErrors = false; // Read the XML data from the specified file. XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(this.FileName); // Sending records to the server is state driven. This loop will collect a batch of commands until a new table is // found in the XML stream, or until the limit of a batch is reached, or until the end of the file is read. The idea // is to allow several tables of data to exist in a single file. XmlNode rootNode = xmlDocument.DocumentElement; // The script name is stored in the root node. The name is used in status and debugging messages. this.ScriptName = rootNode.Attributes["name"] == null ? "Unnamed Batch" : rootNode.Attributes["name"].Value; // If the user wants to specify a new URL and certificate, then prompt for the connection info the next time a // WebTransactionProtocol sends off a batch. if (this.ForceLogin) { WebTransactionProtocol.IsUrlPrompted = true; WebTransactionProtocol.IsCredentialPrompted = true; } // Create a batch to hold the transactions. this.batch = new Batch(); // As methods are parsed, they're added to this transaction. The organization of the transaction is determined by the // input file. Explicit transaction will create their own transactions when they appear in the file. Implicit // transactions are created when an unaffiliated method element is parsed out of the XML file. this.transaction = null; // The batch is sent when this flag is set. bool sendBatch = false; // Cycle through all of the children of the root node. The methods in this file will either be affiliated with an // explicit transaction, or be unaffiliated. The 'free' methods will be packed together in an implicit transaction and // sent to the server when the transaction reaches a predetermined size. This will search the file for both kinds of // records. foreach (XmlNode xmlNode in rootNode) { // A 'transaction' element is a command for an explicit transaction. A 'method' element declares a method for an // implicit (internally created) transaction. switch (xmlNode.Name) { case "transaction": // Parse the methods out of the node and send the batch off to the server for execution. ParseTransaction(xmlNode); break; case "send": // Transactions can be grouped together in a file. They are not sent to the Web Transaction handler until // either the end of the file, or an explicit 'send' node. sendBatch = true;; break; case "method": // For an implicit method execution, a transaction will be created automatically. When the batch is sent, this // value will be cleared again. if (this.transaction == null) { this.transaction = this.batch.Transactions.Add(); } // Parse the method out of the XML node. ParseMethod(xmlNode); // If the size of the transaction has reached the predetermined limit, then the batch can be sent. if (this.transaction.Methods.Count == this.TransactionSize) { sendBatch = true; } break; } // If the parser has determined that the batch is large enough, then it is sent to the server. if (sendBatch) { // Send the batch to the server. SendBatch(batch); // Prepare a brand new batch for the records remaining to be parsed. this.batch = new Batch(); this.transaction = null; sendBatch = false; } } // If a transaction has been initialized but not sent, then send the batch. if (batch.Transactions.Count != 0) { SendBatch(batch); } // Wait here until all the IO requests have completed. this.requestCompleted.WaitOne(); }
/// <summary> /// Read, parse and load the stylesheet into the middle tier. /// </summary> public void Load() { // If this flag is set during the processing of the file, the program will exit with an error code. this.HasErrors = false; // If the user wants to specify a new URL and certificate, then prompt for the connection info the next time a // WebTransactionProtocol sends off a batch. if (this.ForceLogin) { WebTransactionProtocol.IsUrlPrompted = true; WebTransactionProtocol.IsCredentialPrompted = true; } // Load up an XML document with the contents of the file specified on the command line. XmlDocument stylesheet = new XmlDocument(); stylesheet.Load(this.FileName); // The XML document has several nodes that need to be read -- and then removed -- that contain attributes of the // stylesheet. These nodes can be found easily using the XSL Path functions which need a namespace manager to sort out // the tag prefixes. XmlNamespaceManager namespaceManager = new XmlNamespaceManager(stylesheet.NameTable); namespaceManager.AddNamespace("xsl", "http://www.w3.org/1999/XSL/Transform"); namespaceManager.AddNamespace("mts", "urn:schemas-markthreesoftware-com:stylesheet"); // The spreadhseet source has several nodes which contain information about how the data in the XML document should be // loaded into the server, such as the stylesheet identifier, the name and the stylesheet style. They are found at // this node. After these information nodes have been read, they are removed from the stylesheet source. XmlNode stylesheetNode = stylesheet.SelectSingleNode("xsl:stylesheet", namespaceManager); if (stylesheetNode == null) { throw new Exception("Syntax Error: missing stylesheet declaration."); } // Find the StylesheetId node. XmlNode StylesheetIdNode = stylesheetNode.SelectSingleNode("mts:stylesheetId", namespaceManager); if (StylesheetIdNode == null) { throw new Exception("Syntax Error: missing StylesheetId declaration."); } // Find the StylesheetStyle node. XmlNode stylesheetTypeCodeNode = stylesheetNode.SelectSingleNode("mts:stylesheetTypeCode", namespaceManager); if (stylesheetTypeCodeNode == null) { throw new Exception("Syntax Error: missing StylesheetStyle declaration."); } // Find the name node. XmlNode nameNode = stylesheetNode.SelectSingleNode("mts:name", namespaceManager); if (nameNode == null) { throw new Exception("Syntax Error: missing name declaration."); } // Extract the data from the XML nodes. this.StylesheetId = StylesheetIdNode.InnerText; this.StylesheetTypeCode = stylesheetTypeCodeNode.InnerText; this.StylesheetName = nameNode.InnerText; // Remove the stylesheet nodes from the XSL spreadsheet before loading it into the server. stylesheetNode.RemoveChild(StylesheetIdNode); stylesheetNode.RemoveChild(stylesheetTypeCodeNode); stylesheetNode.RemoveChild(nameNode); // Create a command to load the stylesheet from the data loaded from the file. Batch batch = new Batch(); TransactionPlan transaction = batch.Transactions.Add(); AssemblyPlan assembly = batch.Assemblies.Add(this.Assembly); TypePlan type = assembly.Types.Add(this.Type); MethodPlan method = transaction.Methods.Add(type, this.Method); method.Parameters.Add(new InputParameter("stylesheetId", this.StylesheetId)); method.Parameters.Add(new InputParameter("stylesheetTypeCode", this.StylesheetTypeCode)); method.Parameters.Add(new InputParameter("name", this.StylesheetName)); method.Parameters.Add(new InputParameter("text", stylesheet.InnerXml)); try { // Create a new web client that will serve as the connection point to the server and call the web services to execute // the command batch. WebTransactionProtocol.Execute(batch); } catch (BatchException) { foreach (MethodPlan batchMethod in transaction.Methods) { foreach (Exception exception in batchMethod.Exceptions) { Console.WriteLine(String.Format("{0}: {1}", method.Parameters["StylesheetId"].Value, exception.Message)); } } this.HasErrors = true; } }
/// <summary> /// Marshals the data needed refuse a chance to negotiate a trade. /// </summary> /// <param name="parameter">The thread initialization data.</param> private void DeclineNegotiationThread(object parameter) { // Extract the thread parameters int matchId = (int)parameter; // This batch, if succesfully constructed, will be sent to the server to deline the negotiation. Batch batch = new Batch(); try { // Lock the tables. System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); ClientMarketData.MatchLock.AcquireReaderLock(ClientTimeout.LockWait); ClientMarketData.OrderTypeLock.AcquireReaderLock(ClientTimeout.LockWait); ClientMarketData.SecurityLock.AcquireReaderLock(ClientTimeout.LockWait); ClientMarketData.WorkingOrderLock.AcquireReaderLock(ClientTimeout.LockWait); // Find the Match record. ClientMarketData.MatchRow matchRow = ClientMarketData.Match.FindByMatchId(matchId); // Construct a command decline the negotiation. AssemblyPlan assembly = batch.Assemblies.Add("Core Service"); TypePlan type = assembly.Types.Add("MarkThree.Guardian.Core.Negotiation"); TransactionPlan transaction = batch.Transactions.Add(); MethodPlan method = transaction.Methods.Add(type, "Insert"); method.Parameters.Add(new InputParameter("matchId", matchId)); method.Parameters.Add(new InputParameter("quantity", 0.0m)); method.Parameters.Add(new InputParameter("statusCode", Status.Declined)); } catch (Exception exception) { // Write the error and stack trace out to the debug listener EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace); // This indicates that the batch shouldn't be executed. batch = null; } finally { // Release the locks. if (ClientMarketData.MatchLock.IsReaderLockHeld) { ClientMarketData.MatchLock.ReleaseReaderLock(); } if (ClientMarketData.OrderTypeLock.IsReaderLockHeld) { ClientMarketData.OrderTypeLock.ReleaseReaderLock(); } if (ClientMarketData.SecurityLock.IsReaderLockHeld) { ClientMarketData.SecurityLock.ReleaseReaderLock(); } if (ClientMarketData.WorkingOrderLock.IsReaderLockHeld) { ClientMarketData.WorkingOrderLock.ReleaseReaderLock(); } System.Diagnostics.Debug.Assert(!ClientMarketData.IsLocked); } // If the command batch was built successfully, then execute it. if (batch != null) { try { // Call the web server to rename the object on the database. Note that this method must be called when there // are no locks to prevent deadlocking. That is why it appears in it's own 'try/catch' block. ClientMarketData.Execute(batch); } catch (BatchException batchException) { // Write any server generated error messages to the event log. foreach (Exception exception in batchException.Exceptions) { EventLog.Error("{0}, {1}", exception.Message, exception.StackTrace); } } } }