KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > versioning > system > cvss > ExecutorSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.versioning.system.cvss;
21
22 import org.netbeans.lib.cvsclient.CVSRoot;
23 import org.netbeans.lib.cvsclient.event.*;
24 import org.netbeans.lib.cvsclient.command.*;
25 import org.netbeans.modules.versioning.system.cvss.util.Utils;
26 import org.netbeans.modules.versioning.system.cvss.util.CommandDuplicator;
27 import org.netbeans.modules.versioning.system.cvss.ui.wizards.RootWizard;
28 import org.netbeans.modules.versioning.system.cvss.ui.UIUtils;
29 import org.openide.ErrorManager;
30 import org.openide.DialogDescriptor;
31 import org.openide.DialogDisplayer;
32 import org.openide.NotifyDescriptor;
33 import org.openide.filesystems.FileUtil;
34 import org.openide.util.RequestProcessor;
35 import org.openide.util.NbBundle;
36 import org.openide.util.TaskListener;
37
38 import javax.swing.*;
39 import javax.swing.event.ChangeListener JavaDoc;
40 import javax.swing.event.ChangeEvent JavaDoc;
41 import java.util.*;
42 import java.util.List JavaDoc;
43 import java.io.IOException JavaDoc;
44 import java.io.File JavaDoc;
45 import java.io.StringWriter JavaDoc;
46 import java.io.PrintWriter JavaDoc;
47 import java.awt.*;
48 import java.awt.event.ActionEvent JavaDoc;
49 import java.awt.event.ActionListener JavaDoc;
50 import java.text.MessageFormat JavaDoc;
51 import org.openide.xml.XMLUtil;
52
53 /**
54  * Support class for command executors:
55  * <ul>
56  * <li>asynchronously executes command using
57  * one thread per repository thread pool
58  * <li>logs server output to console
59  * <li>supports execution retry on I/O or authentification errors
60  * <li>reliably detects command termination
61  * </ul>
62  *
63  * <p>Static method {@link #prepareBasicCommand} splits command
64  * operating over files in multiple repositories as necessary.
65  *
66  * @author Maros Sandor
67  */

68 public abstract class ExecutorSupport implements CVSListener, ExecutorGroup.Groupable {
69     
70     /**
71      * CVS server messages that start with one of these patterns won't be displayed in Output.
72      * Library needs these messages to prune empty directories, hence this workaround.
73      */

74     private static final String JavaDoc [] ignoredMessagePrefixes = {"cvs server: Updating", "cvs server: New directory"}; // NOI18N
75

76     protected final FileStatusCache cache;
77
78     /**
79      * List of {@link org.netbeans.lib.cvsclient.command.FileInfoContainer} objects that were collected during
80      * command execution. This list is meant to be processed by subclasses in the
81      * {@link #commandFinished(org.netbeans.modules.versioning.system.cvss.ClientRuntime.Result)} method.
82      * It is never cleared after command successfuly finishes.
83      */

84     protected List JavaDoc toRefresh = new ArrayList(10);
85     
86     protected final CvsVersioningSystem cvs;
87     protected final Command cmd;
88     private final GlobalOptions options;
89     private RequestProcessor.Task task;
90     private List JavaDoc taskListeners = new ArrayList(2);
91     private Throwable JavaDoc internalError;
92     private boolean terminated;
93     private boolean commandFailed;
94
95     private boolean finishedExecution;
96     private boolean executed;
97     private CommandRunnable commandRunnable;
98
99     private StringBuffer JavaDoc message = new StringBuffer JavaDoc();
100     private ClientRuntime clientRuntime;
101     private List JavaDoc errorMessages = new ArrayList();
102     private List JavaDoc warningMessages = new ArrayList();
103
104     private ExecutorGroup group;
105
106     /** t9y */
107     boolean t9yRetryFlag;
108
109     /**
110      * Be non-interactive.
111      */

112     private boolean nonInteractive;
113
114     /**
115      * Creates execution environment for given command.
116      * @param cvs
117      * @param cmd that has undergone {@link #prepareBasicCommand} splitting.
118      * @param options
119      */

120     protected ExecutorSupport(CvsVersioningSystem cvs, Command cmd, GlobalOptions options) {
121         this.cvs = cvs;
122         this.cmd = cmd;
123         this.options = options;
124         cache = cvs.getStatusCache();
125     }
126
127     protected void setNonInteractive(boolean nonInteractive) {
128         this.nonInteractive = nonInteractive;
129     }
130
131
132     /**
133      * Async execution.
134      * Returns after enqueing into execution queue i.e.
135      * after {@link #commandEnqueued} call.
136      */

137     public void execute() {
138         assert executed == false;
139         executed = true;
140         if (group == null) {
141             group = new ExecutorGroup(getDisplayName());
142             group.setNonInteractive(nonInteractive);
143         }
144
145         setup();
146         executeImpl();
147     }
148
149     private void executeImpl() {
150         try {
151             task = cvs.post(cmd, options, this);
152         } catch (Throwable JavaDoc e) {
153             internalError = e;
154             group.fail();
155
156             String JavaDoc msg = NbBundle.getMessage(ExecutorSupport.class, "BK1003", new Date(), getDisplayName());
157             if (clientRuntime != null) { // it is null if command did not start
158
clientRuntime.log(msg + "\n"); // NOI18N
159
clientRuntime.logError(e);
160             }
161             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e);
162             synchronized(this) {
163                 finishedExecution = true;
164                 notifyAll();
165             }
166             cleanup();
167         }
168     }
169     
170     /**
171      * Called once, just before the command is sent to CVS for execution.
172      */

