KickJava   Java API By Example, From Geeks To Geeks.

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


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.Client;
24 import org.netbeans.lib.cvsclient.event.TerminationEvent;
25 import org.netbeans.lib.cvsclient.connection.*;
26 import org.netbeans.lib.cvsclient.command.GlobalOptions;
27 import org.netbeans.lib.cvsclient.command.Command;
28 import org.netbeans.lib.cvsclient.command.BasicCommand;
29 import org.netbeans.lib.cvsclient.command.log.RlogCommand;
30 import org.netbeans.lib.cvsclient.command.importcmd.ImportCommand;
31 import org.netbeans.lib.cvsclient.command.checkout.CheckoutCommand;
32 import org.netbeans.lib.cvsclient.command.add.AddCommand;
33 import org.netbeans.modules.versioning.system.cvss.util.Utils;
34 import org.openide.util.RequestProcessor;
35 import org.openide.util.TaskListener;
36 import org.openide.util.Task;
37 import org.openide.ErrorManager;
38 import org.openide.windows.InputOutput;
39 import org.openide.windows.IOProvider;
40 import org.openide.windows.OutputListener;
41
42 import javax.net.SocketFactory;
43 import java.io.File JavaDoc;
44 import java.io.IOException JavaDoc;
45
46 /**
47  * Defines a runtime environment for one CVSRoot. Everytime a command is executed for a new CVSRoot,
48  * a new instance of ClientRuntime is created and cached. This objects is then responsible for running
49  * commands for that CVS root.
50  *
51  * @author Maros Sandor
52  */

