aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/tools/Callback.java
blob: 56c874146ac7592bbfee5953914d15955ccd6435 (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
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package javassist.tools;

import javassist.CannotCompileException;
import javassist.CtBehavior;

import java.util.HashMap;
import java.util.UUID;

/**
 * Creates bytecode that when executed calls back to the instance's result method.
 *
 * <p>Example of how to create and insert a callback:</p>
 * <pre>
 * ctMethod.insertAfter(new Callback("Thread.currentThread()") {
 *     public void result(Object... objects) {
 *         Thread thread = (Thread) objects[0];
 *         // do something with thread...
 *     }
 * }.sourceCode());
 * </pre>
 * <p>Contains utility methods for inserts callbacks in <code>CtBehaviour</code>, example:</p>
 * <pre>
 * insertAfter(ctBehaviour, new Callback("Thread.currentThread(), dummyString") {
 *     public void result(Object... objects) {
 *         Thread thread = (Thread) objects[0];
 *         // do something with thread...
 *     }
 * });
 * </pre>
 *
 * @author Marten Hedborg
 */
public abstract class Callback {

    public static HashMap<String, Callback> callbacks = new HashMap<String, Callback>();

    private final String sourceCode;

    /**
     * Constructs a new <code>Callback</code> object.
     *
     * @param src       The source code representing the inserted callback bytecode.
     *                  Can be one or many single statements each returning one object.
     *                  If many single statements are used they must be comma separated.
     */
    public Callback(String src){
        String uuid = UUID.randomUUID().toString();
        callbacks.put(uuid, this);
        sourceCode = "((javassist.tools.Callback) javassist.tools.Callback.callbacks.get(\""+uuid+"\")).result(new Object[]{"+src+"});";
    }

    /**
     * Gets called when bytecode is executed
     *
     * @param objects   Objects that the bytecode in callback returns
     */
    public abstract void result(Object... objects);

    @Override
    public String toString(){
        return sourceCode();
    }

    public String sourceCode(){
        return sourceCode;
    }

    /**
     * Utility method to insert callback at the beginning of the body.
     *
     * @param callback  The callback
     *
     * @see CtBehavior#insertBefore(String)
     */
    public static void insertBefore(CtBehavior behavior, Callback callback)
            throws CannotCompileException
    {
        behavior.insertBefore(callback.toString());
    }

    /**
     * Utility method to inserts callback at the end of the body.
     * The callback is inserted just before every return instruction.
     * It is not executed when an exception is thrown.
     *
     * @param behavior  The behaviour to insert callback in
     * @param callback  The callback
     *
     * @see CtBehavior#insertAfter(String, boolean)
     */
    public static void insertAfter(CtBehavior behavior,Callback callback)
            throws CannotCompileException
    {
        behavior.insertAfter(callback.toString(), false);
    }

    /**
     * Utility method to inserts callback at the end of the body.
     * The callback is inserted just before every return instruction.
     * It is not executed when an exception is thrown.
     *
     * @param behavior  The behaviour to insert callback in
     * @param callback  The callback representing the inserted.
     * @param asFinally True if the inserted is executed
     *                  Not only when the control normally returns
     *                  but also when an exception is thrown.
     *                  If this parameter is true, the inserted code cannot
     *                  access local variables.
     *
     * @see CtBehavior#insertAfter(String, boolean)
     */
    public static void insertAfter(CtBehavior behavior, Callback callback, boolean asFinally)
            throws CannotCompileException
    {
        behavior.insertAfter(callback.toString(), asFinally);
    }

    /**
     * Utility method to inserts callback at the specified line in the body.
     *
     * @param behavior  The behaviour to insert callback in
     * @param callback  The callback representing.
     * @param lineNum   The line number.  The callback is inserted at the
     *                  beginning of the code at the line specified by this
     *                  line number.
     *
     * @return      The line number at which the callback has been inserted.
     *
     * @see CtBehavior#insertAt(int, String)
     */
    public static int insertAt(CtBehavior behavior, Callback callback, int lineNum)
            throws CannotCompileException
    {
        return behavior.insertAt(lineNum, callback.toString());
    }
}