173     protected void setup() {
174     }
175
176     /**
177      * Called once, after the command finishes execution.
178      */

179     protected void cleanup() {
180     }
181     
182     /**
183      * Default implementation takes first non-null name:
184      * <ul>
185      * <li>group display name
186      * <li>command display name
187      * <li>plain command syntax
188      * </ul>
189      */

190     protected String JavaDoc getDisplayName() {
191         String JavaDoc commandName;
192         if (group != null) {
193             commandName = group.getDisplayName();
194         } else {
195             commandName = cmd.getDisplayName();
196             if (commandName == null) {
197                 commandName = cmd.getCVSCommand();
198             }
199         }
200         return commandName;
201     }
202
203     /**
204      * Controls command textual messages logging
205      * into output window. By default everything is logged.
206      */

207     protected boolean logCommandOutput() {
208         return true;
209     }
210
211     public void joinGroup(ExecutorGroup group) {
212         assert executed == false;
213         this.group = group;
214     }
215
216     public ExecutorGroup getGroup() {
217         return group;
218     }
219
220     /**
221      * Return internal errors.
222      * @see #isSuccessful
223      */

224     public Throwable JavaDoc getFailure() {
225         return internalError;
226     }
227
228     /**
229      * Was the execution cancelled by user?
230      */

231     public boolean isCancelled() {
232         return group.isCancelled();
233     }
234
235     /**
236      * @return true on no internal error, user cancel nor command fail ("server erroe:")
237      */