53 public class ClientRuntime {
54
55     /**
56      * The CVS Root this class manages.
57      */

58     private final String JavaDoc cvsRoot;
59
60     /**
61      * The CVS Root this class manages without password field.
62      */

63     private String JavaDoc cvsRootDisplay;
64     
65     /**
66      * Processor to use when posting commands to given CVSRoot. It has a throughput of 1.
67      */

68     private RequestProcessor requestProcessor;
69
70     /**
71      * Holds server communication log for associated cvs root.
72      */

73     private InputOutput log;
74
75     ClientRuntime(String JavaDoc root) {
76         cvsRoot = root;
77         cvsRootDisplay = root;
78         try {
79             CVSRoot rt = CVSRoot.parse(cvsRoot);
80             if (rt.getPassword() != null) {
81                 // this is not 100% correct but is straightforward
82
int idx = root.indexOf(rt.getPassword());
83                 if (idx != -1) {
84                     cvsRootDisplay = cvsRoot.substring(0, idx - 1) + cvsRoot.substring(idx + rt.getPassword().length());
85                 }
86             }
87         } catch (Exception JavaDoc e) {
88             // should not happen but is harmless here
89
}
90         requestProcessor = new RequestProcessor("CVS: " + cvsRootDisplay); // NOI18N
91
}
92
93     private void ensureValidCommand(File JavaDoc [] files) throws IllegalCommandException {
94         for (int i = 0; i < files.length; i++) {
95             File JavaDoc file = files[i];
96             try {
97                 String JavaDoc root = Utils.getCVSRootFor(file);
98                 if (!root.equals(cvsRoot)) throw new IllegalCommandException("#63547 command includes files from different CVS root.\n Expected: " + cvsRoot + "\nGot: " + root); // NOI18N
99
} catch (IOException JavaDoc e) {
100                 throw new IllegalCommandException("Missing or invalid CVS/Root for: " + file); // NOI18N
101
}
102         }
103     }
104
105     /**
106      * Creates a task that will execute the given command.
107      *
108      * @param cmd command to schedule
109      * @param globalOptions options to use when running the command
110      * @param mgr listener for command events
111      * @return RequestProcessor.Task a task ready to execute the command
112
113      * @throws IllegalCommandException if the command is not valid, e.g. it contains files that cannot be
114      * processed by a single command (they do not have a common filesystem root OR their CVS Roots differ)
115      */

116     public RequestProcessor.Task createTask(Command cmd, GlobalOptions globalOptions, final ExecutorSupport mgr)
117             throws IllegalCommandException {
118         
119         File JavaDoc [] files = getCommandFiles(cmd);
120         if ((cmd instanceof CheckoutCommand) == false && !(cmd instanceof RlogCommand)) { // XXX
121
ensureValidCommand(files);
122         }
123
124         if (globalOptions.getCVSRoot() == null) {
125             globalOptions = (GlobalOptions) globalOptions.clone();
126             globalOptions.setCVSRoot(cvsRoot);
127         }
128
129         Client client = createClient();
130         if ((cmd instanceof RlogCommand)) { // XXX
131
}
132         else if ((cmd instanceof CheckoutCommand)) { // XXX
133
BasicCommand bc = (BasicCommand) cmd;
134             if (bc.getFiles() != null) {
135                 String JavaDoc path = bc.getFiles()[0].getAbsolutePath();
136                 client.setLocalPath(path);
137             } else {
138                 // #67315: use some default working dir
139
client.setLocalPath(System.getProperty("user.dir")); // NOI18N
140
}
141         } else if (cmd instanceof ImportCommand) {
142             client.setLocalPath(((ImportCommand)cmd).getImportDirectory());
143         } else {
144             setLocalDirectory(client, files);
145         }
146
147         client.getEventManager().addCVSListener(mgr);
148         final CommandRunnable cr = new CommandRunnable(client, globalOptions, cmd, mgr);
149         mgr.commandEnqueued(cr);
150         RequestProcessor.Task task = requestProcessor.create(cr);
151         task.addTaskListener(new TaskListener() {
152             public void taskFinished(Task task) {
153                 try {
154                     // There are times when 'commandTerminated()' is not the last method called, therefore I introduced
155
// this event that really marks the very end of a command (thread end)
156
mgr.commandTerminated(new TerminationEvent(new Result(cr)));
157                 } catch (Throwable JavaDoc e) {
158                     ErrorManager.getDefault().notify(ErrorManager.WARNING, e);
159                 } finally {
160                     flushLog();
161                 }
162             }
163         });
164         return task;
165     }
166
167     /**
168      * Logs given message to associated console. The message
169      * is appended at the end.
170      */

171     public void log(String JavaDoc message) {
172         log(message, null);
173     }
174     
175     /**
176      * Logs given message to associated console and formats it as a hyperlink. The message
177      * is appended at the end.
178      */

179     public void log(String JavaDoc message, OutputListener hyperlinkListener) {
180         openLog();
181         if (hyperlinkListener != null) {
182             try {
183                 log.getOut().println(message, hyperlinkListener);
184             } catch (IOException JavaDoc e) {
185                 log.getOut().write(message);
186             }
187         } else {
188             log.getOut().write(message);
189         }
190     }
191
192     private void openLog() {
193         if (log == null || log.isClosed()) {
194             log = IOProvider.getDefault().getIO(cvsRootDisplay, false);
195             try {
196                 // XXX workaround, otherwise it writes to nowhere
197
log.getOut().reset();
198             } catch (IOException JavaDoc e) {
199                 ErrorManager err = ErrorManager.getDefault();
200                 err.notify(e);
201             }
202             //log.select();
203
}
204     }
205
206     public void logError(Throwable JavaDoc e) {
207         openLog();
208         e.printStackTrace(log.getOut());
209     }
210
211     /**
212      * Makes sure output from this command is visible.
213      */

214     void focusLog() {
215         if (log != null) log.select();
216     }
217
218     public void flushLog() {
219         if (log != null) log.getOut().close();
220     }
221
222
223     private File JavaDoc[] getCommandFiles(Command cmd) {
224         if (cmd instanceof AddCommand) {
225             AddCommand c = (AddCommand) cmd;
226             return c.getFiles();
227         } else if (cmd instanceof BasicCommand) {
228             BasicCommand c = (BasicCommand) cmd;
229             return c.getFiles();
230         } else {
231             return new File JavaDoc[0];
232         }
233     }
234
235     private void setLocalDirectory(Client client, File JavaDoc [] files) throws IllegalCommandException {
236         if (files.length == 0) {
237             return;
238         }
239
240         File JavaDoc commonParent;
241
242         if (files[0].isDirectory()) { // XXX it does not work for checkout
243
commonParent = files[0];
244         } else {
245             commonParent = files[0].getParentFile();
246         }
247         
248         for (int i = 1; i < files.length; i++) {
249             if (!Utils.isParentOrEqual(commonParent, files[i])) {
250                 for (;;) {
251                     commonParent = commonParent.getParentFile();
252                     if (commonParent == null) throw new IllegalCommandException("Files do not have common parent!"); // NOI18N
253
if (Utils.isParentOrEqual(commonParent, files[i])) {
254                         break;
255                     }
256                 }
257             }
258         }
259         
260         // we must not run commands from within folders that are not yet in CVS, try to find the closest uptodate parent
261
FileStatusCache cache = CvsVersioningSystem.getInstance().getStatusCache();
262         for (File JavaDoc versionedCommonParent = commonParent; versionedCommonParent != null; versionedCommonParent = versionedCommonParent.getParentFile()) {
263             FileInformation info = cache.getStatus(versionedCommonParent);
264             if (info.getStatus() == FileInformation.STATUS_VERSIONED_UPTODATE) {
265                 commonParent = versionedCommonParent;
266                 break;
267             }
268         }
269         client.setLocalPath(commonParent.getAbsolutePath());
270     }
271
272     /**
273      * Creates a new Client that will handle CVS operations.
274      *
275      * @return a Client instance
276      */

277     private Client createClient() {
278         Connection connection = setupConnection(CVSRoot.parse(cvsRoot));
279         Client client = new Client(connection, CvsVersioningSystem.getInstance().getAdminHandler());
280         client.setUncompressedFileHandler(CvsVersioningSystem.getInstance().getFileHandler());
281         client.setGzipFileHandler(CvsVersioningSystem.getInstance().getGzippedFileHandler());
282         return client;
283     }
284     
285     /**
286      * Sets up connection to a given CVS root including any proxies on route.
287      *
288      * @param cvsRoot root to connect to
289      * @return Connection object ready to connect to the given CVS root
290      * @throws IllegalArgumentException if the 'method' part of the supplied CVS Root is not recognized
291      */

292     public static Connection setupConnection(CVSRoot cvsRoot) throws IllegalArgumentException JavaDoc {
293
294         // for testing porposes allow to use dynamically generated port numbers
295
String JavaDoc t9yRoot = System.getProperty("netbeans.t9y.cvs.connection.CVSROOT"); // NOI18N
296
CVSRoot patchedCvsRoot = cvsRoot;
297         if (t9yRoot != null && t9yRoot.length() > 0) {
298             int idx = t9yRoot.indexOf(',');
299             if (idx != -1) {
300                 System.setProperty("netbeans.t9y.cvs.connection.CVSROOT", t9yRoot.substring(idx + 1)); // NOI18N
301
t9yRoot = t9yRoot.substring(0, idx);
302             }
303             try {
304                 patchedCvsRoot = CVSRoot.parse(t9yRoot);
305                 assert patchedCvsRoot.getRepository().equals(cvsRoot.getRepository());
306                 assert patchedCvsRoot.getHostName() == cvsRoot.getHostName() || patchedCvsRoot.getHostName().equals(cvsRoot.getHostName());
307                 ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "CVS.ClientRuntime: using patched CVSROOT " + t9yRoot); // NOI18N
308
} catch (IllegalArgumentException JavaDoc ex) {
309                 ErrorManager.getDefault().annotate(ex, "While parsing: " + t9yRoot); // NOI18N
310
ErrorManager.getDefault().notify(ex);
311             }
312         }
313
314         if (cvsRoot.isLocal()) {
315             LocalConnection con = new LocalConnection();
316             con.setRepository(cvsRoot.getRepository());
317             return con;
318         }
319
320         SocketFactory factory = SocketFactory.getDefault();
321
322         String JavaDoc method = cvsRoot.getMethod();
323         if (CVSRoot.METHOD_PSERVER.equals(method)) {
324             PServerConnection con = new PServerConnection(patchedCvsRoot, factory);
325             String JavaDoc password = PasswordsFile.findPassword(cvsRoot.toString());
326             con.setEncodedPassword(password);
327             return con;
328         } else if (CVSRoot.METHOD_EXT.equals(method)) {
329             CvsModuleConfig.ExtSettings extSettings = CvsModuleConfig.getDefault().getExtSettingsFor(cvsRoot);
330             String JavaDoc userName = cvsRoot.getUserName();
331             String JavaDoc host = cvsRoot.getHostName();
332             if (extSettings.extUseInternalSsh) {
333                 int port = patchedCvsRoot.getPort();
334                 port = port == 0 ? 22 : port; // default port
335
String JavaDoc password = extSettings.extPassword;
336                 if (password == null) {
337                     password = "\n"; // NOI18N user will be asked later on
338
}
339                 SSHConnection sshConnection = new SSHConnection(factory, host, port, userName, password);
340                 sshConnection.setRepository(cvsRoot.getRepository());
341                 return sshConnection;
342             } else {
343                 // What do we want to achieve here?
344
// It's possible to mimics ordinary cvs or cvsnt behaviour:
345
// Ordinary cvs style (CVS_RSH):
346
// command += " $hostname [-l$username] $CVS_SERVER"
347
// cvsnt style (CVS_EXT and CVS_RSH):
348
// command += " cvs server"
349
// I prefer the cvs style, see issue #62683 for details.
350

351                 String JavaDoc command = extSettings.extCommand;
352                 String JavaDoc cvs_server = System.getenv("CVS_SERVER");
353                 cvs_server = cvs_server != null? cvs_server + " server": "cvs server"; // NOI18N
354
String JavaDoc userOption = ""; // NOI18N
355
if ( userName != null ) {
356                     userOption = " -l " + userName; // NOI18N
357
}
358                 command += " " + host + userOption + " " + cvs_server; // NOI18N
359
ExtConnection connection = new ExtConnection(command);
360                 connection.setRepository(cvsRoot.getRepository());
361                 return connection;
362             }
363         }
364         
365         throw new IllegalArgumentException JavaDoc("Unrecognized CVS Root: " + cvsRoot); // NOI18N
366
}
367
368     public String JavaDoc toString() {
369         return "ClientRuntime queue=" + cvsRootDisplay + " processor=" + requestProcessor; // NOI18N
370
}
371
372     /**
373      * Encapsulates result of a finished command. If the command succeeded, the 'error' field is null. If it failed,
374      * it contains a throwable, cause of the error.
375      */

376     public static class Result {
377         
378         private final CommandRunnable runnable;
379
380         public Result(CommandRunnable runnable) {
381             this.runnable = runnable;
382         }
383
384         /**
385          * Get reason why command has not finished succesfully.
386          * For user cancels return an exception too.
387          */

388         public Throwable JavaDoc getError() {
389             return runnable.getFailure();
390         }
391
392         /** Has it been stopped by user's cancel? */
393         public boolean isAborted() {
394             return runnable.isAborted();
395         }
396     }
397 }
398
Popular Tags