001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.execution41.org.openide.execution;
043:
044: import java.lang.reflect.Modifier;
045: import java.io.IOException;
046:
047: import org.openide.ErrorManager;
048: import org.openide.execution.*;
049: import org.openide.util.HelpCtx;
050: import org.openide.util.NbBundle;
051: import org.openide.windows.InputOutput;
052:
053: /** Executes a class in a thread in the current VM.
054: *
055: * @author Ales Novak
056: //* @deprecated Does not work well with Classpath API: there is no unambigous way to find the class name to load
057: //* given only the data object, without using that API.
058: */
059: public class ThreadExecutor extends Executor {
060: /** generated Serialized Version UID */
061: static final long serialVersionUID = -7160546092135474445L;
062:
063: /** Create a new thread executor. */
064: public ThreadExecutor() {
065: }
066:
067: /*
068: * @param ctx @see ExecutionEngine.Context
069: * @param info an ExecInfo instance describing executed class
070: */
071: public ExecutorTask execute(ExecInfo info) throws IOException {
072: TERunnable run = new TERunnable(info);
073: ExecutorTask ret;
074: InputOutput inout = (needsIO() ? null : InputOutput.NULL);
075:
076: synchronized (run) {
077: ret = ExecutionEngine.getDefault().execute(
078: info.getClassName(), run, inout);
079: run.setInputOutput(ret.getInputOutput());
080: try {
081: run.wait(); // wait for arbitrary exceptions during executing run
082: Throwable t = run.getException();
083: if (t != null) {
084: if (!(t instanceof ThreadDeath)) {
085: if (t instanceof RuntimeException) {
086: throw (RuntimeException) t;
087: } else if (t instanceof Error) {
088: throw (Error) t;
089: } else if (t instanceof IOException) {
090: throw (IOException) t;
091: } else {
092: throw new IOException();
093: }
094: }
095: }
096: } catch (InterruptedException e) {
097: IOException ioe = new IOException("Interupted: " + e); // NOI18N
098: ErrorManager.getDefault().annotate(ioe, e);
099: throw ioe;
100: }
101: }
102: return ret;
103: }
104:
105: public HelpCtx getHelpCtx() {
106: return new HelpCtx(ThreadExecutor.class);
107: }
108:
109: /** Subclasses of the executor can override this method
110: * to check loaded class before its main method is invoked.
111: *
112: * @param clazz
113: * @exception IOException
114: */
115: protected void checkClass(Class clazz) throws IOException {
116: // find main (String[])
117: final java.lang.reflect.Method method;
118: try {
119: method = clazz.getDeclaredMethod("main",
120: new Class[] { String[].class }); // NOI18N
121: } catch (NoSuchMethodException e) {
122: IOException ioe = new IOException(e.toString());
123: ErrorManager.getDefault().annotate(
124: ioe,
125: ErrorManager.USER,
126: null,
127: NbBundle.getMessage(ThreadExecutor.class,
128: "EXC_NoSuchMethodException"), e, null);
129: throw ioe;
130: }
131: if (!Modifier.isStatic(method.getModifiers())
132: || !Modifier.isPublic(method.getModifiers())
133: || method.getReturnType() != Void.TYPE) {
134: IOException ioe = new IOException("wrong signature"); // NOI18N
135: ErrorManager.getDefault().annotate(
136: ioe,
137: NbBundle.getMessage(ThreadExecutor.class,
138: "EXC_not_public_static_void"));
139: throw ioe;
140: }
141: }
142:
143: /** Invokes main method of the class with given parameters.
144: *
145: * @param clazz
146: * @param params
147: */
148: protected void executeClass(Class clazz, String[] params) {
149: try {
150: final java.lang.reflect.Method method = clazz
151: .getDeclaredMethod("main", new Class[] { params
152: .getClass() }); // NOI18N
153: method.setAccessible(true); // needs a permission
154: method.invoke(null, new Object[] { params });
155: } catch (java.lang.reflect.InvocationTargetException ex) {
156: if (!(ex.getTargetException() instanceof ThreadDeath))
157: ex.getTargetException().printStackTrace();
158: } catch (Exception e) {
159: e.printStackTrace(); // is redirected since executed under EE
160: }
161: }
162:
163: /** Allows subclasses to provide its own classloader for loading
164: * classes. Because the class loader is responsible for redirection
165: * of input and output this method takes input output where the
166: * I/O should be printed.
167: * <P>
168: * Default implementation creates <CODE>new NbClassLoader (io)</CODE>
169: *
170: * @param io the input/output to sent output of the classes to
171: * @return the class loader to use
172: */
173: protected ClassLoader createClassLoader(InputOutput io) {
174: throw new AssertionError("XXX broken, cannot work");
175: }
176:
177: /* ThreadExecutor runnable
178: * Its run method loads needed class, notifies waiting thread and executes main method of the class.
179: */
180: private class TERunnable implements Runnable {
181:
182: private Throwable exception;
183: private ExecInfo info;
184: private InputOutput io;
185:
186: TERunnable(ExecInfo info) {
187: this .info = info;
188: }
189:
190: public void run() {
191: String className = info.getClassName();
192: final String[] params = info.getArguments();
193: Class clazz = null;
194:
195: synchronized (this ) {
196: try {
197: ClassLoader loader = createClassLoader(io);
198: clazz = loader.loadClass(className);
199:
200: if (clazz == null) {
201: throw new IOException(); // [PENDING]
202: }
203:
204: if (clazz.getClassLoader() != loader) {
205: ErrorManager
206: .getDefault()
207: .log(
208: ErrorManager.WARNING,
209: "The class "
210: + clazz.getName()
211: + " was loaded by an unexpected classloader: "
212: + clazz
213: .getClassLoader()
214: + ". Usually this means you are trying to run a class from Filesystems via internal execution that is also in an enabled module JAR. The version in the JAR is being used."); // NOI18N
215: }
216:
217: checkClass(clazz);
218:
219: } catch (Exception e) {
220: exception = e;
221: return;
222: } catch (LinkageError e) {
223: exception = e;
224: return;
225: } finally {
226: this .notifyAll();
227: }
228: }
229: // out of sync block since it can take long time to complete...
230: executeClass(clazz, params);
231: }
232:
233: public Throwable getException() {
234: return exception;
235: }
236:
237: public void setInputOutput(InputOutput io) {
238: this.io = io;
239: }
240: }
241: }
|