238     public boolean isSuccessful() {
239         return internalError == null && group.isCancelled() == false && commandFailed == false;
240     }
241
242     /** @return task instance actually used (can change on retry) or null. */
243     public RequestProcessor.Task getTask() {
244         return task;
245     }
246
247     public void messageSent(MessageEvent e) {
248         if (e.isError()) {
249             String JavaDoc msg = e.getMessage();
250             if (msg == null) {
251                 // null is not too descriptive, pass it's source
252
RuntimeException JavaDoc rex = new RuntimeException JavaDoc("Received null MessageEvent from:"); // NOI18N
253
StringWriter JavaDoc sw = new StringWriter JavaDoc();
254                 PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
255                 rex.printStackTrace(pw);
256                 pw.close();
257                 msg = sw.getBuffer().toString();
258             }
259             errorMessages.add(msg);
260         }
261         else if (e.getMessage().startsWith("W ")) { // NOI18N
262
warningMessages.add(e.getMessage().substring(2));
263         }
264         if (e.isTagged()) {
265             String JavaDoc s = MessageEvent.parseTaggedMessage(message, e.getMessage());
266             if (s != null) {
267                 clientRuntime.log(s + "\n"); // NOI18N
268
message.setLength(0);
269             }
270         } else {
271             // If waiting for lock command execution looks deadlocked, always propagate
272
// E cvs server: [09:38:43] waiting for httpd's lock in /shared/data/ccvs/
273
boolean locked = e.getMessage().indexOf("waiting for") != -1; // NOI18N
274
locked &= e.getMessage().indexOf("lock in") != -1; // NOI18N
275
if (locked || logCommandOutput()) {
276                 if (e.getMessage().length() > 0) { // filter out bogus newlines
277
if (shouldBeDisplayed(e.getMessage())) {
278                         clientRuntime.log(e.getMessage() + "\n"); // NOI18N
279
}
280                 }
281             }
282         }
283     }
284
285     private boolean shouldBeDisplayed(String JavaDoc message) {
286         for (int i = 0; i < ignoredMessagePrefixes.length; i++) {
287             if (message.startsWith(ignoredMessagePrefixes[i])) return false;
288         }
289         return true;
290     }
291
292     public void messageSent(BinaryMessageEvent e) {
293     }
294
295     public void fileAdded(FileAddedEvent e) {
296     }
297
298     public void fileRemoved(FileRemovedEvent e) {
299     }
300
301     public void fileUpdated(FileUpdatedEvent e) {
302     }
303
304     public void fileToRemove(FileToRemoveEvent e) {
305     }
306
307     public void fileInfoGenerated(FileInfoEvent e) {
308         assert !terminated;
309         FileInfoContainer fic = e.getInfoContainer();
310         if (fic.getFile() == null) {
311             // this probably indicates a bug in the library but is usually harmless, log it just for reference
312
ErrorManager.getDefault().log(ErrorManager.WARNING, org.netbeans.modules.versioning.util.Utils.getStackTrace());
313             return;
314         }
315         if (fic instanceof DefaultFileInfoContainer) {
316             DefaultFileInfoContainer dfic = ((DefaultFileInfoContainer) fic);
317             dfic.setFile(FileUtil.normalizeFile(dfic.getFile()));
318             // filter out duplicate events, see org.netbeans.lib.cvsclient.response.UpdatedResponse.process()
319
// ? file.txt, U file.txt and C file.txt can all be fired for a single file in any order
320
for (Iterator i = toRefresh.iterator(); i.hasNext();) {
321                 FileInfoContainer existing = (FileInfoContainer) i.next();
322                 if (existing.getFile().equals(fic.getFile())) {
323                     String JavaDoc existingType = ((DefaultFileInfoContainer) existing).getType();
324                     String JavaDoc newType = dfic.getType();
325                     if (importance(newType) <= importance(existingType)) return;
326                     i.remove();
327                     break;
328                 }
329             }
330         }
331         toRefresh.add(fic);
332     }
333
334     private int importance(String JavaDoc type) {
335         return "UC".indexOf(type); // NOI18N
336
}
337
338     /**
339      * Associates this executor with actualy enqueued runnable
340      * (ClientRunnable created by ClientRuntime) performing the command.
341      *
342      * <p>Adds the runnable into group cancelable chain.
343      */

344     public void commandEnqueued(CommandRunnable commandRunnable) {
345         this.commandRunnable = commandRunnable;
346         group.enqueued(cvs.getClientRuntime(cmd, options), this);
347         group.addCancellable(commandRunnable);
348     }
349
350     /**
351      * It (re)runs...
352      */

