From stonehenge-commits-return-191-apmail-incubator-stonehenge-commits-archive=incubator.apache.org@incubator.apache.org Fri Feb 13 12:05:32 2009 Return-Path: Delivered-To: apmail-incubator-stonehenge-commits-archive@minotaur.apache.org Received: (qmail 18320 invoked from network); 13 Feb 2009 12:05:31 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 13 Feb 2009 12:05:31 -0000 Received: (qmail 90127 invoked by uid 500); 13 Feb 2009 12:05:31 -0000 Delivered-To: apmail-incubator-stonehenge-commits-archive@incubator.apache.org Received: (qmail 90107 invoked by uid 500); 13 Feb 2009 12:05:31 -0000 Mailing-List: contact stonehenge-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: stonehenge-dev@incubator.apache.org Delivered-To: mailing list stonehenge-commits@incubator.apache.org Received: (qmail 90096 invoked by uid 99); 13 Feb 2009 12:05:31 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 13 Feb 2009 04:05:31 -0800 X-ASF-Spam-Status: No, hits=-1998.5 required=10.0 tests=ALL_TRUSTED,WEIRD_PORT X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 13 Feb 2009 12:05:18 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id E9AA623889D0; Fri, 13 Feb 2009 12:04:56 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r744093 [1/2] - in /incubator/stonehenge/trunk/stocktrader/ruby: ./ order_processor/ order_processor/controllers/ order_processor/controllers/keys/ order_processor/controllers/policies/ trader_client/ trader_client/controllers/ trader_clien... Date: Fri, 13 Feb 2009 12:04:56 -0000 To: stonehenge-commits@incubator.apache.org From: shankar@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090213120456.E9AA623889D0@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: shankar Date: Fri Feb 13 12:04:55 2009 New Revision: 744093 URL: http://svn.apache.org/viewvc?rev=744093&view=rev Log: ruby stock trader added. Refer https://issues.apache.org/jira/browse/STONEHENGE-7 Added: incubator/stonehenge/trunk/stocktrader/ruby/ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/data_access_layer.rb incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/database_config.xml incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_cert.cert incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_key.pem incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_cert.cert incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_key.pem incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor.rb incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_client.rb incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_controller.rb incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_msec_controller.rb incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/policies/ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/policies/order_processor_policy.xml incubator/stonehenge/trunk/stocktrader/ruby/trader_client/ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/application.rb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_controller.rb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_logic.rb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_utils.rb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/layouts/ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/layouts/default.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/account.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/config.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/confirmation.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/glossary.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/home.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/index.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/login.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/portfolio.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/quotes.html.erb incubator/stonehenge/trunk/stocktrader/ruby/trader_client/views/trade/register.html.erb Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/data_access_layer.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/data_access_layer.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/data_access_layer.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/data_access_layer.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,96 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + + +# This class encapsulates information regarding the establishment +# of database connection. +class ConnectionInfo + attr_accessor :server, :user, :password, :database +end + +# The method retrieves information for the database connection +# from a configuration file. The name of the config file should +# be, database_config.xml, and it should be in the same directory +# as this file. +# @return non NULL value (ConnectionInfo object), upon successfull +# execution, and NULL if some information regarding the +# connection is not available. +def GetConnectionInfo() + input = File.new('./app/controllers/database_config.xml') + unless input.nil? + doc = REXML::Document.new(input) + unless doc.nil? + root_element = doc.root + connectionInfo = ConnectionInfo.new(); + server = REXML::XPath.match(root_element, "/config/server") + if(server) + connectionInfo.server = server[0].get_text.to_s; + end + user = REXML::XPath.match(root_element, "/config/user") + if(user) + connectionInfo.user = user[0].get_text.to_s; + end + password = REXML::XPath.match(root_element, "/config/password") + if(password) + connectionInfo.password = password[0].get_text.to_s; + end + database = REXML::XPath.match(root_element, "/config/database") + if(database) + connectionInfo.database = database[0].get_text.to_s; + end + end + end + + if((connectionInfo) && (connectionInfo.server != "") && (connectionInfo.user != "") && + (connectionInfo.password != "") && (connectionInfo.database != "")) + return connectionInfo; + elsif + puts "Cannot get database configuration details \n" + return nil + end +end + +# This method establishes a connection to the database. +# @return dbhandle, upon successfull execution a non null +# handle to the database connection is returned. Else it +# will be null. +def ConnectToDatabase() + require 'dbi' + connInfo = GetConnectionInfo() + connStr = 'DBI:ADO:Provider=SQLNCLI;Data Source="' + connInfo.server + '";Initial Catalog="' + connInfo.database + '";User ID="' + connInfo.user + '";password="' + connInfo.password + '"' + if(connInfo) + dbConn = DBI.connect(connStr) + end + return dbConn +end + +# This method executes a query that it receives. +# @param dbConn db connection +# @param query the query to execute +# @return non-NULL upon success and NULL otherwise. +def ExecuteQuery(dbConn, query) + if(dbConn) + return dbConn.execute(query) + end +end + +# This method close the connection that is established to the +# database. +# @param dbhandle handle to the database +def CloseDatabase(dbConn) + dbConn.disconnect() +end + Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/database_config.xml URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/database_config.xml?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/database_config.xml (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/database_config.xml Fri Feb 13 12:04:55 2009 @@ -0,0 +1,6 @@ + + 127.0.0.1,1433 + trade + trade + StockTraderDB + Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_cert.cert URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_cert.cert?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_cert.cert (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_cert.cert Fri Feb 13 12:04:55 2009 @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDDCCAfSgAwIBAgIQM6YEf7FVYx/tZyEXgVComTANBgkqhkiG9w0BAQUFADAw +MQ4wDAYDVQQKDAVPQVNJUzEeMBwGA1UEAwwVT0FTSVMgSW50ZXJvcCBUZXN0IENB +MB4XDTA1MDMxOTAwMDAwMFoXDTE4MDMxOTIzNTk1OVowQjEOMAwGA1UECgwFT0FT +SVMxIDAeBgNVBAsMF09BU0lTIEludGVyb3AgVGVzdCBDZXJ0MQ4wDAYDVQQDDAVB +bGljZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAoqi99By1VYo0aHrkKCNT +4DkIgPL/SgahbeKdGhrbu3K2XG7arfD9tqIBIKMfrX4Gp90NJa85AV1yiNsEyvq+ +mUnMpNcKnLXLOjkTmMCqDYbbkehJlXPnaWLzve+mW0pJdPxtf3rbD4PS/cBQIvtp +jmrDAU8VsZKT8DN5Kyz+EZsCAwEAAaOBkzCBkDAJBgNVHRMEAjAAMDMGA1UdHwQs +MCowKKImhiRodHRwOi8vaW50ZXJvcC5iYnRlc3QubmV0L2NybC9jYS5jcmwwDgYD +VR0PAQH/BAQDAgSwMB0GA1UdDgQWBBQK4l0TUHZ1QV3V2QtlLNDm+PoxiDAfBgNV +HSMEGDAWgBTAnSj8wes1oR3WqqqgHBpNwkkPDzANBgkqhkiG9w0BAQUFAAOCAQEA +BTqpOpvW+6yrLXyUlP2xJbEkohXHI5OWwKWleOb9hlkhWntUalfcFOJAgUyH30TT +pHldzx1+vK2LPzhoUFKYHE1IyQvokBN2JjFO64BQukCKnZhldLRPxGhfkTdxQgdf +5rCK/wh3xVsZCNTfuMNmlAM6lOAg8QduDah3WFZpEA0s2nwQaCNQTNMjJC8tav1C +Br6+E5FAmwPXP7pJxn9Fw9OXRyqbRA4v2y7YpbGkG2GI9UvOHw6SGvf4FRSthMMO +35YbpikGsLix3vAsXWWi4rwfVOYzQK0OFPNi9RMCUdSH06m9uLWckiCxjos0FQOD +ZE9l4ATGy9s9hNVwryOJTw== +-----END CERTIFICATE----- Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_key.pem URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_key.pem?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_key.pem (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/alice_key.pem Fri Feb 13 12:04:55 2009 @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCiqL30HLVVijRoeuQoI1PgOQiA8v9KBqFt4p0aGtu7crZcbtqt +8P22ogEgox+tfgan3Q0lrzkBXXKI2wTK+r6ZScyk1wqctcs6OROYwKoNhtuR6EmV +c+dpYvO976ZbSkl0/G1/etsPg9L9wFAi+2mOasMBTxWxkpPwM3krLP4RmwIDAQAB +AoGAY+fazB357rE1YVrh2hlgwh6lr3YRASmzaye+MLOAdNCPW5Sm8iFL5Cn7IU2v +/kKi2eW21oeaLtFzsMU9W2LJP6h33caPcMr/1F3wsiHRCBSZiRLgroYnryJ2pWRq +B8r6/j1mCKzNkoxwspUS1tPFIT0yJB4L/bQGMIvnoM4v5aECQQDX2hBKRbsQYSgL +xZmqx/KJG7+rcpjYXBcztcO09sAsJ+tJe7FPKoKB1CG/KWqj8KQn69blXxhKRDTp +rPZLiU7RAkEAwOnfR+dwLbnNGTuafvvbWE1d0CCa3YGooCrrCq4Af7D5jv9TZXDx +yOIZsHzQH5U47e9ht2JvYllbTlMhirKsqwJBAKbyAadwRz5j5pU0P6XW/78LtzLj +b1Pn5goYi0VrkzaTqWcsQ/b26fmAGJnBbrldZZl6zrqY0jCekE4reFLz4AECQA7Y +MEFFMuGh4YFmj73jvX4u/eANEj2nQ4WHp+x7dTheMuXpCc7NgR13IIjvIci8X9QX +Toqg/Xcw7xC43uTgWN8CQF2p4WulNa6U64sxyK1gBWOr6kwx6PWU29Ay6MPDPAJP +O84lDgb5dlC1SGE+xHUzPPN6E4YFI/ECawOHNrADEsE= +-----END RSA PRIVATE KEY----- Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_cert.cert URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_cert.cert?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_cert.cert (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_cert.cert Fri Feb 13 12:04:55 2009 @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDCjCCAfKgAwIBAgIQYDju2/6sm77InYfTq65x+DANBgkqhkiG9w0BAQUFADAw +MQ4wDAYDVQQKDAVPQVNJUzEeMBwGA1UEAwwVT0FTSVMgSW50ZXJvcCBUZXN0IENB +MB4XDTA1MDMxOTAwMDAwMFoXDTE4MDMxOTIzNTk1OVowQDEOMAwGA1UECgwFT0FT +SVMxIDAeBgNVBAsMF09BU0lTIEludGVyb3AgVGVzdCBDZXJ0MQwwCgYDVQQDDANC +b2IwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMCquMva4lFDrv3fXQnKK8Ck +SU7HvVZ0USyJtlL/yhmHH/FQXHyYY+fTcSyWYItWJYiTZ99PAbD+6EKBGbdfuJNU +JCGaTWc5ZDUISqM/SGtacYe/PD/4+g3swNPzTUQAIBLRY1pkr2cm3s5Ch/f+mYVN +BR41HnBeIxybw25kkoM7AgMBAAGjgZMwgZAwCQYDVR0TBAIwADAzBgNVHR8ELDAq +MCiiJoYkaHR0cDovL2ludGVyb3AuYmJ0ZXN0Lm5ldC9jcmwvY2EuY3JsMA4GA1Ud +DwEB/wQEAwIEsDAdBgNVHQ4EFgQUXeg55vRyK3ZhAEhEf+YT0z986L0wHwYDVR0j +BBgwFoAUwJ0o/MHrNaEd1qqqoBwaTcJJDw8wDQYJKoZIhvcNAQEFBQADggEBAIiV +Gv2lGLhRvmMAHSlY7rKLVkv+zEUtSyg08FBT8z/RepUbtUQShcIqwWsemDU8JVts +ucQLc+g6GCQXgkCkMiC8qhcLAt3BXzFmLxuCEAQeeFe8IATr4wACmEQE37TEqAuW +EIanPYIplbxYgwP0OBWBSjcRpKRAxjEzuwObYjbll6vKdFHYIweWhhWPrefquFp7 +TefTkF4D3rcctTfWJ76I5NrEVld+7PBnnJNpdDEuGsoaiJrwTW3Ixm40RXvG3fYS +4hIAPeTCUk3RkYfUkqlaaLQnUrF2hZSgiBNLPe8gGkYORccRIlZCGQDEpcWl1Uf9 +OHw6fC+3hkqolFd5CVI= +-----END CERTIFICATE----- Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_key.pem URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_key.pem?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_key.pem (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/keys/bob_key.pem Fri Feb 13 12:04:55 2009 @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDAqrjL2uJRQ679310JyivApElOx71WdFEsibZS/8oZhx/xUFx8 +mGPn03EslmCLViWIk2ffTwGw/uhCgRm3X7iTVCQhmk1nOWQ1CEqjP0hrWnGHvzw/ ++PoN7MDT801EACAS0WNaZK9nJt7OQof3/pmFTQUeNR5wXiMcm8NuZJKDOwIDAQAB +AoGBAL9MxBAlVXG68pXAonCF/MtaVC+Uw7qD49WFJzNiJxkRwfWpBSvxY8FbgJP0 +/Addkgb51bk0iUlk0Ni3twEMWga0j9jOJLkDDoXfpHmH5HGTvNa9m241PGQ+kzAU +dFvFzR0qUTDlBjk4pYoeqoJBTgNZGu3b3BHEbz7O7PAJUQEBAkEA8Rwrf7/pSiPH +2pfU5StQ77+1Uva5VHpDoKLC5mgAgiPvQm2yBBSXkwPwXHEeRYEOfHydtCrudQY3 +6fVP4Oy1GQJBAMyQsI6CIjEwZzS1KXLb+ulpFBjcK99PydBGKxRue/o0ZpD69siA +AL4YqyXl4Ai4hEHHe7FxeJe4Wzp6F0A6kXMCQQCpC8QfzHEHTzDnPP7CMm2LupCp ++1wTM6nIrXUS0CZTGFi+7WQbYkinheJ3HcRInOSIOWLkmBkaKWL4gMshezS5AkB8 +1G5pCBBFY/wWtdYtOP/MH0scQH6lLtNAPRFczm7pJ8DPB9ZAU5wgZH1MCxLDP5W1 +bj2U8mFcdCt3a7l0gEjxAkEAwoWqq6i7ZfFg4LUcKElZhjMeF8tKs1fWHhunO80t +6hQUhBHahc4+AAgoXOMe+KAxa+F6uftjM9eg8rAAZ+6q3g== +-----END RSA PRIVATE KEY----- Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,427 @@ + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +ORDER_TYPE_BUY = "buy" +ORDER_TYPE_SELL = "sell" +ORDER_STATUS_CLOSED = "closed" +STATUS_SUCCESS = 1 +STATUS_FAILURE = 0 +INVALID_ID = -1 + +require "data_access_layer.rb" + +# This class encapsulates information regarding the order +class Order + attr_accessor :orderID, :orderType, :orderStatus, :quantity, :price, :orderFee, :symbol +end + +# This class encapsulate information regarding a particular quote. The +# quote information related to a particular symbol, have to be analyzed +# in order to process an order. +class Quote + attr_accessor :low, :open1, :volume, :price, :high, :symbol, :change1 +end + +# This class encapsulates information regarding a particular holding. +# Each buy order creates a holding object and stores an entry in the +# holding table. +class Holding + attr_accessor :purchasePrice, :holdingID, :quantity, :purchaseDate, :accountID, :quoteSymbol +end + +# This is the primary function which corresponds to the SubmitOrder +# operation. +def ProcessOrder(order) + status = STATUS_SUCCESS + dbhandle = ConnectToDatabase() + + #This method with "BEGIN TRAN" initialize a transaction; which privides + #control so that later we can cancel a the transaction, if something + #goes wrong. + commitStatus = dbhandle['AutoCommit'] + dbhandle['AutoCommit'] = false + quote = GetQuoteForUpdate(dbhandle, order.symbol) + if (quote) + order.price = quote.price + +=begin + Buy or sell orders either first creates a holding or sell a + holding. The return value is the holdingID upon success. If NULL + is returned, then the tranaction can not be completed. This is due + to either problem of accessing the database or if there is no + maching holding. + + upon success, total price should be deducted from account's balance. + In case of sell, balance should increase. So, in sell case, total price will be + negative value +=end + + if (order.orderType == ORDER_TYPE_BUY) + holdingID = CreateHolding(dbhandle, order) + if (holdingID != INVALID_ID) + totalPrice = order.quantity * order.price + order.orderFee + end + end + + if (order.orderType == ORDER_TYPE_SELL) + holdingID = SellHolding(dbhandle, order) + if (holdingID != INVALID_ID) + totalPrice = -1 * order.quantity * order.price + order.orderFee + end + end + + if (holdingID != INVALID_ID) + status = UpdateSystemStatus(dbhandle, order, quote, holdingID, totalPrice) + else + puts "Holding id for order with order id " + order.orderID.to_s + " is not valid\n" + status = STATUS_FAILURE + end + else + puts "Cannot get quote with symbol " + order.symbol + "\n" + status = STATUS_FAILURE + end + + if (status == STATUS_SUCCESS) + #Transaction is successfull, we can safely commit the transaction + #into the database. + dbhandle.commit + else + #Transaction is not successfull, we can safely rollback the + #transaction without commiting to the database. + dbhandle.rollback + end + dbhandle['AutoCommit'] = commitStatus + CloseDatabase(dbhandle) +end + +# This method, retrieves all the information related to a particular symbol +# from the QUOTE table. +# @param symbol is the symbol we are looking for +# @return quote object filled with symbol information upons success and else +# NULL is returned. +def GetQuoteForUpdate(dbhandle, symbol) + quote = nil + query = "Set NOCOUNT ON; SELECT SYMBOL, COMPANYNAME, VOLUME, PRICE, " + + "OPEN1, LOW, HIGH, CHANGE1 FROM QUOTE WITH (NOLOCK) WHERE SYMBOL " + + "= '" + symbol +"'" + + result = ExecuteQuery(dbhandle, query) + if (result) + row = result.fetch + if(row) + quote = Quote.new() + quote.symbol = row[0] #Get the symbol. + quote.price = row[3].to_f #Get the price. + quote.low = row[5].to_f #Get the low value. + quote.high = row[6].to_f #Get the high value. + end + result.finish + end + return quote +end + +# This method updates all the system information relates to a particular +# buy or sell operation. +# @param order order object +# @param quote quote object +# @param holdingID holdingID of the holding which relates to the current order +# @param totalPrice the price change (amount of money the flows in/out of a +# user's account). +# @return STATUS_SUCCESS upon success and STATUS_FAILURE otherwise. +def UpdateSystemStatus(dbhandle, order, quote, holdingID, totalPrice) + status = STATUS_SUCCESS + accountID = GetAccountIDFromOrder(dbhandle, order) + if (accountID != INVALID_ID) + if(UpdateAccountBalance(dbhandle, accountID, totalPrice) == STATUS_SUCCESS) + if(UpdateStockPriceVolume(dbhandle, order.quantity, quote) == STATUS_SUCCESS) + if(CloseOrder(dbhandle, order, holdingID) == STATUS_FAILURE) + puts "Cannot close order for order id " + order.orderID.to_s + " \n" + status = STATUS_FAILURE + end + else + puts "Cannot update stock price volume for symbol " + quote.symbol + "\n" + status = STATUS_FAILURE + end + else + puts "Cannot update account balace for account id " + accountID.to_s + "\n" + status = STATUS_FAILURE + end + else + puts "Account id for order id " + order.orderID.to_s + " is not valid \n" + status = STATUS_FAILURE + end + return status +end + +# This function corresponds to a sell operation. It matches a particular +# holding related to a particular order (symbol) and then do the transaction +# @param order order object +# @return a valid holdingID upon success and INVALID_ID otherwise. +def SellHolding(dbhandle, order) + holding = GetHoldingForUpdate(dbhandle, order) + if (holding) + accountID = holding.accountID + quantity = order.quantity + holdingQuantity = holding.quantity + + if (order.quantity < holding.quantity) + if(UpdateHolding(dbhandle, holding, order.quantity) == STATUS_FAILURE) + puts "Cannot update holding with holding id " + holding.holdingID.to_s + " \n" + holding.holdingID = INVALID_ID + end + elsif (order.quantity == holding.quantity) + if(DeleteHolding(dbhandle, holding) == STATUS_FAILURE) + puts "Cannot delete holding with holding id " + holding.holdingID.to_s + " \n" + holding.holdingID = INVALID_ID + end + else + if(DeleteHolding(dbhandle, holding) == STATUS_FAILURE) + puts "Cannot delete holding with holding id " + holding.holdingID.to_s + " \n" + holding.holdingID = INVALID_ID + else + order.quantity = holding.quantity + if(UpdateOrder(dbhandle, order) == STATUS_FAILURE) + puts "Cannot update order with order id " + order.orderID.to_s + " \n" + holding.holdingID = INVALID_ID + end + end + end + else + puts "Holding for order id " + order.orderID.to_s + " is not valid \n" + holding.holdingID = INVALID_ID + end + return holding.holdingID +end + +# This method updates the status of an order as a result of a buy or sell +# operation. +# @param order order object +# @return a Holding object upon success and NULL otherwise. +def UpdateOrder(dbhandle, order) + query = "UPDATE ORDERS WITH (ROWLOCK) SET QUANTITY='" + order.quantity.to_s + "' WHERE" + + " ORDERID='" + order.orderID.to_s + "'" + result = ExecuteQuery(dbhandle, query) + if(result) + status = STATUS_SUCCESS + result.finish + else + status = STATUS_FAILURE + end + return status +end + +# This method updates a particular Holing entry in the HOLDING table. +# @param holding is the holding object. +# @param quantity is the amount of buy or sell. +# @return a Holding object upon success and NULL otherwise. +def UpdateHolding(dbhandle, holding, quantity) + query = "UPDATE HOLDING WITH (ROWLOCK) SET QUANTITY=QUANTITY-'" + quantity.to_s + "'" + + " WHERE HOLDINGID='" + holding.holdingID.to_s + "'" + result = ExecuteQuery(dbhandle, query) + if(result) + status = STATUS_SUCCESS + result.finish + else + status = STATUS_FAILURE + end + return status +end + +# Removes an entry from the HOLDING table when a matching order is received. +# @param holding is a holding object. +# @return STATUS_SUCCESS value on success and STATUS_FAILURE otherwise. +def DeleteHolding(dbhandle, holding) + query = "DELETE FROM HOLDING WITH (ROWLOCK) WHERE HOLDINGID='" + holding.holdingID.to_s + "'" + result = ExecuteQuery(dbhandle, query) + if(result) + status = STATUS_SUCCESS + result.finish + else + status = STATUS_FAILURE + end + return status +end + +# This method returns a quote object which matches to the particular sell +# order. +# @param order the order object. +# @return a Holding object upon success and NULL otherwise. +def GetHoldingForUpdate(dbhandle, order) + holding = nil + query = "Set NOCOUNT ON; SELECT HOLDING.HOLDINGID, HOLDING.ACCOUNT_ACCOUNTID,"+ + " HOLDING.QUANTITY, HOLDING.PURCHASEPRICE, HOLDING.PURCHASEDATE,"+ + " HOLDING.QUOTE_SYMBOL FROM HOLDING WITH (ROWLOCK) INNER JOIN ORDERS"+ + " ON HOLDING.HOLDINGID = ORDERS.HOLDING_HOLDINGID WHERE "+ + "(ORDERS.ORDERID = '" + order.orderID.to_s + "')" + + #Get the machining tuple from HOLDING table, that corresponds to the + #current sell operation. + result = ExecuteQuery(dbhandle, query) + if (result) + row = result.fetch + if(row) + holding = Holding.new() + holding.holdingID = row[0] #Get the holdingID. + holding.accountID = row[1] #Get the accountID. + holding.quantity = row[2] #Get the quantity. + holding.purchasePrice = row[3] #Get the price. + holding.purchaseDate = row[4] #Get the date. + holding.quoteSymbol = row[5] #Get the symbol. + else + puts "Cannot obtain holding for order id " + order.orderID.to_s + "\n" + end + result.finish + else + puts "Cannot obtain holding for order id " + order.orderID.to_s + "\n" + end + return holding +end + +# This method updates the order status, with newest settings on completion +# of processing an order. +# @param order order object. +# @param holdingID holdingID of the particular holding. +# @return STATUS_SUCCESS on success and STATUS_FAILURE on failure. +def CloseOrder(dbhandle, order, holdingID) + order.orderStatus = ORDER_STATUS_CLOSED + if (order.orderType == ORDER_TYPE_SELL) + holdingID = 0 + end + query = "UPDATE ORDERS WITH (ROWLOCK) SET " + + "ORDERSTATUS='" + ORDER_STATUS_CLOSED + "'," + + " COMPLETIONDATE=GetDate(), HOLDING_HOLDINGID='" + holdingID.to_s + "'," + + " PRICE='" + order.price.to_s + "' WHERE ORDERID='" + order.orderID.to_s + "'" + result = ExecuteQuery(dbhandle, query) + if(result) + status = STATUS_SUCCESS + result.finish + else + status = STATUS_FAILURE + end +end + +# Create an entry in the HOLDING table to represent a particular buy order. +# @param order order object filled with order information. +# @return the holdingID of the created holding upon success and else it +# returns INVALID_ID +def CreateHolding(dbhandle, order) + accountID = GetAccountIDFromOrder(dbhandle, order) + if (accountID != INVALID_ID) + query = "INSERT INTO HOLDING (PURCHASEPRICE, QUANTITY, PURCHASEDATE," + + " ACCOUNT_ACCOUNTID, QUOTE_SYMBOL) VALUES ('" + order.price.to_s + "','" + + order.quantity.to_s + "', GetDate(), '" + accountID.to_s + "', '" + order.symbol + "');" + + " SELECT ID=@@IDENTITY" + result = ExecuteQuery(dbhandle, query) + if(result) + row = result.fetch + if (row) + holdingID = row[0] + else + puts "Cannot create holding for order id " + order.orderID + "\n" + holdingID = INVALID_ID + end + result.finish + else + puts "Cannot create holding for order id " + order.orderID + "\n" + holdingID = INVALID_ID + end + else + puts "Account id for order with order id "+ order.orderID + " is not valid\n" + holdingID = INVALID_ID + end + return holdingID +end + +# This method retrieves the acccountID from a given order. +# @param order the order object. +# @return NON-NULL accountID upon success and NULL otherwise. +def GetAccountIDFromOrder(dbhandle, order) + query = "Set NOCOUNT ON; SELECT ACCOUNT_ACCOUNTID FROM ORDERS WITH " + + "(NOLOCK) WHERE ORDERID='" + order.orderID.to_s + "'" + + #Get a tuple including accountID for a particular order + result = ExecuteQuery(dbhandle, query) + if(result) + row = result.fetch + if (row) + accountID = row[0] #Get accountID. + else + puts "Cannot obtain account id for order with order id " + order.orderID.to_s + "\n" + accountID = INVALID_ID + end + result.finish + else + puts "Cannot obtain account id for order with order id " + order.orderID.to_s + "\n" + accountID = INVALID_ID + end + return accountID +end + +# This method updates the account balance of the user who buy or sell some +# sybmol. +# @param accountID is the account to be updated. +# @param amount the amount of money by which the account is updated. +# @return STATUS_SUCCESS upon success and STATUS_FAILURE on failure. +def UpdateAccountBalance(dbhandle, accountID, amount) + status = STATUS_FAILURE + query = "UPDATE ACCOUNT WITH (ROWLOCK) SET BALANCE=(BALANCE - '" + amount.to_s + + "') WHERE ACCOUNTID = '" + accountID.to_s + "'" + result = ExecuteQuery(dbhandle, query) + if(result) + status = STATUS_SUCCESS + result.finish + end + return status +end + +# This method updates the QUOTE table with the new price values. In here, a +# random value is generated which is between 0.1 and 2, and then the quote +# price is changed by multiplying it with the generted random value. +# @param quantity the quantity of a particular symbol the client buy or sell. +# @return STATUS_SUCCESS upon success and STATUS_FAILURE upon failure. +def UpdateStockPriceVolume(dbhandle, quantity, quote) + status = STATUS_FAILURE + if (quote) + randomfloat = rand() + randomint = rand(2) + priceChangeFactor = randomint + randomfloat + quote.price = quote.price * priceChangeFactor + + if(quote.price < 0.05 || quote.price > 1000) + quote.price = 100 + end + + if (quote.price < quote.low) + quote.low = quote.price + end + + if (quote.price > quote.high) + quote.high = quote.price + end + + query = "UPDATE QUOTE WITH (ROWLOCK) SET PRICE='" + quote.price.to_s + + "', LOW='" + quote.low.to_s + "', HIGH='" + quote.high.to_s + "', CHANGE1='" + quote.price.to_s + + "' - OPEN1, VOLUME=VOLUME+'" + quantity.to_s + "' WHERE SYMBOL='" + quote.symbol + "'" + + result = ExecuteQuery(dbhandle, query) + if(result) + status = STATUS_SUCCESS + result.finish + end + end + return status +end Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_client.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_client.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_client.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_client.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,95 @@ +#!/usr/bin/env ruby + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require 'wsf' + +include WSO2::WSF + +req_payload_string = < + + 100000097 + buy + open + 1 + 1 + 15.95 + s:0 + + +XML + +begin + +=begin + randomfloat = rand() + randomint = rand(2) + priceChangeFactor = randomint + randomfloat + puts priceChangeFactor +=end + LOG_FILE_NAME = "ruby_echo_client_addr.log" + END_POINT = "http://localhost:3001/order_processor" + #ACTION = "http://ruby.wsf.wso2/samples/echoString" + ACTION = "SubmitOrderOnePhase" + + client = WSClient.new({"use_wsa" => "TRUE"}, + LOG_FILE_NAME) + + req_message = WSMessage.new(req_payload_string, + nil, + {"to" => END_POINT, + "action" => ACTION}) + + puts "Sending OM : " << "\n" << req_payload_string << "\n" + + res_message = client.send(req_message) + + #ACTION = "http://ruby.wsf.wso2/samples/echoString" + ACTION1 = "isOnline" + + req_message = WSMessage.new(req_payload_string, + nil, + {"to" => END_POINT, + "action" => ACTION1}) + + puts "Sending OM : " << "\n" << req_payload_string << "\n" + + res_message = client.send(req_message) + + if not res_message.nil? then + puts "Received OM : "<< "\n" << res_message.payload_to_s << "\n\n" + puts "Client invocation SUCCESSFUL !!!" + else + puts "Client invocation FAILED !!!" + end +rescue WSFault => wsfault + puts "Client invocation FAILED !!!\n" + puts "WSFault : " + puts wsfault.xml + puts "----------" + puts wsfault.code + puts "----------" + puts wsfault.reason + puts "----------" + puts wsfault.role + puts "----------" + puts wsfault.detail + puts "----------" +rescue => exception + puts "Client invocation FAILED !!!\n" + puts "Exception : " << exception +end Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_controller.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_controller.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_controller.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_controller.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,207 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "order_processor.rb" + +# This method corresponds to the primary operation of the service.It processes +# an incomming order object. +# @param input, the order object, filled with data correspond to an order +# @return accept upon success. +def SubmitOrderOnePhase(input) + inputStr = input.payload_to_s() + order = nil + doc = REXML::Document.new(inputStr) + unless doc.nil? + root_element = doc.root + end + if(root_element) + orderType = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderType", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderType != nil) + if((orderType[0].get_text == ORDER_TYPE_BUY) || + (orderType[0].get_text == ORDER_TYPE_SELL)) + order = Order.new() + + #filling values to order object + order.orderType = orderType[0].get_text.to_s; + orderID = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderID", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderID) + order.orderID = orderID[0].get_text.to_s.to_i; + end + + orderStatus = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderStatus", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderStatus) + order.orderStatus = orderStatus[0].get_text.to_s; + end + + quantity = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:quantity", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(quantity) + order.quantity = quantity[0].get_text.to_s.to_f; + end + + price = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:price", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(price) + order.price = price[0].get_text.to_s.to_f; + end + + orderFee = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderFee", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderFee) + order.orderFee = orderFee[0].get_text.to_s.to_f; + end + + symbol = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:symbol", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(symbol) + order.symbol = symbol[0].get_text.to_s; + end + + Thread.new do + # This will obtains some additional time and let the business service + # to store information regarding an order. Then the OrderProcessor can + # continue processing the order request that was just stored in the + # database. + sleep(2) + ProcessOrder(order) + end + elsif + puts "Unknown order type given \n" + end + elsif + puts "Order type is not valid \n" + end + elsif + puts "Order object given for processing is not valid \n" + end +end + +def SubmitOrderTransactedQueue(input) + inputStr = input.payload_to_s() + order = nil + doc = REXML::Document.new(inputStr) + unless doc.nil? + root_element = doc.root + end + if(root_element) + orderType = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderType", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderType != nil) + if((orderType[0].get_text == ORDER_TYPE_BUY) || + (orderType[0].get_text == ORDER_TYPE_SELL)) + order = Order.new() + + #filling values to order object + order.orderType = orderType[0].get_text.to_s; + orderID = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderID", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderID) + order.orderID = orderID[0].get_text.to_s.to_i; + end + + orderStatus = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderStatus", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderStatus) + order.orderStatus = orderStatus[0].get_text.to_s; + end + + quantity = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:quantity", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(quantity) + order.quantity = quantity[0].get_text.to_s.to_f; + end + + price = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:price", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(price) + order.price = price[0].get_text.to_s.to_f; + end + + orderFee = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderFee", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderFee) + order.orderFee = orderFee[0].get_text.to_s.to_f; + end + + symbol = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:symbol", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(symbol) + order.symbol = symbol[0].get_text.to_s; + end + + Thread.new do + # This will obtains some additional time and let the business service + # to store information regarding an order. Then the OrderProcessor can + # continue processing the order request that was just stored in the + # database. + sleep(2) + ProcessOrder(order) + end + elsif + puts "Unknown order type given \n" + end + elsif + puts "Order type is not valid \n" + end + elsif + puts "Order object given for processing is not valid \n" + end +end +# This function corresponds to the isOnline operation. This is used by the +# Configuration service to make sure that the OrderProcessor service is +# online. +# @return just a return is expected to make sure the service is online. +def isOnline(input) +end + +class OrderProcessorController < ApplicationController + + require "wsf" + skip_before_filter :verify_authenticity_token + + def index + #operation to ruby function map + operations = {"isOnline" => "isOnline", "SubmitOrderOnePhase" => "SubmitOrderOnePhase", "SubmitOrderTransactedQueue" => "SubmitOrderTransactedQueue"} + + #action to operation map + actions = {"isOnline" => "isOnline", "SubmitOrderOnePhase" => "SubmitOrderOnePhase", "SubmitOrder" => "SubmitOrderTransactedQueue"} + + + wss = WSO2::WSF::WSService.new({"operations" => operations, + "actions" => actions}) + + res = wss.reply(request, response); + render :text => res, :status => 202 + end + +end Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_msec_controller.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_msec_controller.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_msec_controller.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/order_processor_msec_controller.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,230 @@ + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require "order_processor.rb" + +# This method corresponds to the primary operation of the service.It processes +# an incomming order object. +# @param input, the order object, filled with data correspond to an order +# @return accept upon success. +def SubmitOrderOnePhase(input) + inputStr = input.payload_to_s() + order = nil + doc = REXML::Document.new(inputStr) + unless doc.nil? + root_element = doc.root + end + if(root_element) + orderType = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderType", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderType) + if((orderType[0].get_text == ORDER_TYPE_BUY) || + (orderType[0].get_text == ORDER_TYPE_SELL)) + order = Order.new() + + #filling values to order object + order.orderType = orderType[0].get_text.to_s; + orderID = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderID", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderID) + order.orderID = orderID[0].get_text.to_s.to_i; + end + + orderStatus = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderStatus", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderStatus) + order.orderStatus = orderStatus[0].get_text.to_s; + end + + quantity = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:quantity", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(quantity) + order.quantity = quantity[0].get_text.to_s.to_f; + end + + price = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:price", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(price) + order.price = price[0].get_text.to_s.to_f; + end + + orderFee = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:orderFee", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderFee) + order.orderFee = orderFee[0].get_text.to_s.to_f; + end + + symbol = REXML::XPath.match(root_element, "/ns1:SubmitOrder/ns1:order/ns2:symbol", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(symbol) + order.symbol = symbol[0].get_text.to_s; + end + + Thread.new do + # This will obtains some additional time and let the business service + # to store information regarding an order. Then the OrderProcessor can + # continue processing the order request that was just stored in the + # database. + sleep(2) + ProcessOrder(order) + end + elsif + puts "Unknown order type given \n" + end + elsif + puts "Order type is not valid \n" + end + elsif + puts "Order object given for processing is not valid \n" + end +end + +def SubmitOrderTransactedQueue(input) + inputStr = input.payload_to_s() + order = nil + doc = REXML::Document.new(inputStr) + unless doc.nil? + root_element = doc.root + end + if(root_element) + orderType = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderType", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderType != nil) + if((orderType[0].get_text == ORDER_TYPE_BUY) || + (orderType[0].get_text == ORDER_TYPE_SELL)) + order = Order.new() + + #filling values to order object + order.orderType = orderType[0].get_text.to_s; + orderID = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderID", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderID) + order.orderID = orderID[0].get_text.to_s.to_i; + end + + orderStatus = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderStatus", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderStatus) + order.orderStatus = orderStatus[0].get_text.to_s; + end + + quantity = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:quantity", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(quantity) + order.quantity = quantity[0].get_text.to_s.to_f; + end + + price = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:price", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(price) + order.price = price[0].get_text.to_s.to_f; + end + + orderFee = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:orderFee", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(orderFee) + order.orderFee = orderFee[0].get_text.to_s.to_f; + end + + symbol = REXML::XPath.match(root_element, "/ns1:SubmitOrderTransactedQueue/ns1:order/ns2:symbol", + {"ns1" => "http://Trade.TraderOrderHost", + "ns2" => "http://trade.samples.websphere.ibm.com"}) + if(symbol) + order.symbol = symbol[0].get_text.to_s; + end + + Thread.new do + # This will obtains some additional time and let the business service + # to store information regarding an order. Then the OrderProcessor can + # continue processing the order request that was just stored in the + # database. + sleep(2) + ProcessOrder(order) + end + elsif + puts "Unknown order type given \n" + end + elsif + puts "Order type is not valid \n" + end + elsif + puts "Order object given for processing is not valid \n" + end +end + + +# This function corresponds to the isOnline operation. This is used by the +# Configuration service to make sure that the OrderProcessor service is +# online. +# @return just a return is expected to make sure the service is online. +def isOnline(input) +end + +def load_policy_from_file(filename) + return nil unless filename.kind_of? String + input = File.new(filename) + unless input.nil? + doc = REXML::Document.new(input) + unless doc.nil? + root_element = doc.root + return root_element + end + end + return nil +end + +class OrderProcessorMsecController < ApplicationController + + require "wsf" + skip_before_filter :verify_authenticity_token + + def index + operations = {"isOnline" => "isOnline", "SubmitOrderOnePhase" => "SubmitOrderOnePhase", "SubmitOrderTransactedQueue" => "SubmitOrderTransactedQueue"} + actions = {"isOnline" => "isOnline", "SubmitOrderOnePhase" => "SubmitOrderOnePhase", "SubmitOrder" => "SubmitOrderTransactedQueue"} + + #security specific configurations + #cert = WSO2::Util::WSUtil::ws_get_cert_from_file("./app/controllers/keys/bob_cert.cert"); + pvt_key = WSO2::Util::WSUtil::ws_get_key_from_file("./app/controllers/keys/bob_key.pem"); + #pub_key = WSO2::Util::WSUtil::ws_get_cert_from_file("./app/controllers/keys/alice_cert.cert"); + policy_content = load_policy_from_file("./app/controllers/policies/order_processor_policy.xml") + policy = WSO2::WSF::WSPolicy.new(policy_content) + + sec_token = WSO2::WSF::WSSecurityToken.new({"private_key" => pvt_key}) + #"certificate" => cert, + #"receiver_certificate" =>pub_key}) + + wss = WSO2::WSF::WSService.new({"operations" => operations, + "actions" => actions, + "policy" => policy, + "security_token" => sec_token}) + + res = wss.reply(request, response); + render :text => res, :status => 202 + end +end Added: incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/policies/order_processor_policy.xml URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/policies/order_processor_policy.xml?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/policies/order_processor_policy.xml (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/order_processor/controllers/policies/order_processor_policy.xml Fri Feb 13 12:04:55 2009 @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Added: incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/application.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/application.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/application.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/application.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,31 @@ + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Filters added to this controller apply to all controllers in the application. +# Likewise, all the methods added will be available for all controllers. + +class ApplicationController < ActionController::Base + helper :all # include all helpers, all the time + + # See ActionController::RequestForgeryProtection for details + # Uncomment the :secret if you're not using the cookie session store + protect_from_forgery # :secret => '82596297efe03131186d1f272ff82ba6' + + # See ActionController::Base for details + # Uncomment this to filter the contents of submitted sensitive data parameters + # from your application log (in this case, all fields with names like "password"). + # filter_parameter_logging :password +end Added: incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_controller.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_controller.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_controller.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_controller.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,249 @@ + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "trade_logic.rb" + +class TradeController < ApplicationController + #protect_from_forgery :only => [] + skip_before_filter :verify_authenticity_token + layout "default" + + def account + if(!IsLoggedIn()) + redirect_to(request.protocol + request.host_with_port + "/trade/login") + return + else + updateProfile = request.parameters["UPDATEUSERPROFILE"] + if(updateProfile) + userId = GetUserFromCookie() + password = request.parameters["PASSWORD"] + fullName = request.parameters["FULLNAME"] + address = request.parameters["ADDRESS"] + email = request.parameters["EMAIL"] + creditCard = request.parameters["CREDITCARD"] + + UpdateAccountProfile(userId, fullName, email, address, creditCard, password) + end + end + + @ordersReturn = GetOrders(GetUserFromCookie()) + @accountSummary = nil + if(@ordersReturn) + @accountSummary = GetUserAccountSummary(@ordersReturn) + end + @userAccountDataReturn = GetAccountData(GetUserFromCookie()) + @userAccountProfileDataReturn = GetAccountProfileData(GetUserFromCookie()) + @closedOrders = GetClosedOrders(GetUserFromCookie()) + @userId = GetUserFromCookie() + end + + def config + end + + def confirmation + if(!IsLoggedIn()) + redirect_to(request.protocol + request.host_with_port + "/trade/login") + return + end + @message = "" + if (request.parameters['SELL']) + @isSell = request.parameters['SELL'] + @holdingID = request.parameters['HOLDINGID'] + @quantity = request.parameters['QUANTITY'] + @symbol = request.parameters['SYMBOL'] + elsif (request.parameters['BUY']) + @quantity = request.parameters['QUANTITY'] + @symbol = request.parameters['SYMBOL'] + @price = request.parameters['PRICE'] + @isBuy = request.parameters['BUY'] + else + @message = "This is not buy or sell." + end + end + + def glossary + end + + def index + end + + def login + @message = "" + if(IsLoggedIn()) + user = GetUserFromCookie() + LogoutUser(user) + @message = "You are just log out as " + user + end + if(request.post?) + if(request.parameters["LOGINREQUEST"] != nil && request.parameters["USERNAME"] != nil && + request.parameters["PASSWORD"] && request.parameters["USERNAME"] != "" && request.parameters["PASSWORD"] != "") + username = request.parameters['USERNAME'] + password = request.parameters['PASSWORD'] + response = Login(username, password) + @message = response + if(Login(username, password)) + # login request received, log in the user with given username and password + WriteUsername(username) + redirect_to(request.protocol + request.host_with_port + "/trade/account") + @message = username + " logged in." + end + else + @message = "Login failed! Username or Password missing or invalid!" + end + end + end + + + def config + setendpoint = request.parameters["SETENDPOINT"] + endpoint = request.parameters["ENDPOINT"] + if(endpoint != nil && endpoint != "") + if(WriteEndpoint(endpoint)) + @message = "" + else + redirect_to(request.protocol + request.host_with_port + "/trade/login") + end + end + end + + def quotes + if(!IsLoggedIn()) + redirect_to(request.protocol + request.host_with_port + "/trade/login") + return + elsif(request.parameters['GETQUOTE'] != nil) + # This is a request to get quote information for a particular symbol + symbol = request.parameters['SYMBOLS'] + if (symbol) + @quotesReturn = GetQuote(symbol) + end + elsif (request.parameters['BUY'] != nil || request.parameters['SELL'] != nil) + # This is a buy or sell request + quantity = request.parameters['QUANTITY'] + userID = GetUserFromCookie(); + isBuy = false + isSell = false + + if (request.parameters['BUY']) + mode = 0; + @isBuy = true + symbol = request.parameters['SYMBOL'] + @buyReturn = Buy(userID, symbol, quantity, mode) + if (@buyReturn && @buyReturn["orderID"]) + @isReply = true + else + @response = nil + end + elsif(request.parameters['SELL']) + @isSell = true + holdingID = request.parameters['HOLDINGID'] + @sellEnhancedReturn = SellEnhanced(userID, holdingID, quantity) + @message = obj_to_s(@shellEnhancedReturn) + if (@sellEnhancedReturn && @sellEnhancedReturn["orderID"]) + @isReply = true + else + @response = nil + end + end + else + @quotesInitialPage = TRUE + end + + @closedOrders = GetClosedOrders(GetUserFromCookie()) + + end + + def portfolio + if(!IsLoggedIn()) + redirect_to(request.protocol + request.host_with_port + "/trade/login") + return + end + @holdingsReturn = GetHoldings(GetUserFromCookie()) + @quoteInfo = {} + index = 0 + while ((bean=@holdingsReturn["HoldingDataBean"][index]) != nil) + if (!@quoteInfo[bean["quoteID"]]) + quotesReturn = GetQuote(bean["quoteID"]) + @quoteInfo[bean["quoteID"]] = quotesReturn["price"] + end + index = index + 1 + end + @closedOrders = nil + @closedOrders = GetClosedOrders(GetUserFromCookie()) + end + + def register + if (request.parameters['REGISTERUSER']) + # New user registration + userID = request.parameters['REQUESTEDID'] + openBalance = request.parameters['OPENBALANCE'] + fullname = request.parameters['FULLNAME'] + email = request.parameters['EMAIL'] + address = request.parameters['ADDRESS'] + password = request.parameters['PASSWORD'] + creditcard = request.parameters['CREDITCARD'] + confpassword = request.parameters['CONFIRMATIONPASSWORD'] + + @invalidInformation = false + @successfulRegistration = false + @invalidInformation = false + + + + if (userID == nil || password != confpassword) + @invalidInformation = true + else + response = RegisterUser(userID, password, fullname, + address, email, creditcard, openBalance) + #@message = obj_to_s(response) + if (response) + @successfulRegistration = true + else + @invalidInformation = true + end + end + end + end + + def home + if(!IsLoggedIn()) + redirect_to(request.protocol + request.host_with_port + "/trade/login") + return + end + + # Market data summary. + @getMarketSummaryReturn= GetMarketSummary() + + @tsia = @getMarketSummaryReturn["TSIA"] + @gain = @getMarketSummaryReturn["TSIA"].to_f - @getMarketSummaryReturn["openTSIA"].to_f + @volume = @getMarketSummaryReturn["volume"] + @topGainers = @getMarketSummaryReturn["topGainers"] + @topLosers = @getMarketSummaryReturn["topLosers"] + + # Account information for the user. + @accountDataReturn = GetAccountData(GetUserFromCookie()); + #@accountDataReturn = @accountData->getAccountDataReturn; + + # Holding information for a particular user + @holdings = GetHoldings(GetUserFromCookie()) + @holdingInfo = GetHoldingInformation(@holdings); + @noOfHoldings = @totalHoldings = 0 + @noOfHoldings = @holdingInfo["noOfHoldings"] + @totalHoldings = @holdingInfo["totalHoldings"] + + @userId = GetUserFromCookie() + end +end Added: incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_logic.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_logic.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_logic.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_logic.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,488 @@ + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require "trade_utils.rb" + +require 'wsf' # Use WSO2 WSF/Ruby module + +#include WSO2::WSF + +# Constant definition +WSDL_FILE_NAME = "public/wsdl/noimports.wsdl" +LOG_FILE_NAME = "wsf_ruby_client.log" +CONFIG_WSDL_NAME = "public/wsdl/config_svc.wsdl" +CLIENT_NAME = "RUBY_CLIENT" + +##################### +# Web Services Client +##################### + + +# Get proxy client +def GetProxy() + endpoint = GetBSEndpoint(); + if(endpoint != nil) + client = WSO2::WSF::WSClient.new({"wsdl" => WSDL_FILE_NAME, + "to" => endpoint}, LOG_FILE_NAME) + + return client.get_proxy + else + return nil + end +end + + +# Get client +def GetClient() + endpoint = GetBSEndpoint(); + if(endpoint != nil) + client = WSO2::WSF::WSClient.new( + {"to" => endpoint, "use_soap" => 1.1}, LOG_FILE_NAME) + + return client + else + return nil + end +end + +# Sends login request to verify whether current user is authorized +# @param userid user id of current user +# @param password password given by current user +# @return profile id of the user if login is success. NULL otherwise +def Login(userid, password) + proxy = GetProxy() + if(proxy != nil) + response = proxy.login({"login"=> {"userID"=> userid, + "password" => password}}) + if(response["loginResponse"] != nil && response["loginResponse"]["loginReturn"] != nil) + return response["loginResponse"]["loginReturn"]["profileID"] + else + return nil + end + end +end + +# When user logout, user id will be deleted from the cookie +# @param username user id of current user + +def LogoutUser(username) + + client = GetClient() + input = "#{username}" + begin + response = client.request(input) + rescue WSO2::WSF::WSFault => wsfault + end + DeleteCookie() +end + + +# get the orders +def GetOrders(userid) + proxy = GetProxy() + response =proxy.getOrders({"getOrders"=> {"userID" => userid}}) + if(response != nil && response["getOrdersResponse"] != nil && + response["getOrdersResponse"]["getOrdersReturn"] != nil) + ret = response["getOrdersResponse"]["getOrdersReturn"] + return ret + end +end + +# Given the order details of a user, this method calculates summery of +# activities of the user. This includes total money spent on buying stocks +# total money earned from selling them etc. +# @param ordersReturn collection of orders of a user +# @return summery of user's activities + + +def GetUserAccountSummary(ordersReturn) + index = 0 + sells = 0 + buys = 0 + tax = 0 + + if(ordersReturn["OrderDataBean"].class.to_s == "Array") + while((order = ordersReturn["OrderDataBean"][index]) != nil) + if(order.class.to_s == "Hash") + if (order["orderType"] == "buy") + buys = buys + ((order["price"].to_f) * + (order["quantity"].to_i)) + + (order["orderFee"].to_f) + elsif (order["orderType"] == "sell") + sells = sells + ((order["price"].to_f) * + (order["quantity"].to_i)) - + (order["orderFee"].to_f) + end + tax = tax + order["orderFee"].to_f; + end + index = index + 1; + end + else + order = ordersReturn["OrderDataBean"] + if(order.class.to_s == "Hash") + if (order["orderType"] == "buy") + buys = buys + ((order["price"].to_f) * + (order["quantity"].to_i)) + + (order["orderFee"].to_f) + elsif (order["orderType"] == "sell") + sells = sells + ((order["price"].to_f) * + (order["quantity"].to_i)) - + (order["orderFee"].to_f) + end + tax = tax + order["orderFee"].to_f; + end + end + return {"totalBuys" => buys, + "totalSells" => sells, + "totalTax" => tax, + "totalImpact" => buys + tax - sells} +end + +# Updates account profile information +# @param userID id of the user +# @param fullname full name of the user +# @param email email address of the user +# @param address address of the user +# @param creditcard credit card number of the user +# @param password password of the user +# @return account details of the modified user on success. NULL otherwise. + +def UpdateAccountProfile(userID, fullName, email, + address, creditCard, password) + proxy = GetProxy(); + input = {"updateAccountProfile" => + {"profileData" => + { "userID" => userID, + "password" => password, + "fullName" => fullName, + "address" => address, + "email" => email, + "creditCard" => creditCard}}} + response = proxy.updateAccountProfile(input); + return response; +end + + +# Gets account details of current user +# @param userid user id of current user +# @return account details if success. NULL otherwise + +def GetAccountData(userid) + proxy = GetProxy() + input = {"getAccountData" => + {"userID" => userid}} + response = proxy.getAccountData(input) + if(response["getAccountDataResponse"] != nil && + response["getAccountDataResponse"]["getAccountDataReturn"] != nil) + return response["getAccountDataResponse"]["getAccountDataReturn"] + end +end + +# Gets account profile information of current user +# @param userid user id of current user +# @return account profile data of current user if success. NULL otherwise + +def GetAccountProfileData(userid) + proxy = GetProxy() + input = {"getAccountProfileData" => + {"userID" => userid}} + response = proxy.getAccountProfileData(input) + if(response["getAccountProfileDataResponse"] != nil && + response["getAccountProfileDataResponse"]["getAccountProfileDataReturn"] != nil) + return response["getAccountProfileDataResponse"]["getAccountProfileDataReturn"] + end +end + +# Gets closed orders of current user +# @return collection of orders whose status is closed + +def GetClosedOrders(userid) + proxy = GetProxy() + input = {"getClosedOrders" => + {"userID" => userid}} + response = proxy.getClosedOrders(input) + #return response + if(response != nil && + response["getClosedOrdersResponse"] != nil && + response["getClosedOrdersResponse"]["getClosedOrdersReturn"] != nil) + return response["getClosedOrdersResponse"]["getClosedOrdersReturn"] + end + return nil +end + + +# Gets quote of given symbol +# @param symbol id of the stock +# @return details of the symbol when success. NULL otherwise + +def GetQuote(symbol) + + proxy = GetProxy(); + input = {"getQuote" => + {"symbol" => symbol}} + response = proxy.getQuote(input) + if(response != nil && + response["getQuoteResponse"] != nil && + response["getQuoteResponse"]["getQuoteReturn"] != nil) + getQuoteReturn = response["getQuoteResponse"]["getQuoteReturn"] + return getQuoteReturn + end + return nil +end + + +# Buys number of stocks of given symbol +# @param userID user id of current user +# @param symbol symbol of needed stock +# @quantity number of stocks needed +# @mode mode of buying +# @return details of buy order if success. NULL otherwise + +def Buy(userID, symbol, quantity, mode) + proxy = GetProxy() + input = {"buy" => + {"symbol" => symbol, + "userID" => userID, + "quantity" => quantity.to_f, + "orderProcessingMode" => mode.to_i}} + response = proxy.buy(input) + if(response != nil && + response["buyResponse"] != nil && + response["buyResponse"]["buyReturn"] != nil) + return response["buyResponse"]["buyReturn"] + end + return nil +end + +# Sells given holding or part of it of given user +# @param userID user id of current user +# @param holdingID holding id of the holding +# @param quantity number of stocks to be sold +# @return details of sell order if success. NULL otherwise + +def SellEnhanced(userID, holdingID, quantity) + proxy = GetProxy() + input = {"sellEnhanced" => + {"userID" => userID, + "holdingID" => holdingID.to_i, + "quantity" => quantity.to_f}} + response = proxy.sellEnhanced(input) + if(response != nil && + response["sellEnhancedResponse"] != nil && + response["sellEnhancedResponse"]["sellEnhancedReturn"] != nil) + return response["sellEnhancedResponse"]["sellEnhancedReturn"] + end + return nil +end + + +# Gets holding details of given user +# @param userid user id of current user +# returns collection of holding if success. NULL otherwise + +def GetHoldings(userID) + proxy = GetProxy(); + input = {"getHoldings" => + {"userID" => userID}} + response = proxy.getHoldings(input) + if(response != nil && + response["getHoldingsResponse"] != nil && + response["getHoldingsResponse"]["getHoldingsReturn"] != nil) + return response["getHoldingsResponse"]["getHoldingsReturn"] + end + return nil +end + + +# This method registes a new user in the system +# @param userID id of the user +# @param password password of the user +# @param fullname full name of the user +# @param address address of the user +# @param email email address of the user +# @param creditcard credit card number of the user +# @param openBalance initial balance of the user +# @return account details of the registerd user on success. NULL otherwise. + +def RegisterUser(userID, password, fullname, + address, email, creditcard, openBalance) + + proxy = GetProxy() + input = {"register" => + {"userID" => userID, + "password" => password, + "fullname" => fullname, + "address" => address, + "email" => email, + "creditcard" => creditcard, + "openBalance" => openBalance.to_f}} + response = proxy.register(input) + if(response != nil && + response["registerResponse"] != nil && + response["registerResponse"]["registerReturn"] != nil) + return response["registerResponse"]["registerReturn"] + end + return response +end + +require 'rexml/document' +include REXML + +# Gets market summary +# @return market summery + +def GetMarketSummary +# proxy = GetProxy() +# input = {"getMarketSummary" => nil} +# response = proxy.getMarketSummary(input) +# if(response != nil && +# response["getMarketSummaryResponse"] != nil && +# response["getMarketSummaryResponse"]["getMarketSummaryReturn"] != nil) +# return response["getMarketSummaryResponse"]["getMarketSummaryReturn"] +# end +# return response + client = GetClient() + input = "" + + response = client.request(input) + + doc = Document.new(response.payload_to_s) + + ret_val = {} + ret_val["TSIA"]= XPath.first(doc, "//pq:TSIA", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(doc, "//pq:TSIA", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil + ret_val["openTSIA"]= XPath.first(doc, "//pq:openTSIA", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(doc, "//pq:openTSIA", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil + ret_val["volume"]= XPath.first(doc, "//pq:volume", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(doc, "//pq:volume", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil + ret_val["summaryDate"]= XPath.first(doc, "//pq:summaryDate", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(doc, "//pq:summaryDate", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil + + top_gainers_arr = Array.new + XPath.each(doc, "//pq:topGainers/pq:QuoteDataBean",{"pq" => "http://trade.samples.websphere.ibm.com"}) do |quote| + top_gainers_arr << + { + "symbol" => XPath.first(quote, "./pq:symbol", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:symbol", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "companyName" => XPath.first(quote, "./pq:companyName", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:companyName", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "price" => XPath.first(quote, "./pq:price", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:price", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "open" => XPath.first(quote, "./pq:open", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:open", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "low" => XPath.first(quote, "./pq:low", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:low", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "high" => XPath.first(quote, "./pq:high", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:high", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "change" => XPath.first(quote, "./pq:change", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:change", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "volume" => XPath.first(quote, "./pq:volume", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:volume", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil + } + end + + top_losers_arr = Array.new + XPath.each(doc, "//pq:topLosers/pq:QuoteDataBean",{"pq" => "http://trade.samples.websphere.ibm.com"}) do |quote| + top_losers_arr << + { "symbol" => XPath.first(quote, "./pq:symbol", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:symbol", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "companyName" => XPath.first(quote, "./pq:companyName", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:companyName", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "price" => XPath.first(quote, "./pq:price", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:price", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "open" => XPath.first(quote, "./pq:open", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:open", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "low" => XPath.first(quote, "./pq:low", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:low", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "high" => XPath.first(quote, "./pq:high", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:high", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "change" => XPath.first(quote, "./pq:change", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:change", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil, + "volume" => XPath.first(quote, "./pq:volume", {"pq" => "http://trade.samples.websphere.ibm.com"})? + XPath.first(quote, "./pq:volume", {"pq" => "http://trade.samples.websphere.ibm.com"}).text.to_s : nil + } + end + + ret_val["topLosers"] = top_losers_arr + ret_val["topGainers"] = top_gainers_arr + + + return ret_val +end + + + +# Given the holdings of a user, this methods calculate total market value of +# holding and number of holdings +# @param holdings collection of holdings of a user +# @return summery of holding details + +def GetHoldingInformation(holdingsReturn) + quoteInfo = {} + index = 0 + marketValue = 0 + totalHoldings = 0 + while ((bean=holdingsReturn["HoldingDataBean"][index]) != nil) + if (!quoteInfo[bean["quoteID"]]) + quotesReturn = GetQuote(bean["quoteID"]) + quoteInfo[bean["quoteID"]] = quotesReturn["price"] + end + + quoteID = bean["quoteID"] + totalHoldings = totalHoldings + bean["purchasePrice"].to_f * (bean["quantity"].to_i) + marketValue = marketValue + (quoteInfo[quoteID].to_i) * (bean["quantity"].to_i) + + index = index + 1 + end + + holdingInfo = {"totalHoldings" => marketValue, "noOfHoldings" => index } + return holdingInfo +end + +# Get the endpoint of business service +def GetBSEndpoint() + #get the endpoint first + endpoint = GetEndpoint() + + if(endpoint == nil) + return nil + end + # create client in WSDL mode + client = WSO2::WSF::WSClient.new({"wsdl" =>CONFIG_WSDL_NAME, + "to" => endpoint}, LOG_FILE_NAME) + + # get proxy object reference form client + proxy = client.get_proxy(); + input = {"ClientConfigRequest" => + {"Client" => CLIENT_NAME } } + + response = proxy.ClientConfigRequest(input); + if(response && response["ClientConfigResponse"]) + bsendpoint = response["ClientConfigResponse"]["BS"] + end + cookies[:bsendpoint] = { :value => bsendpoint, + :expires => Time.now + 24.hour} + return bsendpoint +end + + +# Get the endpoint of the business service to be consumed +def GetEndpoint() + return cookies[:endpoint] +end + + Added: incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_utils.rb URL: http://svn.apache.org/viewvc/incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_utils.rb?rev=744093&view=auto ============================================================================== --- incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_utils.rb (added) +++ incubator/stonehenge/trunk/stocktrader/ruby/trader_client/controllers/trade_utils.rb Fri Feb 13 12:04:55 2009 @@ -0,0 +1,117 @@ + +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# Store business service's endpoint in cookie +# @param endPoint end point address of the business service +def WriteEndpoint(endpoint) + if(cookies[:endpoint] == endpoint) + return false + else + cookies[:endpoint] = { :value => endpoint, :expires => Time.now + 24.hour} + if(cookies[:bsendpoint]) + cookies.delete :bsendpoint + end + return true + end +end + + +# Checks whether user is logged in. If the user is logged in, user id +# cookie would have been already set. Checking whether cookie is set +# equals to checking whether user is logged in. +def IsLoggedIn() + return cookies[:username] != nil && + !cookies[:username].empty? +end + +# Writes user id to cookie +# @param username user id of the current user +def WriteUsername(username) + cookies[:username] = { :value => username, :expires => Time.now + 24.hour} +end + +# Deletes user id from cookie +# @param username user id of current user +def DeleteCookie() + cookies.delete :username +end + +# Retrun the user +def GetUserFromCookie() + return cookies[:username] +end + +def obj_to_s(obj, terminator= "\n", index = 0) + str = "" + index.times do |num| + str = str + " " + end + if(obj.class.to_s == "Hash") + str = str + "{" + obj.each do |key, value| + value_to_str = obj_to_s(value, terminator, index + 2) + str = str + key + " => " + value_to_str + " " + end + str = str + "}" + elsif(obj.class.to_s == "Array") + str = str + "[" + obj.each do |value| + value_to_str = obj_to_s(value, terminator, index + 2) + str = str + value_to_str + " " + end + str = str + "]" + elsif(obj.class.to_s == "String") + str = str + obj + " " + elsif(obj.class.to_s == "FixNum") + str = str + obj.to_s + " " + elsif(obj.class.to_s == "Float") + str = str + obj.to_s + " " + else + str = str + obj.to_s + " " + end + str = str + terminator + return str +end + + +def convert_date(str) + if(str) + date_arr = str.to_s.tr("T:.", "-").split("-") + year = date_arr[0] + mon = date_arr[1] + date = date_arr[2] + hour = date_arr[3] + min = date_arr[4] + sec = date_arr[5] + + if(hour.to_i > 12) + hour = hour.to_i - 12 + hour = hour.to_s + ampm = "PM" + else + ampm = "AM" + end + + return mon.to_s + "/" + + date.to_s + "/" + + year.to_s + " " + + hour.to_s + ":" + + min.to_s + ":" + + sec.to_s + " " + ampm + end + return "" +end