using System; namespace MyRM { /// /// class MyRM implements: see TP.RM /// public class MyRM : System.MarshalByRefObject, TP.RM { MyLM lockManager; TP.TM transactionManager; System.Collections.Hashtable Items; System.Collections.Hashtable Reservations; /// ///Constructor /// public MyRM() { this.lockManager = new MyLM(); /* don't need this for now */ /* this.transactionManager = (TP.TM) System.Activator.GetObject( typeof( MyTM.MyTM ), "http://localhost:8081/TM.soap"); TP.Transaction tid = transactionManager.Start(); transactionManager.Abort( tid ); */ Items = new System.Collections.Hashtable(); Reservations = new System.Collections.Hashtable(); } class Reservation { public TP.Customer Holder; public System.Collections.ArrayList Items; public Reservation( TP.Customer c, TP.Item i, int price ) { this.Holder = c; Items = new System.Collections.ArrayList(); Items.Add( new ItemReservation( i, price )); } } class ItemReservation { public TP.Item ThisItem; public int Price; public ItemReservation( TP.Item i, int price) { this.ThisItem=i; Price = price; } } class ItemInstance { string Name { get { return i.Name; } } TP.Item i; public int Count; public int CurrentPrice; public ItemInstance( TP.Item i, int count, int price ) { this.i = i; this.Count = count; this.CurrentPrice = price; } } static void Main( string [] args ) { if (args.Length<1) { Console.WriteLine("Usage: MyRM [port_number]"); return; } string port_num; if (args.Length<2){ port_num="8081"; } else port_num=args[1]; System.Console.WriteLine( string.Format( "Starting resource manager for {0} on port {1}", args[0], port_num )); System.Threading.Thread.Sleep( 4000 ); // Wait for Transaction manager to come up System.Runtime.Remoting.Channels.Http.HttpChannel channel = new System.Runtime.Remoting.Channels.Http.HttpChannel( Convert.ToInt32(port_num) ); System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel( channel ); System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownServiceType ( Type.GetType("MyRM.MyRM") // assembly name , "RM.soap" //URI , System.Runtime.Remoting.WellKnownObjectMode.Singleton // instancing mode ); while( true ) System.Threading.Thread.Sleep( 100000 ); } public void Enlist( TP.Transaction context ) { // transactionManager.Enlist( context ); } public void Commit(TP.Transaction context ) { //transactionManager.Commit( context ); } public void Abort(TP.Transaction context ) { //transactionManager.Abort( context ); } ///NEED TO ADD CODE ///This method adds a resource to the available ones public bool Add( TP.Transaction context, TP.Item i, int count, int price) { ItemInstance ii = (ItemInstance)Items[i.Name]; if( ii != null ) { Console.WriteLine("RM: Add: item is null {0} ",i); ii.Count += count; ii.CurrentPrice = price; } else{ Console.WriteLine("RM: Add: item is NOT null {0} ",i); Items.Add( i.Name, new ItemInstance( i, count, price ) ); //NEED TO DO ADD LOCKING STUFF HERE } return true; } ///NEED TO ADD CODE public bool Delete( TP.Transaction context, TP.Item i ) { //NEED TO DO ADD LOCKING STUFF HERE Items.Remove( i.Name ); return true; } /// ///NEED TO ADD CODE For STEP 2 /// The call to shutdown causes the RM to gracefully exit. /// It waits for all the existing txns to end and any new transaction /// enlistments are refused. If any of the existing txns block /// forever, a retry/timeout mechanism is used to exit the RM /// no recovery is done upon startup /// public void Shutdown() { } /// // Call exit after a specified number of disk writes. /// Support for this method requires a wrapper around the system's /// write to disk command that decrements the counter set by this method. /// This counter should default to 0, which implies that the wrapper /// will do nothing. If the count is non-zero, the wrapper should decrement /// the counter, see if it becomes zero, and if so, call exit(), otherwise /// continue the write. /// public void SelfDestruct(int diskWritesToWait) { } /// ///ADD CODE HERE /// returns the amount available for the specified item type /// public int Query( TP.Transaction context, TP.Item i ) { Console.WriteLine("RM: Query"); ItemInstance ii = (ItemInstance) Items[i.Name]; if( ii == null ) return 0; else return ii.Count; } /// ///ADD CODE HERE /// returns the price for the specified item type /// public int QueryPrice( TP.Transaction xId, TP.Item i ) { return ((ItemInstance)Items[i.Name]).CurrentPrice; } /// ///ADD CODE HERE--need LOCKING: STEP 2 ///Query the bill for a customer. /// /// /// customer to be queried /// Bill for customer public string QueryCustomerInfo( TP.Transaction context, TP.Customer c ) { string order; order = ""; Reservation r = (Reservation) Reservations[c.Id]; foreach( ItemReservation rr in r.Items ) { if( order.Length > 0 ) order += ","; order += rr.ThisItem.Name; } return order; } public int QueryCustomer( TP.Transaction context, TP.Customer c ) { int bill=0; Reservation r = (Reservation) Reservations[c.Id]; foreach( ItemReservation rr in r.Items ) { bill+= rr.Price; } return bill ; } /// ///ADD CODE HERE /// /// /// Customer /// item to reserve /// success public bool Reserve( TP.Transaction context, TP.Customer c, TP.Item i ) { ItemInstance ii = (ItemInstance)Items[i.Name]; if( ii == null) throw new System.Exception( string.Format( "Item {0} does not exists", i.Name)); if( ii.Count > 0 ) { Reservation r = (Reservation)Reservations[c.Id]; if( r == null ) { r = new Reservation( c, i, ii.CurrentPrice ); Reservations.Add( c.Id, r ); } else{ r.Items.Add(new ItemReservation(i,ii.CurrentPrice)); } ii.Count -= 1; return true; } else throw new System.Exception( "No more items available" ); } /// ///ADD CODE HERE /// /// /// Customer public void DropReservations( TP.Transaction context, TP.Customer c ) { Reservation r = (Reservation) Reservations[c.Id]; foreach( ItemReservation rr in r.Items ) ((ItemInstance)Items[rr.ThisItem]).Count += 1; Reservations.Remove(c.Id); } } }