353     public void commandStarted(CommandRunnable commandRunnable) {
354         clientRuntime = cvs.getClientRuntime(cmd, options);
355         group.started(clientRuntime);
356     }
357
358     public void commandTerminated(TerminationEvent e) {
359         try {
360             if (e.getSource() instanceof ClientRuntime.Result) {
361                 assert !terminated;
362                 terminated = true;
363                 ClientRuntime.Result result = (ClientRuntime.Result) e.getSource();
364                 Throwable JavaDoc error = result.getError();
365                 if (result.isAborted() || Thread.currentThread().isInterrupted()) {
366                     toRefresh.clear();
367                     return;
368                 } else if (error != null) {
369                     toRefresh.clear();
370                     if (error instanceof CommandException) {
371                         // TODO internalError = result.getError();?
372
// TODO group.fail();?
373
internalError = error;
374                         ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, error);
375                         report(NbBundle.getMessage(ExecutorSupport.class, "MSG_CommandFailed_Title"),
376                                NbBundle.getMessage(ExecutorSupport.class, "MSG_CommandFailed_Prompt"),
377                                Arrays.asList(new String JavaDoc [] { error.getMessage() }), NotifyDescriptor.ERROR_MESSAGE);
378                     }
379                     else if (!nonInteractive && retryConnection(error)) {
380                         terminated = false;
381                         String JavaDoc msg = NbBundle.getMessage(ExecutorSupport.class, "BK1004", new Date(), getDisplayName());
382                         clientRuntime = cvs.getClientRuntime(cmd, options);
383                         clientRuntime.log(msg + "\n"); // NOI18N
384
executeImpl();
385                     } else {
386                         if (!nonInteractive) {
387                             String JavaDoc msg = NbBundle.getMessage(ExecutorSupport.class, "BK1005", new Date(), getDisplayName());
388                             clientRuntime.log(msg + "\n"); // NOI18N
389
}
390                         internalError = result.getError();
391                         group.fail();
392                         ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, internalError);
393                         // TODO ErrorManager.getDefault().notify(ErrorManager.USER, internalError);?
394
}
395                 } else { // error == null
396
commandFinished((ClientRuntime.Result) e.getSource());
397                     if (cmd.hasFailed()) {
398                         commandFailed = true;
399                         group.fail();
400                         report(NbBundle.getMessage(ExecutorSupport.class, "MSG_CommandFailed_Title"),
401                                NbBundle.getMessage(ExecutorSupport.class, "MSG_CommandFailed_Prompt"),
402                                errorMessages, NotifyDescriptor.ERROR_MESSAGE);
403                     }
404                     if (warningMessages.size() > 0) {
405                         report(NbBundle.getMessage(ExecutorSupport.class, "MSG_CommandWarning_Title"),
406                                NbBundle.getMessage(ExecutorSupport.class, "MSG_CommandWarning_Prompt"),
407                                warningMessages, NotifyDescriptor.WARNING_MESSAGE);
408                     }
409                 }
410             }
411         } finally {
412             if (terminated) {
413                 cleanup();
414                 synchronized(this) {
415                     finishedExecution = true;
416                     notifyAll();
417                 }
418
419                 Iterator it;
420                 synchronized(taskListeners) {
421                     it = new ArrayList(taskListeners).iterator();
422                 }
423                 while (it.hasNext()) {
424                     try {
425                         TaskListener listener = (TaskListener) it.next();
426                         listener.taskFinished(task);
427                     } catch (RuntimeException JavaDoc ex) {
428                         ErrorManager.getDefault().notify(ex);
429                     }
430                 }
431
432                 group.finished(clientRuntime, this);
433             }
434         }
435     }
436
437     protected void report(String JavaDoc title, String JavaDoc prompt, List JavaDoc<String JavaDoc> messages, int type) {
438         if (nonInteractive) return;
439         boolean emptyReport = true;
440         for (String JavaDoc message : messages) {
441             if (message != null && message.length() > 0) {
442                 emptyReport = false;
443                 break;
444             }
445         }
446         if (emptyReport) return;
447         CommandReport report = new CommandReport(prompt, messages);
448         JButton ok = new JButton(NbBundle.getMessage(ExecutorSupport.class, "MSG_CommandReport_OK"));
449         NotifyDescriptor descriptor = new NotifyDescriptor(
450                 report,
451                 title,
452                 NotifyDescriptor.DEFAULT_OPTION,
453                 type,
454                 new Object JavaDoc [] { ok },
455                 ok);
456         DialogDisplayer.getDefault().notify(descriptor);
457     }
458     
459     /** Retry aware task events source*/
460     public void addTaskListener(TaskListener l) {
461         synchronized(taskListeners) {
462             taskListeners.add(l);
463         }
464     }
465
466     public void removeTaskListener(TaskListener l) {
467         synchronized(taskListeners) {
468             taskListeners.remove(l);
469         }
470     }
471
472     /**
473      * I/O exception occured give user chance to fix it.
474      * It shows dialog allowing to rewise proxy settings.
475      */

