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);
}
}
}