1/*
2 * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * This source code is provided to illustrate the usage of a given feature
28 * or technique and has been deliberately simplified. Additional steps
29 * required for a production-quality application, such as security checks,
30 * input validation and proper error handling, might not be present in
31 * this sample code.
32 */
33
34
35package com.sun.tools.example.debug.tty;
36
37import com.sun.jdi.*;
38import com.sun.jdi.request.EventRequest;
39import com.sun.jdi.request.ExceptionRequest;
40import com.sun.jdi.request.ClassPrepareRequest;
41import com.sun.jdi.event.ClassPrepareEvent;
42import java.util.ArrayList;
43
44abstract class EventRequestSpec {
45
46    final ReferenceTypeSpec refSpec;
47
48    int suspendPolicy = EventRequest.SUSPEND_ALL;
49
50    EventRequest resolved = null;
51    ClassPrepareRequest prepareRequest = null;
52
53    EventRequestSpec(ReferenceTypeSpec refSpec) {
54        this.refSpec = refSpec;
55    }
56
57    /**
58     * The 'refType' is known to match, return the EventRequest.
59     */
60    abstract EventRequest resolveEventRequest(ReferenceType refType)
61                                           throws Exception;
62
63    /**
64     * @return If this EventRequestSpec matches the 'refType'
65     * return the cooresponding EventRequest.  Otherwise
66     * return null.
67     */
68    synchronized EventRequest resolve(ClassPrepareEvent event) throws Exception {
69        if ((resolved == null) &&
70            (prepareRequest != null) &&
71            prepareRequest.equals(event.request())) {
72
73            resolved = resolveEventRequest(event.referenceType());
74            prepareRequest.disable();
75            Env.vm().eventRequestManager().deleteEventRequest(prepareRequest);
76            prepareRequest = null;
77
78            if (refSpec instanceof PatternReferenceTypeSpec) {
79                PatternReferenceTypeSpec prs = (PatternReferenceTypeSpec)refSpec;
80                if (! prs.isUnique()){
81                    /*
82                     * Class pattern event requests are never
83                     * considered "resolved", since future class loads
84                     * might also match.
85                     * Create and enable a new ClassPrepareRequest to
86                     * keep trying to resolve.
87                     */
88                    resolved = null;
89                    prepareRequest = refSpec.createPrepareRequest();
90                    prepareRequest.enable();
91                }
92            }
93        }
94        return resolved;
95    }
96
97    synchronized void remove() {
98        if (isResolved()) {
99            Env.vm().eventRequestManager().deleteEventRequest(resolved());
100        }
101        if (refSpec instanceof PatternReferenceTypeSpec) {
102            PatternReferenceTypeSpec prs = (PatternReferenceTypeSpec)refSpec;
103            if (! prs.isUnique()){
104                /*
105                 * This is a class pattern.  Track down and delete
106                 * all EventRequests matching this spec.
107                 * Note: Class patterns apply only to ExceptionRequests,
108                 * so that is all we need to examine.
109                 */
110                ArrayList<ExceptionRequest> deleteList = new ArrayList<ExceptionRequest>();
111                for (ExceptionRequest er :
112                         Env.vm().eventRequestManager().exceptionRequests()) {
113                    if (prs.matches(er.exception())) {
114                        deleteList.add (er);
115                    }
116                }
117                Env.vm().eventRequestManager().deleteEventRequests(deleteList);
118            }
119        }
120    }
121
122    private EventRequest resolveAgainstPreparedClasses() throws Exception {
123        for (ReferenceType refType : Env.vm().allClasses()) {
124            if (refType.isPrepared() && refSpec.matches(refType)) {
125                resolved = resolveEventRequest(refType);
126            }
127        }
128        return resolved;
129    }
130
131    synchronized EventRequest resolveEagerly() throws Exception {
132        try {
133            if (resolved == null) {
134                /*
135                 * Not resolved.  Schedule a prepare request so we
136                 * can resolve later.
137                 */
138                prepareRequest = refSpec.createPrepareRequest();
139                prepareRequest.enable();
140
141                // Try to resolve in case the class is already loaded.
142                resolveAgainstPreparedClasses();
143                if (resolved != null) {
144                    prepareRequest.disable();
145                    Env.vm().eventRequestManager().deleteEventRequest(prepareRequest);
146                    prepareRequest = null;
147                }
148            }
149            if (refSpec instanceof PatternReferenceTypeSpec) {
150                PatternReferenceTypeSpec prs = (PatternReferenceTypeSpec)refSpec;
151                if (! prs.isUnique()){
152                    /*
153                     * Class pattern event requests are never
154                     * considered "resolved", since future class loads
155                     * might also match.  Create a new
156                     * ClassPrepareRequest if necessary and keep
157                     * trying to resolve.
158                     */
159                    resolved = null;
160                    if (prepareRequest == null) {
161                        prepareRequest = refSpec.createPrepareRequest();
162                        prepareRequest.enable();
163                    }
164                }
165            }
166        } catch (VMNotConnectedException e) {
167            // Do nothing. Another resolve will be attempted when the
168            // VM is started.
169        }
170        return resolved;
171    }
172
173    /**
174     * @return the eventRequest this spec has been resolved to,
175     * null if so far unresolved.
176     */
177    EventRequest resolved() {
178        return resolved;
179    }
180
181    /**
182     * @return true if this spec has been resolved.
183     */
184    boolean isResolved() {
185        return resolved != null;
186    }
187
188    protected boolean isJavaIdentifier(String s) {
189        if (s.length() == 0) {
190            return false;
191        }
192
193        int cp = s.codePointAt(0);
194        if (! Character.isJavaIdentifierStart(cp)) {
195            return false;
196        }
197
198        for (int i = Character.charCount(cp); i < s.length(); i += Character.charCount(cp)) {
199            cp = s.codePointAt(i);
200            if (! Character.isJavaIdentifierPart(cp)) {
201                return false;
202            }
203        }
204
205        return true;
206    }
207
208    String errorMessageFor(Exception e) {
209        if (e instanceof IllegalArgumentException) {
210            return (MessageOutput.format("Invalid command syntax"));
211        } else if (e instanceof RuntimeException) {
212            // A runtime exception that we were not expecting
213            throw (RuntimeException)e;
214        } else {
215            return (MessageOutput.format("Internal error; unable to set",
216                                         this.refSpec.toString()));
217        }
218    }
219}
220