476     private boolean retryConnection(Throwable JavaDoc cause) {
477
478         Throwable JavaDoc initialCause = cause;
479         String JavaDoc cvsRoot = getCvsRoot();
480         if (cvsRoot == null) return false;
481         
482         final CVSRoot root;
483         try {
484             root = CVSRoot.parse(cvsRoot);
485         } catch (IllegalArgumentException JavaDoc ex) {
486             return false;
487         }
488
489         final RootWizard rootWizard = RootWizard.configureRoot(root.toString());
490         JPanel panel = new JPanel();
491         panel.setLayout(new BorderLayout());
492         panel.setBorder(BorderFactory.createEmptyBorder(0,6,6,6));
493         StringBuffer JavaDoc reason = new StringBuffer JavaDoc("<ul>"); // NOI18N
494
while (cause != null) {
495             try {
496                 String JavaDoc msg = cause.getLocalizedMessage();
497                 if (msg == null) {
498                     msg = cause.getClass().getName();
499                 } else {
500                     msg = XMLUtil.toElementContent(msg);
501                 }
502                 reason.append("<li>" + msg + "</li>"); // NOI18N
503
} catch (IOException JavaDoc ex) {
504                 ErrorManager.getDefault().notify(ex);
505             }
506             cause = cause.getCause();
507         }
508         reason.append("</ul>"); // NOI18N
509
String JavaDoc msg = NbBundle.getMessage(ExecutorSupport.class, "BK0001", reason.toString(), cvsRoot);
510         JLabel label = new JLabel(msg);
511         int ex = Math.max((int) (cvsRoot.length() * 1.1), 50);
512         UIUtils.computePreferredSize(label, ex);
513         panel.add(label, BorderLayout.NORTH);
514         panel.add(rootWizard.getPanel(), BorderLayout.CENTER);
515
516         String JavaDoc okMsg = NbBundle.getMessage(ExecutorSupport.class, "CTL_Password_Action_Ok");
517         final JButton ok = new JButton(okMsg);
518         ok.setEnabled(rootWizard.isValid());
519         ok.getAccessibleContext().setAccessibleDescription(okMsg);
520         String JavaDoc cancelMsg = NbBundle.getMessage(ExecutorSupport.class, "CTL_Password_Action_Cancel");
521         final JButton cancel = new JButton(cancelMsg);
522         cancel.getAccessibleContext().setAccessibleDescription(cancelMsg);
523         DialogDescriptor descriptor = new DialogDescriptor(
524                 panel,
525                 NbBundle.getMessage(ExecutorSupport.class, "BK0004", getDisplayName()),
526                 true,
527                 new Object JavaDoc [] { ok, cancel },
528                 ok,
529                 DialogDescriptor.BOTTOM_ALIGN,
530                 null,
531                 new ActionListener JavaDoc() {
532                     public void actionPerformed(ActionEvent JavaDoc e) {
533                     }
534                 });
535         descriptor.setMessageType(DialogDescriptor.WARNING_MESSAGE);
536         descriptor.setClosingOptions(null);
537         rootWizard.addChangeListener(new ChangeListener JavaDoc() {
538             public void stateChanged(ChangeEvent JavaDoc e) {
539                 ok.setEnabled(rootWizard.isValid());
540             }
541         });
542
543         ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, initialCause);
544         Dialog dialog = DialogDisplayer.getDefault().createDialog(descriptor);
545         dialog.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(ExecutorSupport.class, "BK0005"));
546         dialog.setVisible(true);
547
548         boolean retry = false;
549         if (descriptor.getValue() == ok) {
550             rootWizard.commit(false);
551             retry = true;
552         }
553         return retry;
554     }
555
556     private String JavaDoc getCvsRoot() {
557         if (cmd.getGlobalOptions() != null && cmd.getGlobalOptions().getCVSRoot() != null) return cmd.getGlobalOptions().getCVSRoot();
558         if (options != null && options.getCVSRoot() != null) return options.getCVSRoot();
559         try {
560             return cvs.detectCvsRoot(cmd);
561         } catch (NotVersionedException e) {
562         }
563         return null;
564     }
565
566     protected abstract void commandFinished(ClientRuntime.Result result);
567
568     public void moduleExpanded(ModuleExpansionEvent e) {
569     }
570
571     /**
572      * Prepares the command for execution by splitting it into one or more separate commands.
573      * The split is necessary if the original command acts on files that are from different repositories or
574      * they lie under different filesystem roots.
575      *
576      * @param cmd original command to be executed
577      * @return array of commands where each command contains only files that have a common parent and are stored under
578      * the same CVS root
579      *
580      * @see ExecutorGroup
581      */

