summaryrefslogtreecommitdiff
path: root/java/test/Freeze/evictor/AccountI.java
blob: 6649385847675dbb945b898fc53123f64769288f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// **********************************************************************
//
// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************

package test.Freeze.evictor;
import test.Freeze.evictor.Test.*;

public class AccountI extends Account
{
    public int
    getBalance(Ice.Current current)
    {
        return balance;
    }

    public void
    deposit(int amount, Ice.Current current)
        throws InsufficientFundsException
    {
        //
        // No need to synchronize since everything occurs within its own transaction
        //
        int newBalance = balance + amount;
        if(newBalance < 0)
        {
            throw new InsufficientFundsException();
        }
        balance = newBalance;
    }

    public void
    transfer(int amount, AccountPrx toAccount, Ice.Current current) throws InsufficientFundsException
    {
        test(_evictor.getCurrentTransaction() != null);

        toAccount.deposit(amount); // collocated call
        deposit(-amount, current); // direct call
    }

    public void
    transfer2_async(AMD_Account_transfer2 cb, int amount, AccountPrx toAccount, Ice.Current current)
    {
        //
        // Here the dispatch thread does everything
        //
        test(_evictor.getCurrentTransaction() != null);

        try
        {
            toAccount.deposit(amount); // collocated call
            deposit(-amount, current); // direct call
        }
        catch(InsufficientFundsException ex)
        {
            cb.ice_exception(ex);
            return;
        }

        cb.ice_response();
    }

    public void
    transfer3_async(final AMD_Account_transfer3 cb, int amount, AccountPrx toAccount, Ice.Current current)
    {
        //
        // Here the dispatch thread does the actual work, but a separate thread sends the response
        //

        class ResponseThread extends Thread
        {
            synchronized void
            response()
            {
                _response = true;
                notify();
            }

            synchronized void
            exception(Ice.UserException e)
            {
                _exception = e;
                notify();
            }

            public synchronized void
            run()
            {
                if(_response == false && _exception == null)
                {
                    try
                    {
                        wait(1000);
                    }
                    catch(InterruptedException e)
                    {
                    }
                }
                try
                {
                    test(_evictor.getCurrentTransaction() == null);
                }
                catch(Freeze.EvictorDeactivatedException ex)
                {
                    //
                    // Clearly nobody is waiting for a response!
                    //
                    return;
                }

                if(_response)
                {
                    cb.ice_response();
                }
                else if(_exception != null)
                {
                    cb.ice_exception(_exception);
                }
                else
                {
                    //
                    // We don't wait forever!
                    //
                    cb.ice_exception(new Ice.TimeoutException());
                }
            }

            private boolean _response = false;
            private Ice.UserException _exception;
        };

        ResponseThread thread = new ResponseThread();
        thread.setDaemon(true);

        test(_evictor.getCurrentTransaction() != null);

        try
        {
            toAccount.deposit(amount); // collocated call
            deposit(-amount, current); // direct call
        }
        catch(Ice.UserException e)
        {
            thread.start();
            Thread.yield();

            //
            // Need to rollback here -- "rollback on user exception" does not work
            // when the dispatch commits before it gets any response!
            //
            _evictor.getCurrentTransaction().rollback();

            thread.exception(e);
            return;
        }

        thread.start();
        Thread.yield();
        thread.response();
    }

    public
    AccountI(int initialBalance, Freeze.TransactionalEvictor evictor)
    {
        super(initialBalance);
        _evictor = evictor;
    }

    public
    AccountI()
    {
    }

    public void
    init(Freeze.TransactionalEvictor evictor)
    {
        assert _evictor == null;
        _evictor = evictor;
    }

    private Freeze.TransactionalEvictor _evictor;

    private static void
    test(boolean b)
    {
        if(!b)
        {
            throw new RuntimeException();
        }
    }
}