This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 32054
Collapse All | Expand All

(-)bootstrap/src/org/netbeans/Bundle.properties (+14 lines)
Added Link Here
1
#                 Sun Public License Notice
2
# 
3
# The contents of this file are subject to the Sun Public License
4
# Version 1.0 (the "License"). You may not use this file except in
5
# compliance with the License. A copy of the License is available at
6
# http://www.sun.com/
7
# 
8
# The Original Code is NetBeans. The Initial Developer of the Original
9
# Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
10
# Microsystems, Inc. All Rights Reserved.
11
12
#Question to show user to find out whether start second instance of NetBeans  or not
13
MSG_AlreadyRunning=Another version of the program seems to be running. Continue anyway?
14
MSG_AlreadyRunningTitle=Warning
(-)bootstrap/src/org/netbeans/CLIHandler.java (+811 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans;
15
16
import java.io.*;
17
import java.net.InetAddress;
18
import java.net.ServerSocket;
19
import java.net.Socket;
20
import java.net.URL;
21
import java.security.NoSuchAlgorithmException;
22
import java.security.SecureRandom;
23
import java.util.ArrayList;
24
import java.util.Arrays;
25
import java.util.Collections;
26
import java.util.Enumeration;
27
import java.util.Iterator;
28
import java.util.List;
29
30
/**
31
 * Command Line Interface and User Directory Locker support class.
32
 * Subclasses may be registered into the system to handle special command-line options.
33
 * To be registered, use <samp>META-INF/services/org.netbeans.CLIHandler</code>
34
 * in a JAR file in the startup or dynamic class path (e.g. <samp>lib/ext/</samp>
35
 * or <samp>lib/</samp>).
36
 * @author Jaroslav Tulach
37
 * @since org.netbeans.core/1 1.18
38
 * @see "#32054"
39
 * @see <a href="http://openide.netbeans.org/proposals/arch/cli.html">Specification</a>
40
 */
41
public abstract class CLIHandler extends Object {
42
    /** lenght of the key used for connecting */
43
    private static final int KEY_LENGTH = 10;
44
    /** ok reply */
45
    private static final int REPLY_OK = 1;
46
    /** sends exit code */
47
    private static final int REPLY_EXIT = 2;
48
    /** fail reply */
49
    private static final int REPLY_FAIL = 0;
50
    
51
    /** request to read from input stream */
52
    private static final int REPLY_READ = 10;
53
    /** request to write */
54
    private static final int REPLY_WRITE = 11;
55
    /** request to find out how much data is available */
56
    private static final int REPLY_AVAILABLE = 12;
57
    
58
    /**
59
     * Used during bootstrap sequence. Should only be used by core, not modules.
60
     */
61
    public static final int WHEN_BOOT = 1;
62
    /**
63
     * Used during later initialization or while NetBeans is up and running.
64
     */
65
    public static final int WHEN_INIT = 2;
66
    
67
    private int when;
68
    
69
    /**
70
     * Create a CLI handler and indicate its preferred timing.
71
     * @param when when to run the handler: {@link #WHEN_BOOT} or {@link #WHEN_INIT}
72
     */
73
    protected CLIHandler(int when) {
74
        this.when = when;
75
    }
76
    
77
    /**
78
     * Process some set of command-line arguments.
79
     * Unrecognized or null arguments should be ignored.
80
     * Recognized arguments should be nulled out.
81
     * @param args arguments
82
     * @return error value or 0 if everything is all right
83
     */
84
    protected abstract int cli(Args args);
85
    
86
    private static void showHelp(PrintWriter w, List handlers) {
87
        w.println("-?");
88
        w.println("-help");
89
        w.println("  Show this help information.");
90
        Iterator it = handlers.iterator();
91
        while (it.hasNext()) {
92
            ((CLIHandler)it.next()).usage(w);
93
        }
94
    }
95
    
96
    /**
97
     * Print usage information for this handler.
98
     * @param w a writer to print to
99
     */
100
    protected abstract void usage(PrintWriter w);
101
    
102
    /** For testing purposes we can block the
103
     * algorithm in any place in the initialize method.
104
     */
105
    private static void enterState(int state, Integer block) {
106
        if (block == null) return;
107
        
108
        // for easier debugging of CLIHandlerTest
109
        //System.err.println("state: " + state + " block: " + block + " thread: " + Thread.currentThread());
110
        
111
        synchronized (block) {
112
            if (state == block.intValue()) {
113
                block.notifyAll();
114
                try {
115
                    block.wait();
116
                } catch (InterruptedException ex) {
117
                    throw new IllegalStateException();
118
                }
119
            }
120
        }
121
    }
122
    
123
    /** Notification of available handlers.
124
     * @return non-zero if one of the handlers fails
125
     */
126
    private static int notifyHandlers(Args args, List handlers, int when, boolean failOnUnknownOptions, boolean consume) {
127
        try {
128
            //System.err.println("notifyHandlers: handlers=" + handlers + " when=" + when + " args=" + Arrays.asList(args.getArguments()));
129
            if (failOnUnknownOptions) {
130
                String[] argv = args.getArguments();
131
                for (int i = 0; i < argv.length; i++) {
132
                    if (argv[i].equals("-?") || argv[i].equals("-help")) { // NOI18N
133
                        PrintWriter w = new PrintWriter(args.getOutputStream());
134
                        showHelp(w, handlers);
135
                        w.flush();
136
                        return 2;
137
                    }
138
                }
139
            }
140
            int r = 0;
141
            Iterator it = handlers.iterator();
142
            while (it.hasNext()) {
143
                CLIHandler h = (CLIHandler)it.next();
144
                if (h.when != when) continue;
145
146
                r = h.cli(args);
147
                //System.err.println("notifyHandlers: exit code " + r + " from " + h);
148
                if (r != 0) {
149
                    return r;
150
                }
151
            }
152
            if (failOnUnknownOptions) {
153
                String[] argv = args.getArguments();
154
                for (int i = 0; i < argv.length; i++) {
155
                    if (argv[i] != null) {
156
                        // Unhandled option.
157
                        PrintWriter w = new PrintWriter(args.getOutputStream());
158
                        w.println("Unknown option: " + argv[i]); // NOI18N
159
                        showHelp(w, handlers);
160
                        w.flush();
161
                        return 2;
162
                    }
163
                }
164
            }
165
            return 0;
166
        } finally {
167
            args.reset(consume);
168
        }
169
    }
170
    
171
    /**
172
     * Represents result of initialization.
173
     * @see #initialize(String[], ClassLoader)
174
     * @see #initialize(Args, Integer, List)
175
     */
176
    static final class Status {
177
        public static final int CANNOT_CONNECT = -255;
178
        
179
        private final File lockFile;
180
        private final int port;
181
        private final int exitCode;
182
        /**
183
         * General failure.
184
         */
185
        Status() {
186
            this(0);
187
        }
188
        /**
189
         * Failure due to a parse problem.
190
         * @param c bad status code (not 0)
191
         * @see #cli(Args)
192
         */
193
        Status(int c) {
194
            this(null, 0, c);
195
        }
196
        /**
197
         * Some measure of success.
198
         * @param l the lock file (not null)
199
         * @param p the server port (not 0)
200
         * @param c a status code (0 or not)
201
         */
202
        Status(File l, int p, int c) {
203
            lockFile = l;
204
            port = p;
205
            exitCode = c;
206
        }
207
        /**
208
         * Get the lock file, if available.
209
         * @return the lock file, or null if there is none
210
         */
211
        public File getLockFile() {
212
            return lockFile;
213
        }
214
        /**
215
         * Get the server port, if available.
216
         * @return a port number for the server, or 0 if there is no port open
217
         */
218
        public int getServerPort() {
219
            return port;
220
        }
221
        /**
222
         * Get the CLI parse status.
223
         * @return 0 for success, some other value for error conditions
224
         */
225
        public int getExitCode() {
226
            return exitCode;
227
        }
228
    }
229
    
230
    
231
    /** Initializes the system by creating lock file.
232
     *
233
     * @param args the command line arguments to recognize
234
     * @param classloader to find command CLIHandlers in
235
     * @param doAllInit if true, run all WHEN_INIT handlers now; else wait for {@link #finishInitialization}
236
     * @param failOnUnknownOptions if true, fail (status 2) if some options are not recognized (also checks for -? and -help)
237
     * @param cleanLockFile removes lock file if it appears to be dead
238
     * @return the file to be used as lock file or null parsing of args failed
239
     */
240
    static Status initialize(String[] args, ClassLoader loader, boolean doAllInit, boolean failOnUnknownOptions, boolean cleanLockFile) {
241
        return initialize(new Args(args, System.in, System.err, System.getProperty ("user.dir")), (Integer)null, allCLIs(loader), doAllInit, failOnUnknownOptions, cleanLockFile);
242
    }
243
    
244
    /**
245
     * What to do later when {@link #finishInitialization} is called.
246
     * May remain null.
247
     */
248
    private static Runnable doLater = null;
249
    
250
    /** Initializes the system by creating lock file.
251
     *
252
     * @param args the command line arguments to recognize
253
     * @param block the state we want to block in
254
     * @param handlers all handlers to use
255
     * @param doAllInit if true, run all WHEN_INIT handlers now; else wait for {@link #finishInitialization}
256
     * @param failOnUnknownOptions if true, fail (status 2) if some options are not recognized (also checks for -? and -help)
257
     * @param cleanLockFile removes lock file if it appears to be dead
258
     * @return a status summary
259
     */
260
    static Status initialize(final Args args, Integer block, final List handlers, boolean doAllInit, final boolean failOnUnknownOptions, boolean cleanLockFile) {
261
        // initial parsing of args
262
        {
263
            int r = notifyHandlers(args, handlers, WHEN_BOOT, false, failOnUnknownOptions);
264
            if (r != 0) {
265
                return new Status(r);
266
            }
267
        }
268
        
269
        // get the value
270
        String home = System.getProperty("netbeans.user"); // NOI18N
271
        if (home == null) {
272
            home = System.getProperty("user.home"); // NOI18N
273
        }
274
        File lockFile = new File(home, "lock"); // NOI18N
275
        
276
        for (int i = 0; i < 5; i++) {
277
            // try few times to succeed
278
            try {
279
                if (lockFile.exists()) {
280
                    enterState(5, block);
281
                    throw new IOException("EXISTS"); // NOI18N
282
                }
283
                lockFile.getParentFile().mkdirs();
284
                lockFile.createNewFile();
285
                lockFile.deleteOnExit();
286
                try {
287
                    // try to make it only user-readable (on Unix)
288
                    // since people are likely to leave a+r on their userdir
289
                    File chmod = new File("/bin/chmod"); // NOI18N
290
                    if (!chmod.isFile()) {
291
                        // Linux uses /bin, Solaris /usr/bin, others hopefully one of those
292
                        chmod = new File("/usr/bin/chmod"); // NOI18N
293
                    }
294
                    if (chmod.isFile()) {
295
                        int chmoded = Runtime.getRuntime().exec(new String[] {
296
                            chmod.getAbsolutePath(),
297
                            "go-rwx", // NOI18N
298
                            lockFile.getAbsolutePath()
299
                        }).waitFor();
300
                        if (chmoded != 0) {
301
                            throw new IOException("could not run " + chmod + " go-rwx " + lockFile); // NOI18N
302
                        }
303
                    }
304
                } catch (InterruptedException e) {
305
                    throw (IOException)new IOException(e.toString()).initCause(e);
306
                }
307
                
308
                enterState(10, block);
309
                
310
                byte[] arr = new byte[KEY_LENGTH];
311
                try {
312
                    SecureRandom.getInstance("SHA1PRNG").nextBytes(arr); // NOI18N
313
                } catch (NoSuchAlgorithmException e) {
314
                    // #36966: IBM JDK doesn't have it.
315
                    try {
316
                        SecureRandom.getInstance("IBMSecureRandom").nextBytes(arr); // NOI18N
317
                    } catch (NoSuchAlgorithmException e2) {
318
                        // OK, disable server...
319
                        System.err.println("WARNING: remote IDE automation features cannot be cryptographically secured, so disabling; please reopen http://www.netbeans.org/issues/show_bug.cgi?id=36966"); // NOI18N
320
                        e.printStackTrace();
321
                        return new Status();
322
                    }
323
                }
324
                
325
                Server server = new Server(arr, block, handlers, failOnUnknownOptions);
326
                
327
                DataOutputStream os = new DataOutputStream(new FileOutputStream(lockFile));
328
                int p = server.getLocalPort();
329
                os.writeInt(p);
330
                
331
                enterState(20, block);
332
                
333
                os.write(arr);
334
                os.close();
335
                
336
                int exitCode;
337
                if (doAllInit) {
338
                    exitCode = notifyHandlers(args, handlers, WHEN_INIT, failOnUnknownOptions, failOnUnknownOptions);
339
                } else {
340
                    doLater = new Runnable() {
341
                        public void run() {
342
                            int r = notifyHandlers(args, handlers, WHEN_INIT, failOnUnknownOptions, failOnUnknownOptions);
343
                            if (r != 0) {
344
                                // Not much to do about it.
345
                                System.err.println("Post-initialization command-line options could not be run."); // NOI18N
346
                                //System.err.println("r=" + r + " args=" + java.util.Arrays.asList(args.getArguments()));
347
                            }
348
                        }
349
                    };
350
                    exitCode = 0;
351
                }
352
                
353
                enterState(0, block);
354
                return new Status(lockFile, server.getLocalPort(), exitCode);
355
                
356
            } catch (IOException ex) {
357
                if (!"EXISTS".equals(ex.getMessage())) { // NOI18N
358
                    ex.printStackTrace();
359
                }
360
                // already exists, try to read
361
                byte[] key = null;
362
                int port = -1;
363
                try {
364
                    DataInputStream is = new DataInputStream(new FileInputStream(lockFile));
365
                    port = is.readInt();
366
                    key = new byte[KEY_LENGTH];
367
                    is.readFully(key);
368
                    is.close();
369
                } catch (IOException ex2) {
370
                    // ok, try to read it once more
371
                }
372
                
373
                if (key != null && port != -1) {
374
                    try {
375
                        // ok, try to connect
376
                        enterState(28, block);
377
                        Socket socket = new Socket(InetAddress.getLocalHost(), port);
378
                        // wait max of 1s for reply
379
                        socket.setSoTimeout(5000);
380
                        DataOutputStream os = new DataOutputStream(socket.getOutputStream());
381
                        os.write(key);
382
                        os.flush();
383
                        
384
                        enterState(30, block);
385
                        
386
                        DataInputStream replyStream = new DataInputStream(socket.getInputStream());
387
                        COMMUNICATION: for (;;) {
388
                            enterState(32, block);
389
                            int reply = replyStream.read();
390
                            //System.err.println("reply=" + reply);
391
                            enterState(34, block);
392
                            
393
                            switch (reply) {
394
                                case REPLY_FAIL:
395
                                    enterState(36, block);
396
                                    break COMMUNICATION;
397
                                case REPLY_OK:
398
                                    enterState(38, block);
399
                                    // write the arguments
400
                                    String[] arr = args.getArguments();
401
                                    os.writeInt(arr.length);
402
                                    for (int a = 0; a < arr.length; a++) {
403
                                        os.writeUTF(arr[a]);
404
                                    }
405
                                    os.writeUTF (args.getCurrentDirectory().toString()); 
406
                                    os.flush();
407
                                    break;
408
                                case REPLY_EXIT:
409
                                    int exitCode = replyStream.readInt();
410
                                    if (exitCode == 0) {
411
                                        // to signal end of the world
412
                                        exitCode = -1;
413
                                    }
414
                                    
415
                                    os.close();
416
                                    replyStream.close();
417
                                    
418
                                    enterState(0, block);
419
                                    return new Status(lockFile, port, exitCode);
420
                                case REPLY_READ: {
421
                                    enterState(42, block);
422
                                    int howMuch = replyStream.readInt();
423
                                    byte[] byteArr = new byte[howMuch];
424
                                    args.getInputStream().read(byteArr);
425
                                    os.write(byteArr);
426
                                    os.flush();
427
                                    break;
428
                                }
429
                                case REPLY_WRITE: {
430
                                    enterState(44, block);
431
                                    int howMuch = replyStream.readInt();
432
                                    byte[] byteArr = new byte[howMuch];
433
                                    replyStream.read(byteArr);
434
                                    args.getOutputStream().write(byteArr);
435
                                    break;
436
                                }
437
                                case REPLY_AVAILABLE:
438
                                    enterState(46, block);
439
                                    os.writeInt(args.getInputStream().available());
440
                                    os.flush();
441
                                    break;
442
                                case -1:
443
                                    // EOF. Why does this happen?
444
                                    break;
445
                                default:
446
                                    throw new IllegalStateException ("Reply: " + reply); // NOI18N
447
                            }
448
                        }
449
                        
450
                        // connection ok, but secret key not recognized
451
                        // delete the lock file
452
                    } catch (java.net.SocketTimeoutException ex2) {
453
                        // connection failed, the port is dead
454
                        enterState(33, block);
455
                    } catch (IOException ex2) {
456
                        // some strange exception
457
                        ex2.printStackTrace();
458
                        enterState(33, block);
459
                    }
460
                    if (cleanLockFile) {
461
                        // remove the file and try once more
462
                        lockFile.delete();
463
                    } else {
464
                        return new Status (Status.CANNOT_CONNECT);
465
                    }
466
                }
467
            }
468
            
469
            try {
470
                enterState(83, block);
471
                Thread.sleep((int)(Math.random() * 1000.00));
472
                enterState(85, block);
473
            } catch (InterruptedException ex) {
474
                // means nothing
475
            }
476
        }
477
        
478
        // failure
479
        return new Status();
480
    }
481
482
    /**
483
     * Run any {@link #WHEN_INIT} handlers that were passed to the original command line.
484
     * Should be called when the system is up and ready.
485
     * Cancels any existing actions, in case it is called twice.
486
     */
487
    static void finishInitialization() {
488
        if (doLater != null) {
489
            doLater.run();
490
            doLater = null;
491
        }
492
    }
493
    
494
    /** For a given classloader finds all registered CLIHandlers.
495
     */
496
    private static List allCLIs(ClassLoader loader) {
497
        /* should be, but we cannot use it yet, as openide is not separated:
498
        return new ArrayList(Lookups.metaInfServices(loader).lookup(new Lookup.Template(CLIHandler.class)).allInstances());
499
         */
500
        List res = new ArrayList();
501
        Enumeration en;
502
        try {
503
            en = loader.getResources("META-INF/services/org.netbeans.CLIHandler"); // NOI18N
504
        } catch (IOException ex) {
505
            ex.printStackTrace();
506
            return Collections.EMPTY_LIST;
507
        }
508
        while (en.hasMoreElements()) {
509
            URL url = (URL)en.nextElement();
510
            try {
511
                InputStream is = url.openStream();
512
                try {
513
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // NOI18N
514
                    while (true) {
515
                        String line = reader.readLine();
516
                        if (line == null) break;
517
                        
518
                        // Ignore blank lines and comments.
519
                        line = line.trim();
520
                        if (line.length() == 0) continue;
521
                        
522
                        boolean remove = false;
523
                        if (line.charAt(0) == '#') {
524
                            if (line.length() == 1 || line.charAt(1) != '-') {
525
                                continue;
526
                            }
527
                            
528
                            // line starting with #- is a sign to remove that class from lookup
529
                            remove = true;
530
                            line = line.substring(2);
531
                        }
532
                        Class inst = Class.forName(line, false, loader);
533
                        
534
                        Object obj = inst.newInstance();
535
                        res.add((CLIHandler)obj);
536
                    }
537
                } finally {
538
                    is.close();
539
                }
540
            } catch (Exception e) {
541
                e.printStackTrace();
542
            }
543
        }
544
        
545
        return res;
546
    }
547
    
548
    /** Class that represents available arguments to the CLI
549
     * handlers.
550
     */
551
    public static final class Args extends Object {
552
        private String[] args;
553
        private final String[] argsBackup;
554
        private InputStream is;
555
        private OutputStream os;
556
        private File currentDir;
557
        
558
        Args(String[] args, InputStream is, OutputStream os, String currentDir) {
559
            argsBackup = args;
560
            reset(false);
561
            this.is = is;
562
            this.os = os;
563
            this.currentDir = new File (currentDir);
564
        }
565
        
566
        /**
567
         * Restore the arguments list to a clean state.
568
         * If not consuming arguments, it is just set to the original list.
569
         * If consuming arguments, any nulled-out arguments are removed from the list.
570
         */
571
        void reset(boolean consume) {
572
            if (consume) {
573
                String[] a = args;
574
                if (a == null) {
575
                    a = argsBackup;
576
                }
577
                List l = new ArrayList(Arrays.asList(a));
578
                l.removeAll(Collections.singleton(null));
579
                args = (String[])l.toArray(new String[l.size()]);
580
            } else {
581
                args = (String[])argsBackup.clone();
582
            }
583
        }
584
        
585
        /**
586
         * Get the command-line arguments.
587
         * You may not modify the returned array except to set some elements
588
         * to null as you recognize them.
589
         * @return array of string arguments, may contain nulls
590
         */
591
        public String[] getArguments() {
592
            return args;
593
        }
594
        
595
        /**
596
         * Get an output stream to which data may be sent.
597
         * @return stream to write to
598
         */
599
        public OutputStream getOutputStream() {
600
            return os;
601
        }
602
        
603
        public File getCurrentDirectory () {
604
            return currentDir;
605
        }
606
        
607
        /**
608
         * Get an input stream that may supply additional data.
609
         * @return stream to read from
610
         */
611
        public InputStream getInputStream() {
612
            return is;
613
        }
614
    } // end of Args
615
    
616
    /** Server that creates local socket and communicates with it.
617
     */
618
    private static final class Server extends Thread {
619
        private byte[] key;
620
        private ServerSocket socket;
621
        private Integer block;
622
        private List handlers;
623
        private Socket work;
624
        private static volatile int counter;
625
        private final boolean failOnUnknownOptions;
626
        
627
        public Server(byte[] key, Integer block, List handlers, boolean failOnUnknownOptions) throws IOException {
628
            super("CLI Requests Server"); // NOI18N
629
            this.key = key;
630
            this.setDaemon(true);
631
            this.block = block;
632
            this.handlers = handlers;
633
            this.failOnUnknownOptions = failOnUnknownOptions;
634
            
635
            socket = new ServerSocket(0);
636
            
637
            start();
638
        }
639
        
640
        public Server(Socket request, byte[] key, Integer block, List handlers, boolean failOnUnknownOptions) throws IOException {
641
            super("CLI Handler Thread Handler: " + ++counter); // NOI18N
642
            this.key = key;
643
            this.setDaemon(true);
644
            this.block = block;
645
            this.handlers = handlers;
646
            this.work = request;
647
            this.failOnUnknownOptions = failOnUnknownOptions;
648
            
649
            start();
650
        }
651
        
652
        public int getLocalPort() {
653
            return socket.getLocalPort();
654
        }
655
        
656
        public void run() {
657
            if (work != null) {
658
                // I am a worker not listener server
659
                try {
660
                    handleConnect(work);
661
                } catch (IOException ex) {
662
                    ex.printStackTrace();
663
                }
664
                return;
665
            }
666
            
667
            
668
            while (true) {
669
                try {
670
                    enterState(65, block);
671
                    Socket s = socket.accept();
672
                    
673
                    // spans new request handler
674
                    new Server(s, key, block, handlers, failOnUnknownOptions);
675
                } catch (IOException ex) {
676
                    ex.printStackTrace();
677
                }
678
            }
679
        }
680
        
681
        
682
        private void handleConnect(Socket s) throws IOException {
683
            
684
            byte[] check = new byte[key.length];
685
            DataInputStream is = new DataInputStream(s.getInputStream());
686
            
687
            enterState(70, block);
688
            
689
            is.readFully(check);
690
            
691
            enterState(90, block);
692
            
693
            DataOutputStream os = new DataOutputStream(s.getOutputStream());
694
            
695
            if (Arrays.equals(check, key)) {
696
                enterState(93, block);
697
                os.write(REPLY_OK);
698
                os.flush();
699
                
700
                // continue with arguments
701
                int numberOfArguments = is.readInt();
702
                String[] args = new String[numberOfArguments];
703
                for (int i = 0; i < args.length; i++) {
704
                    args[i] = is.readUTF();
705
                }
706
                String currentDir = is.readUTF ();
707
                
708
                Args arguments = new Args(args, new IS(is, os), new OS(is, os), currentDir);
709
                int res = notifyHandlers(arguments, handlers, WHEN_INIT, failOnUnknownOptions, false);
710
                
711
                if (res == 0) {
712
                    enterState(98, block);
713
                } else {
714
                    enterState(99, block);
715
                }
716
                
717
                os.write(REPLY_EXIT);
718
                os.writeInt(res);
719
            } else {
720
                enterState(103, block);
721
                os.write(REPLY_FAIL);
722
            }
723
            
724
            
725
            enterState(120, block);
726
            
727
            os.close();
728
            is.close();
729
        }
730
        
731
        private static final class IS extends InputStream {
732
            private DataInputStream is;
733
            private DataOutputStream os;
734
            
735
            public IS(DataInputStream is, DataOutputStream os) {
736
                this.is = is;
737
                this.os = os;
738
            }
739
            
740
            public int read() throws IOException {
741
                byte[] arr = new byte[1];
742
                if (read(arr) == 1) {
743
                    return arr[0];
744
                } else {
745
                    return -1;
746
                }
747
            }
748
            
749
            public void close() throws IOException {
750
                super.close();
751
            }
752
            
753
            public int available() throws IOException {
754
                // ask for data
755
                os.write(REPLY_AVAILABLE);
756
                os.flush();
757
                // read provided data
758
                return is.readInt();
759
            }
760
            
761
            public int read(byte[] b) throws IOException {
762
                return read(b, 0, b.length);
763
            }
764
            
765
            public int read(byte[] b, int off, int len) throws IOException {
766
                // ask for data
767
                os.write(REPLY_READ);
768
                os.writeInt(len);
769
                os.flush();
770
                // read provided data
771
                return is.read(b, off, len);
772
            }
773
            
774
        } // end of IS
775
        
776
        private static final class OS extends OutputStream {
777
            private DataOutputStream os;
778
            
779
            public OS(DataInputStream is, DataOutputStream os) {
780
                this.os = os;
781
            }
782
            
783
            public void write(int b) throws IOException {
784
                byte[] arr = { (byte)b };
785
                write(arr);
786
            }
787
            
788
            public void write(byte[] b) throws IOException {
789
                write(b, 0, b.length);
790
            }
791
            
792
            public void close() throws IOException {
793
                super.close();
794
            }
795
            
796
            public void flush() throws IOException {
797
                os.flush();
798
            }
799
            
800
            public void write(byte[] b, int off, int len) throws IOException {
801
                os.write(REPLY_WRITE);
802
                os.writeInt(len);
803
                os.write(b, off, len);
804
            }
805
            
806
        } // end of OS
807
        
808
    } // end of Server
809
    
810
    
811
}
(-)bootstrap/src/org/netbeans/Main.java (-4 / +42 lines)
Lines 16-33 Link Here
16
import java.io.File;
16
import java.io.File;
17
import java.util.*;
17
import java.util.*;
18
import java.lang.reflect.Method;
18
import java.lang.reflect.Method;
19
import java.net.MalformedURLException;
20
import java.net.URL;
21
import java.util.jar.JarFile;
19
import java.util.jar.JarFile;
22
import java.security.*;
20
import java.security.*;
21
import java.net.*;
23
22
24
/** Bootstrap main class.
23
/** Bootstrap main class.
25
 * @author Jaroslav Tulach, Jesse Glick
24
 * @author Jaroslav Tulach, Jesse Glick
26
 */
25
 */
27
public class Main extends Object {
26
public class Main extends Object {
27
    
28
    /** Starts the IDE.
28
    /** Starts the IDE.
29
    * @param args the command line arguments
29
     * @param args the command line arguments
30
    */
30
     * @throws Exception for lots of reasons
31
     */
31
    public static void main (String args[]) throws Exception {
32
    public static void main (String args[]) throws Exception {
32
        ArrayList list = new ArrayList ();
33
        ArrayList list = new ArrayList ();
33
34
Lines 92-99 Link Here
92
        // Note that ModuleManager.updateContextClassLoaders will later change
93
        // Note that ModuleManager.updateContextClassLoaders will later change
93
        // the loader on this and other threads to be MM.SystemClassLoader anyway.
94
        // the loader on this and other threads to be MM.SystemClassLoader anyway.
94
        Thread.currentThread().setContextClassLoader (loader);
95
        Thread.currentThread().setContextClassLoader (loader);
96
        
97
        
98
        //
99
        // Evaluate command line interfaces and lock the user directory
100
        //
101
102
        CLIHandler.Status result;
103
        result = CLIHandler.initialize(args, loader, false, true, false);
104
        if (result.getExitCode () == CLIHandler.Status.CANNOT_CONNECT) {
105
            int value = javax.swing.JOptionPane.showConfirmDialog (
106
                null,
107
                java.util.ResourceBundle.getBundle("org/netbeans/Bundle").getString("MSG_AlreadyRunning"),
108
                java.util.ResourceBundle.getBundle("org/netbeans/Bundle").getString("MSG_AlreadyRunningTitle"),
109
                javax.swing.JOptionPane.OK_CANCEL_OPTION,
110
                javax.swing.JOptionPane.WARNING_MESSAGE
111
            );
112
            if (value == javax.swing.JOptionPane.OK_OPTION) {
113
                result = CLIHandler.initialize(args, loader, false, true, true);
114
            }
115
        }
116
117
        int res = result.getExitCode();
118
        if (res == -1) {
119
            // Connected to another running NB instance and succeeded in making a call.
120
            System.exit(0);
121
        } else if (res != 0) {
122
            // Some CLIHandler refused the invocation
123
            System.exit(res);
124
        }
95
125
96
        m.invoke (null, new Object[] { args });
126
        m.invoke (null, new Object[] { args });
127
    }
128
    
129
    /**
130
     * Call when the system is up and running, to complete handling of
131
     * delayed command-line options like -open FILE.
132
     */
133
    public static void finishInitialization() {
134
        CLIHandler.finishInitialization();
97
    }
135
    }
98
    
136
    
99
    private static final class BootClassLoader extends JarClassLoader {
137
    private static final class BootClassLoader extends JarClassLoader {
(-)src/META-INF/services/org.netbeans.CLIHandler (+1 lines)
Added Link Here
1
org.netbeans.core.CLIOptions
(-)src/org/netbeans/core/Bundle.properties (-1 lines)
Lines 171-177 Link Here
171
ERR_UIError=An error occured when setting the specified UI, using default UI ...
171
ERR_UIError=An error occured when setting the specified UI, using default UI ...
172
ERR_FontSizeExpected=Font size expected, using default font size...
172
ERR_FontSizeExpected=Font size expected, using default font size...
173
ERR_BadFontSize=Bad format of the font size, using default font size...
173
ERR_BadFontSize=Bad format of the font size, using default font size...
174
ERR_UnknownOption=Unknown option
175
174
176
# Notify system
175
# Notify system
177
# {0} - class name of exception
176
# {0} - class name of exception
(-)src/org/netbeans/core/CLIOptions.java (+173 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans.core;
15
16
import java.awt.*;
17
import java.awt.event.*;
18
import java.beans.*;
19
import java.io.*;
20
import java.security.*;
21
import java.util.Locale;
22
import javax.swing.*;
23
import javax.swing.border.*;
24
25
import org.netbeans.CLIHandler;
26
27
import org.netbeans.core.perftool.StartLog;
28
import org.openide.util.NbBundle;
29
30
/**
31
 * Handler for core options.
32
 * @author Jaroslav Tulach
33
 */
34
public class CLIOptions extends CLIHandler {
35
    
36
    private static boolean specifiedBranding = false;
37
38
    /**
39
     * Create a default handler.
40
     */
41
    public CLIOptions() {
42
        super(WHEN_BOOT);
43
    }
44
    
45
    protected int cli(Args arguments) {
46
        return cli(arguments.getArguments());
47
    }
48
    
49
    final int cli(String[] args) {
50
        // let's go through the command line
51
        for (int i = 0; i < args.length; i++) {
52
            if (args[i] == null) {
53
                continue;
54
            }
55
            boolean used = true;
56
            if (args[i].equalsIgnoreCase("-nogui")) { // NOI18N
57
                System.getProperties().put("org.openide.TopManager", "org.netbeans.core.NonGui"); // NOI18N
58
            } else if (args[i].equalsIgnoreCase("-nosplash")) { // NOI18N
59
                NonGui.noSplash = true;
60
            } else if (args[i].equalsIgnoreCase("-noinfo")) { // NOI18N
61
                // obsolete switch, ignore
62
            } else if (args[i].equalsIgnoreCase("-nologging")) { // NOI18N
63
                NonGui.noLogging = true;
64
            } else if (args[i].equalsIgnoreCase("-ui")) { // NOI18N
65
                args[i] = null;
66
                try {
67
                    NonGui.uiClass = Class.forName(args[++i]);
68
                } catch(ArrayIndexOutOfBoundsException e) {
69
                    System.err.println(NonGui.getString("ERR_UIExpected"));
70
                    return 2;
71
                } catch (ClassNotFoundException e2) {
72
                    System.err.println(NonGui.getString("ERR_UINotFound"));
73
                    return 1;
74
                }
75
            } else if (args[i].equalsIgnoreCase("-fontsize")) { // NOI18N
76
                args[i] = null;
77
                try {
78
                    NonGui.uiFontSize = Integer.parseInt(args[++i]);
79
                } catch(ArrayIndexOutOfBoundsException e) {
80
                    System.err.println(NonGui.getString("ERR_FontSizeExpected"));
81
                    return 2;
82
                } catch (NumberFormatException e2) {
83
                    System.err.println(NonGui.getString("ERR_BadFontSize"));
84
                    return 1;
85
                }
86
            } else if (args[i].equalsIgnoreCase("-locale")) { // NOI18N
87
                args[i] = null;
88
                String localeParam = args[++i];
89
                String language;
90
                String country = ""; // NOI18N
91
                String variant = ""; // NOI18N
92
                int index1 = localeParam.indexOf(":"); // NOI18N
93
                if (index1 == -1)
94
                    language = localeParam;
95
                else {
96
                    language = localeParam.substring(0, index1);
97
                    int index2 = localeParam.indexOf(":", index1+1); // NOI18N
98
                    if (index2 != -1) {
99
                        country = localeParam.substring(index1+1, index2);
100
                        variant = localeParam.substring(index2+1);
101
                    }
102
                    else
103
                        country = localeParam.substring(index1+1);
104
                }
105
                Locale.setDefault(new Locale(language, country, variant));
106
            } else if (args[i].equalsIgnoreCase("-branding")) { // NOI18N
107
                args[i] = null;
108
                String branding = args[++i];
109
                if (branding.equals("-")) branding = null; // NOI18N
110
                try {
111
                    NbBundle.setBranding(branding);
112
                } catch (IllegalArgumentException iae) {
113
                    iae.printStackTrace();
114
                    return 1;
115
                }
116
                specifiedBranding = true;
117
            } else {
118
                used = false;
119
            }
120
            args[i] = null;
121
        }
122
        
123
        return 0;
124
    }
125
    
126
    /** Initializes logging etc.
127
     */
128
    public static void initialize() {
129
        if (! specifiedBranding) {
130
            // Read default branding from file "lib/branding" in installation.
131
            File branding = new File(new File(NonGui.getHomeDir(), "lib"), "branding"); // NOI18N
132
            if (branding.exists()) {
133
                try {
134
                    InputStream is = new FileInputStream(branding);
135
                    try {
136
                        BufferedReader rd = new BufferedReader(new InputStreamReader(is));
137
                        String line = rd.readLine();
138
                        if (line == null || line.equals("")) // NOI18N
139
                            throw new IOException("empty branding file"); // NOI18N
140
                        if (rd.readLine() != null)
141
                            throw new IOException("branding file more than one line"); // NOI18N
142
                        line = line.trim();
143
                        if (line.equals("-")) line = null; // NOI18N
144
                        try {
145
                            org.openide.util.NbBundle.setBranding(line);
146
                        } catch (IllegalArgumentException iae) {
147
                            iae.printStackTrace();
148
                        }
149
                    } finally {
150
                        is.close();
151
                    }
152
                } catch (IOException ioe) {
153
                    ioe.printStackTrace();
154
                }
155
            }
156
        }
157
        
158
        if (!NonGui.noLogging) {
159
            try {
160
                NonGui.logger = new TopLogging(NonGui.getSystemDir());
161
            } catch (IOException e) {
162
                System.err.println("Cannot create log file. Logging disabled."); // NOI18N
163
                e.printStackTrace();
164
            }
165
        }
166
        StartLog.logProgress("TopLogging initialized"); // NOI18N
167
    }
168
    
169
    protected void usage(PrintWriter w) {
170
        w.println(NonGui.getString("TEXT_help"));
171
    }
172
    
173
}
(-)src/org/netbeans/core/Main.java (-1 / +1 lines)
Lines 414-420 Link Here
414
//     the loger
414
//     the loger
415
//    org.netbeans.lib.logger.TraceLogger lgr = org.netbeans.lib.logger.TraceLogger.getTraceLogger();
415
//    org.netbeans.lib.logger.TraceLogger lgr = org.netbeans.lib.logger.TraceLogger.getTraceLogger();
416
416
417
    NonGui.parseCommandLine (args);
417
    CLIOptions.initialize();
418
    StartLog.logProgress ("Command line parsed"); // NOI18N
418
    StartLog.logProgress ("Command line parsed"); // NOI18N
419
    
419
    
420
    checkDoubleBuffering();
420
    checkDoubleBuffering();
(-)src/org/netbeans/core/NonGui.java (-7 / +8 lines)
Lines 23-30 Link Here
23
import javax.swing.*;
23
import javax.swing.*;
24
import javax.swing.border.*;
24
import javax.swing.border.*;
25
import java.lang.reflect.Method;
25
import java.lang.reflect.Method;
26
import java.net.MalformedURLException;
26
import java.net.*;
27
import java.net.URLClassLoader;
28
import java.util.ArrayList;
27
import java.util.ArrayList;
29
import java.util.Iterator;
28
import java.util.Iterator;
30
import java.util.List;
29
import java.util.List;
Lines 35-48 Link Here
35
import org.openide.loaders.*;
34
import org.openide.loaders.*;
36
import org.openide.actions.*;
35
import org.openide.actions.*;
37
import org.openide.filesystems.*;
36
import org.openide.filesystems.*;
38
import org.openide.filesystems.FileSystem;
39
import org.openide.windows.*;
37
import org.openide.windows.*;
40
import org.openide.explorer.*;
38
import org.openide.explorer.*;
41
import org.openide.util.Lookup;
39
import org.openide.util.Lookup;
42
import org.openide.util.NbBundle;
40
import org.openide.util.NbBundle;
43
import org.openide.util.SharedClassObject;
41
import org.openide.util.SharedClassObject;
44
import org.openide.util.Utilities;
45
import org.openide.util.io.*;
42
import org.openide.util.io.*;
43
import org.openide.util.Utilities;
46
import org.openide.nodes.*;
44
import org.openide.nodes.*;
47
45
48
import org.netbeans.TopSecurityManager;
46
import org.netbeans.TopSecurityManager;
Lines 97-109 Link Here
97
95
98
    /** The flag whether to create the log - can be set via -nologging
96
    /** The flag whether to create the log - can be set via -nologging
99
    * command line option */
97
    * command line option */
100
    private static boolean noLogging = false;
98
    protected static boolean noLogging = false;
101
99
102
    /** The flag whether to show the Splash screen on the startup */
100
    /** The flag whether to show the Splash screen on the startup */
103
    protected  static boolean noSplash = false;
101
    protected static boolean noSplash = false;
104
102
105
    /** The Class that logs the IDE events to a log file */
103
    /** The Class that logs the IDE events to a log file */
106
    private static TopLogging logger;
104
    protected static TopLogging logger;
107
105
108
    /** Getter for home directory. */
106
    /** Getter for home directory. */
109
    protected static String getHomeDir () {
107
    protected static String getHomeDir () {
Lines 564-569 Link Here
564
        java.net.Authenticator.setDefault (new NbAuthenticator ());
562
        java.net.Authenticator.setDefault (new NbAuthenticator ());
565
        StartLog.logProgress ("Security managers installed"); // NOI18N
563
        StartLog.logProgress ("Security managers installed"); // NOI18N
566
        Main.incrementSplashProgressBar();
564
        Main.incrementSplashProgressBar();
565
        
566
        org.netbeans.Main.finishInitialization();
567
        StartLog.logProgress("Ran any delayed command-line options"); // NOI18N
567
    }
568
    }
568
569
569
570
(-)src/org/netbeans/core/NonGuiMain.java (-4 / +6 lines)
Lines 93-99 Link Here
93
    
93
    
94
    /** Prints help to the System.out. */
94
    /** Prints help to the System.out. */
95
    public static void showHelp2() {
95
    public static void showHelp2() {
96
        showHelp();
96
        // XXX how to implement? CLIOptions.showHelp();
97
        System.out.println(getStringX("CTL_INPUT_option")); // NOI18N
97
        System.out.println(getStringX("CTL_INPUT_option")); // NOI18N
98
        System.out.println(getStringX("CTL_OUTPUT_option"));
98
        System.out.println(getStringX("CTL_OUTPUT_option"));
99
        System.out.println(getStringX("CTL_INFO_option"));
99
        System.out.println(getStringX("CTL_INFO_option"));
Lines 338-347 Link Here
338
	// if we are starting the GUI (e.g. for running Jemmy tests),
338
	// if we are starting the GUI (e.g. for running Jemmy tests),
339
	// pass the args to Main.main, rather than NonGui.main.
339
	// pass the args to Main.main, rather than NonGui.main.
340
	//
340
	//
341
	if (startGui)
341
	if (startGui) {
342
	    startGui(tmpArgs);
342
	    startGui(tmpArgs);
343
	else
343
        } else {
344
	    NonGui.parseCommandLine(tmpArgs);
344
            new CLIOptions().cli(tmpArgs);
345
            CLIOptions.initialize();
346
        }
345
        
347
        
346
        if (showInfo) {
348
        if (showInfo) {
347
            info();
349
            info();
(-)test/unit/src/org/netbeans/CLIHandlerTest.java (+479 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.netbeans;
15
16
import java.io.*;
17
import junit.textui.TestRunner;
18
import org.netbeans.junit.*;
19
import java.util.*;
20
import org.openide.util.RequestProcessor;
21
22
/**
23
 * Test the command-line-interface handler.
24
 * @author Jaroslav Tulach
25
 */
26
public class CLIHandlerTest extends NbTestCase {
27
    
28
    private static ByteArrayInputStream nullInput = new ByteArrayInputStream(new byte[0]);
29
    private static ByteArrayOutputStream nullOutput = new ByteArrayOutputStream();
30
    
31
    public CLIHandlerTest(String name) {
32
        super(name);
33
    }
34
    
35
    public static void main(String[] args) {
36
        TestRunner.run(new NbTestSuite(CLIHandlerTest.class));
37
    }
38
    
39
    protected void setUp() throws Exception {
40
        super.setUp();
41
        
42
        // setups a temporary file
43
        String tmp = System.getProperty("java.io.tmpdir");
44
        assertNotNull(tmp);
45
        System.getProperties().put("netbeans.user", tmp);
46
        
47
        File f = new File(tmp, "lock");
48
        if (f.exists()) {
49
            assertTrue("Clean up previous mess", f.delete());
50
            assertTrue(!f.exists());
51
        }
52
    }
53
    
54
    public void testFileExistsButItCannotBeRead() throws Exception {
55
        // just creates the file and blocks
56
        InitializeRunner runner = new InitializeRunner(10);
57
        
58
        // blocks when operation fails
59
        InitializeRunner second = new InitializeRunner(85);
60
        
61
        for (int i = 0; i < 3; i++) {
62
            second.next();
63
        }
64
        
65
        // finishes the code
66
        runner.next();
67
        
68
        assertNotNull("Runner succeeded to allocate the file", runner.resultFile());
69
        
70
        // let the second code go on as well
71
        second.next();
72
        
73
        assertEquals("The same file has been allocated", runner.resultFile(), second.resultFile());
74
    }
75
    
76
    public void testFileExistsButTheServerCannotBeContacted() throws Exception {
77
        // start the server and block
78
        InitializeRunner runner = new InitializeRunner(65);
79
        
80
        assertNotNull("File created", runner.resultFile());
81
        assertTrue("Port allocated", runner.resultPort() != 0);
82
        
83
        // blocks when operation fails
84
        InitializeRunner second = new InitializeRunner(85);
85
        // second try should be ok
86
        second.next();
87
        
88
        assertNotNull("Previous file deleted and new one created", second.resultFile());
89
        assertTrue("Another port allocated", second.resultPort() != runner.resultPort());
90
        
91
        
92
    }
93
    
94
    public void testFileExistsButTheServerCannotBeContactedAndWeDoNotWantToCleanTheFile() throws Exception {
95
        // start the server and block
96
        InitializeRunner runner = new InitializeRunner(65);
97
        
98
        assertNotNull("File created", runner.resultFile());
99
        assertTrue("Port allocated", runner.resultPort() != 0);
100
        
101
        CLIHandler.Status res = CLIHandler.initialize(
102
            new CLIHandler.Args(new String[0], nullInput, nullOutput, ""), 
103
            null, Collections.EMPTY_LIST, true, false, false
104
        );
105
        
106
        assertEquals ("Cannot connect", CLIHandler.Status.CANNOT_CONNECT, res.getExitCode());
107
    }
108
    
109
    public void testFileExistsButTheKeyIsNotRecognized() throws Exception {
110
        // start the server be notified when it accepts connection
111
        InitializeRunner runner = new InitializeRunner(65);
112
        
113
        assertNotNull("File created", runner.resultFile());
114
        assertTrue("Port allocated", runner.resultPort() != 0);
115
        
116
        int s = (int)runner.resultFile().length();
117
        byte[] copy = new byte[s];
118
        FileInputStream is = new FileInputStream(runner.resultFile());
119
        assertEquals("Read fully", s, is.read(copy));
120
        is.close();
121
        
122
        // change the key
123
        copy[s - 1]++;
124
        
125
        FileOutputStream os = new FileOutputStream(runner.resultFile());
126
        os.write(copy);
127
        os.close();
128
        
129
        // try to connect to previous server be notified as soon as it
130
        // sends request
131
        InitializeRunner second = new InitializeRunner(30);
132
        
133
        // handle the request, say NO
134
        runner.next();
135
        
136
        // read the reply and allocate new port
137
        second.next();
138
        
139
        assertNotNull("Previous file deleted and new one created", second.resultFile());
140
        assertTrue("Another port allocated", second.resultPort() != runner.resultPort());
141
    }
142
    
143
    public void testCLIHandlersCanChangeLocationOfLockFile() throws Exception {
144
        File f = File.createTempFile("suffix", "tmp").getParentFile();
145
        final File dir = new File(f, "subdir");
146
        dir.delete();
147
        assertTrue(dir.exists() || dir.mkdir());
148
        
149
        class UserDir extends CLIHandler {
150
            private int cnt;
151
            
152
            public UserDir() {
153
                super(WHEN_BOOT);
154
            }
155
            
156
            protected int cli(Args args) {
157
                cnt++;
158
                System.setProperty("netbeans.user", dir.toString());
159
                return 0;
160
            }
161
            
162
            protected void usage(PrintWriter w) {}
163
        }
164
        UserDir ud = new UserDir();
165
        
166
        CLIHandler.Status res = cliInitialize(new String[0], ud, nullInput, nullOutput, null);
167
        
168
        assertEquals("Our command line handler is called once", 1, ud.cnt);
169
        assertEquals("Lock file is created in dir", dir, res.getLockFile().getParentFile());
170
        
171
        dir.delete();
172
    }
173
    
174
    public void testCLIHandlerCanStopEvaluation() throws Exception {
175
        class H extends CLIHandler {
176
            private int cnt;
177
            
178
            public H() {
179
                super(WHEN_INIT);
180
            }
181
            
182
            protected int cli(Args args) {
183
                cnt++;
184
                return 1;
185
            }
186
            
187
            protected void usage(PrintWriter w) {}
188
        }
189
        H h1 = new H();
190
        H h2 = new H();
191
        
192
        
193
        CLIHandler.Status res = cliInitialize(new String[0], new H[] {
194
            h1, h2
195
        }, nullInput, nullOutput);
196
        
197
        assertEquals("CLI evaluation failed with return code of h1", 1, res.getExitCode());
198
        assertEquals("First one executed", 1, h1.cnt);
199
        assertEquals("Not the second one", 0, h2.cnt);
200
    }
201
    
202
    public void testWhenInvokedTwiceParamsGoToTheFirstHandler() throws Exception {
203
        final String[] template = { "Ahoj", "Hello" };
204
        final String currentDir = "MyDir";
205
        
206
        class H extends CLIHandler {
207
            private int cnt;
208
            
209
            public H() {
210
                super(WHEN_INIT);
211
            }
212
            
213
            protected int cli(Args args) {
214
                String[] a = args.getArguments();
215
                String[] t = template;
216
                
217
                assertEquals("Same length", t.length, a.length);
218
                assertEquals("First is same", t[0], a[0]);
219
                assertEquals("Second is same", t[1], a[1]);
220
                assertEquals("Current dir is fine", currentDir, args.getCurrentDirectory().toString());
221
                return ++cnt;
222
            }
223
            
224
            protected void usage(PrintWriter w) {}
225
        }
226
        H h1 = new H();
227
        
228
        
229
        CLIHandler.Status res = cliInitialize(template, h1, nullInput, nullOutput, null, currentDir);
230
        
231
        assertEquals("First one executed", 1, h1.cnt);
232
        assertEquals("CLI evaluation failed with return code of h1", 1, res.getExitCode());
233
        
234
        res = cliInitialize(template, java.util.Collections.EMPTY_LIST, nullInput, nullOutput, null, currentDir);
235
        assertEquals("But again executed h1", 2, h1.cnt);
236
        assertEquals("Now the result is 2 as cnt++ was increased", 2, res.getExitCode());
237
        
238
    }
239
    
240
    public void testServerIsNotBlockedByLongRequests() throws Exception {
241
        class H extends CLIHandler {
242
            private int cnt = -1;
243
            public int toReturn;
244
            
245
            public H() {
246
                super(CLIHandler.WHEN_INIT);
247
            }
248
            
249
            protected synchronized int cli(Args args) {
250
                notifyAll();
251
                cnt++;
252
                return toReturn;
253
            }
254
            
255
            protected void usage(PrintWriter w) {}
256
        }
257
        H h = new H();
258
        
259
        h.toReturn = 7;
260
        final Integer blockOn = new Integer(99);
261
        CLIHandler.Status res = cliInitialize(new String[0], h, nullInput, nullOutput, blockOn);
262
        assertEquals("Called once, increased -1 to 0", 0, h.cnt);
263
        assertEquals("Result is provided by H", 7, res.getExitCode());
264
        
265
        // blocks after connection established, before returning the result
266
        class R implements Runnable {
267
            CLIHandler.Status res;
268
            public void run() {
269
                res = cliInitialize(new String[0], Collections.EMPTY_LIST, nullInput, nullOutput, blockOn);
270
            }
271
        }
272
        R r = new R();
273
        RequestProcessor.Task task;
274
        synchronized (h) {
275
            h.toReturn = 5;
276
            task = new org.openide.util.RequestProcessor("Blocking request").post(r);
277
            h.wait();
278
            assertEquals("Connects to the h", 1, h.cnt);
279
            assertEquals("But is not finished", null, r.res);
280
        }
281
        
282
        // while R is blocked, run another task
283
        h.toReturn = 0;
284
        res = cliInitialize(new String[0], Collections.EMPTY_LIST, nullInput, nullOutput, null);
285
        assertEquals("Called once, increased to 2", 2, h.cnt);
286
        assertEquals("Result is provided by H, H gives 0, changes into -1 right now", -1, res.getExitCode());
287
        
288
        synchronized (blockOn) {
289
            // let the R task go on
290
            blockOn.notifyAll();
291
        }
292
        task.waitFinished();
293
        assertNotNull("Now it is finished", r.res);
294
        assertEquals("Result is -1, if this fails: this usually means that the server is blocked by some work and the task R started new server to handle its request",
295
            5, r.res.getExitCode());
296
        assertEquals("H called three times (but counting from -1)", 2, h.cnt);
297
    }
298
    
299
    public void testReadingOfInputWorksInHandler() throws Exception {
300
        final byte[] template = { 1, 2, 3, 4 };
301
        
302
        class H extends CLIHandler {
303
            private byte[] arr;
304
            
305
            public H() {
306
                super(WHEN_INIT);
307
            }
308
            
309
            protected int cli(Args args) {
310
                try {
311
                    InputStream is = args.getInputStream();
312
                    arr = new byte[is.available() / 2];
313
                    if (arr.length > 0) {
314
                        assertEquals("Read amount is the same", arr.length, is.read(arr));
315
                    }
316
                    is.close();
317
                } catch (IOException ex) {
318
                    fail("There is an exception: " + ex);
319
                }
320
                return 0;
321
            }
322
            
323
            protected void usage(PrintWriter w) {}
324
        }
325
        H h1 = new H();
326
        H h2 = new H();
327
        
328
        // why twice? first attempt is direct, second thru the socket server
329
        for (int i = 0; i < 2; i++) {
330
            CLIHandler.Status res = cliInitialize(
331
                new String[0], new H[] { h1, h2 }, new ByteArrayInputStream(template), nullOutput);
332
            
333
            assertNotNull("Attempt " + i + ": " + "Can be read", h1.arr);
334
            assertEquals("Attempt " + i + ": " + "Read two bytes", 2, h1.arr.length);
335
            assertEquals("Attempt " + i + ": " + "First is same", template[0], h1.arr[0]);
336
            assertEquals("Attempt " + i + ": " + "Second is same", template[1], h1.arr[1]);
337
            
338
            assertNotNull("Attempt " + i + ": " + "Can read as well", h2.arr);
339
            assertEquals("Attempt " + i + ": " + "Just one char", 1, h2.arr.length);
340
            assertEquals("Attempt " + i + ": " + "And is the right one", template[2], h2.arr[0]);
341
            
342
            h1.arr = null;
343
            h2.arr = null;
344
        }
345
    }
346
    
347
    public void testWritingToOutputIsFine() throws Exception {
348
        final byte[] template = { 1, 2, 3, 4 };
349
        
350
        class H extends CLIHandler {
351
            public H() {
352
                super(WHEN_INIT);
353
            }
354
            
355
            protected int cli(Args args) {
356
                try {
357
                    OutputStream os = args.getOutputStream();
358
                    os.write(template);
359
                    os.close();
360
                } catch (IOException ex) {
361
                    fail("There is an exception: " + ex);
362
                }
363
                return 0;
364
            }
365
            
366
            protected void usage(PrintWriter w) {}
367
        }
368
        H h1 = new H();
369
        H h2 = new H();
370
        
371
        // why twice? first attempt is direct, second thru the socket server
372
        for (int i = 0; i < 2; i++) {
373
            ByteArrayOutputStream os = new ByteArrayOutputStream();
374
            
375
            CLIHandler.Status res = cliInitialize(
376
                new String[0], new H[] { h1, h2 }, nullInput, os);
377
            
378
            byte[] arr = os.toByteArray();
379
            assertEquals("Double size of template", template.length * 2, arr.length);
380
            
381
            for (int pos = 0; pos < arr.length; pos++) {
382
                assertEquals(pos + ". is the same", template[pos % template.length], arr[pos]);
383
            }
384
        }
385
    }
386
    
387
    //
388
    // Utility methods
389
    //
390
    
391
    private static CLIHandler.Status cliInitialize(String[] args, CLIHandler handler, InputStream is, OutputStream os, Integer lock) {
392
        return cliInitialize(args, handler, is, os, lock, System.getProperty ("user.dir"));
393
    }
394
    private static CLIHandler.Status cliInitialize(String[] args, CLIHandler handler, InputStream is, OutputStream os, Integer lock, String currentDir) {
395
        return cliInitialize(args, Collections.nCopies(1, handler), is, os, lock, currentDir);
396
    }
397
    private static CLIHandler.Status cliInitialize(String[] args, CLIHandler[] arr, InputStream is, OutputStream os) {
398
        return cliInitialize(args, Arrays.asList(arr), is, os, null);
399
    }
400
    private static CLIHandler.Status cliInitialize(String[] args, List coll, InputStream is, OutputStream os, Integer lock) {
401
        return cliInitialize (args, coll, is, os, lock, System.getProperty ("user.dir"));
402
    }
403
    private static CLIHandler.Status cliInitialize(String[] args, List coll, InputStream is, OutputStream os, Integer lock, String currentDir) {
404
        return CLIHandler.initialize(new CLIHandler.Args(args, is, os, currentDir), lock, coll, true, false, true);
405
    }
406
    
407
    
408
    private static final class InitializeRunner extends Object implements Runnable {
409
        private Integer block;
410
        private String[] args;
411
        private CLIHandler handler;
412
        private CLIHandler.Status result;
413
        
414
        public InitializeRunner(int till) throws InterruptedException {
415
            this(new String[0], null, till);
416
        }
417
        
418
        public InitializeRunner(String[] args, CLIHandler h, int till) throws InterruptedException {
419
            this(args, h, new Integer(till));
420
        }
421
        public InitializeRunner(String[] args, CLIHandler h, Integer till) throws InterruptedException {
422
            this.args = args;
423
            this.block = till;
424
            this.handler = h;
425
            
426
            synchronized (block) {
427
                RequestProcessor.getDefault().post(this);
428
                block.wait();
429
            }
430
        }
431
        
432
        public void run() {
433
            synchronized (block) {
434
                result = CLIHandler.initialize(
435
                    new CLIHandler.Args(args, nullInput, nullOutput, ""),
436
                    block,
437
                    handler == null ? java.util.Collections.EMPTY_LIST : java.util.Collections.nCopies(1, handler),
438
                    true,
439
                    false,
440
                    true);
441
                // we are finished, wake up guys in next() if any
442
                block.notifyAll();
443
            }
444
        }
445
        
446
        /** Executes the code to next invocation */
447
        public void next() throws InterruptedException {
448
            synchronized (block) {
449
                block.notify();
450
                block.wait();
451
            }
452
        }
453
        
454
        /** Has already the resutl?
455
         */
456
        public boolean hasResult() {
457
            return result != null;
458
        }
459
        
460
        /** Gets the resultFile, if there is some,
461
         */
462
        public File resultFile() {
463
            if (result == null) {
464
                fail("No result produced");
465
            }
466
            return result.getLockFile();
467
        }
468
        
469
        /** Gets the port, if there is some,
470
         */
471
        public int resultPort() {
472
            if (result == null) {
473
                fail("No result produced");
474
            }
475
            return result.getServerPort();
476
        }
477
    } // end of InitializeRunner
478
    
479
}

Return to bug 32054