582     protected static BasicCommand [] prepareBasicCommand(BasicCommand cmd) throws IOException JavaDoc {
583         String JavaDoc format = cmd.getDisplayName();
584         File JavaDoc [] files = cmd.getFiles();
585         if (files == null || files.length < 2) {
586             if (format != null) cmd.setDisplayName(MessageFormat.format(format, new Object JavaDoc [] { files == null ? "" : files[0].getName() })); // NOI18N
587
return new BasicCommand [] { cmd };
588         }
589         File JavaDoc [][] fileSets = splitFiles(files);
590         if (fileSets.length == 1) {
591             String JavaDoc nfiles = NbBundle.getMessage(ExecutorSupport.class, "MSG_ExecutorSupport_CommandFiles", Integer.toString(fileSets[0].length));
592             if (format != null) cmd.setDisplayName(MessageFormat.format(format, new Object JavaDoc [] { nfiles }));
593             return new BasicCommand [] { cmd };
594         }
595         BasicCommand [] commands = new BasicCommand[fileSets.length];
596         CommandDuplicator cloner = CommandDuplicator.getDuplicator(cmd);
597         for (int i = 0; i < fileSets.length; i++) {
598             BasicCommand bc = (BasicCommand) cloner.duplicate();
599             bc.setFiles(fileSets[i]);
600             commands[i] = bc;
601             String JavaDoc nfiles = NbBundle.getMessage(ExecutorSupport.class, "MSG_ExecutorSupport_CommandFiles", Integer.toString(fileSets[i].length));
602             if (format != null) commands[i].setDisplayName(MessageFormat.format(format, new Object JavaDoc [] { nfiles }));
603         }
604         return commands;
605     }
606
607     /**
608      * Splits input files to groups with common CVS root and common local filesystem parent. Files in each group
609      * are guaranteed to belong to the same CVS root and lie under one local directory (it may be '/').
610      *
611      * @param files files to examine
612      * @return File[][] groups of files
613      * @throws IOException if a CVS/Root file is unreadable
614      */

615     protected static File JavaDoc[][] splitFiles(File JavaDoc[] files) throws IOException JavaDoc {
616         List JavaDoc ret = new ArrayList();
617         File JavaDoc [][] aset = splitByCvsRoot(files);
618         for (int i = 0; i < aset.length; i++) {
619             File JavaDoc [] fileSet = aset[i];
620             File JavaDoc [][] splitSet = splitByCommonParent(fileSet);
621             for (int j = 0; j < splitSet.length; j++) {
622                 ret.add(splitSet[j]);
623             }
624         }
625         return (File JavaDoc[][]) ret.toArray(new File JavaDoc[ret.size()][]);
626     }
627
628     // XXX actually masks error in cvsclient library
629
// command-line cvs works smoothly over multi-cvsrooted
630
// workdirs opening new connections as necessary
631
protected static File JavaDoc[][] splitByCvsRoot(File JavaDoc [] files) throws IOException JavaDoc {
632         Map fileBuckets = new HashMap();
633         for (int i = 0; i < files.length; i++) {
634             File JavaDoc file = files[i];
635             String JavaDoc root = Utils.getCVSRootFor(file);
636             Set bucket = (Set) fileBuckets.get(root);
637             if (bucket == null) {
638                 bucket = new HashSet();
639                 fileBuckets.put(root, bucket);
640             }
641             bucket.add(file);
642         }
643         File JavaDoc [][] sets = new File JavaDoc[fileBuckets.size()][];
644         int idx = 0;
645         for (Iterator i = fileBuckets.values().iterator(); i.hasNext();) {
646             Set bucket = (Set) i.next();
647             sets[idx++] = (File JavaDoc[]) bucket.toArray(new File JavaDoc[bucket.size()]);
648         }
649         return sets;
650     }
651     
652     private static File JavaDoc[][] splitByCommonParent(File JavaDoc[] files) {
653         Map fileBuckets = new HashMap();
654         for (int i = 0; i < files.length; i++) {
655             File JavaDoc file = files[i];
656             File JavaDoc parent;
657             if (file.isDirectory()) {
658                 parent = file;
659             } else {
660                 parent = file.getParentFile();
661             }
662             
663             Set fileset = null;
664             File JavaDoc commonParent = null;
665             for (Iterator j = fileBuckets.keySet().iterator(); j.hasNext();) {
666                 File JavaDoc key = (File JavaDoc) j.next();
667                 commonParent = org.netbeans.modules.versioning.util.Utils.getCommonParent(parent, key);
668                 if (commonParent != null) {
669                     fileset = (Set) fileBuckets.get(key);
670                     j.remove();
671                     break;
672                 }
673             }
674
675             if (commonParent == null) {
676                 fileset = new HashSet(1);
677                 commonParent = parent;
678             }
679             fileset.add(file);
680             fileBuckets.put(commonParent, fileset);
681         }
682         
683         File JavaDoc [][] sets = new File JavaDoc[fileBuckets.size()][];
684         int idx = 0;
685         for (Iterator i = fileBuckets.values().iterator(); i.hasNext();) {
686             Set bucket = (Set) i.next();
687             sets[idx++] = (File JavaDoc[]) bucket.toArray(new File JavaDoc[bucket.size()]);
688         }
689         return sets;
690     }
691
692     /**
693      * Waits until all executors finish.
694      *
695      * @param executors array of executors to check
696      * @return true if all executors finished successfuly, false otherwise
697      */

698     public static boolean wait(ExecutorSupport[] executors) {
699         boolean success = true;
700         for (int i = 0; i < executors.length; i++) {
701             ExecutorSupport executor = executors[i];
702             synchronized(executor) {
703                 while (!executor.finishedExecution) {
704                     try {
705                         executor.wait();
706                     } catch (InterruptedException JavaDoc e) {
707                         // forward interrupt
708
executor.getGroup().cancel();
709                     }
710                 }
711             }
712             if (executor.isSuccessful() == false) {
713                 success = false;
714             }
715         }
716         return success;
717     }
718
719     /**
720      * Notify progress in terms of transmitted/received bytes.
721      */

722     public void increaseDataCounter(long bytes) {
723         group.increaseDataCounter(bytes);
724     }
725
726 }
727
Popular Tags