KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > cvsclient > Client


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 the CVS Client Library.
16  * The Initial Developer of the Original Software is Robert Greig.
17  * Portions created by Robert Greig are Copyright (C) 2000.
18  * All Rights Reserved.
19  *
20  * Contributor(s): Robert Greig.
21  *****************************************************************************/

22 package org.netbeans.lib.cvsclient;
23
24 import java.io.*;
25 import java.util.*;
26
27 import org.netbeans.lib.cvsclient.admin.*;
28 import org.netbeans.lib.cvsclient.command.*;
29 import org.netbeans.lib.cvsclient.connection.*;
30 import org.netbeans.lib.cvsclient.event.*;
31 import org.netbeans.lib.cvsclient.file.*;
32 import org.netbeans.lib.cvsclient.request.*;
33 import org.netbeans.lib.cvsclient.response.*;
34 import org.netbeans.lib.cvsclient.util.*;
35
36 /**
37  * The main way of communication with a server using the CVS Protocol. The
38  * client is not responsible for setting up the connection with the server,
39  * only interacting with it.
40  * @see org.netbeans.lib.cvsclient.connection.Connection
41  * @author Robert Greig
42  */

43 public class Client implements ClientServices, ResponseServices {
44     /**
45      * The connection used to interact with the server.
46      */

47     private Connection connection;
48
49     /**
50      * The file handler to use.
51      */

52     private FileHandler transmitFileHandler;
53
54     private FileHandler gzipFileHandler = new GzippedFileHandler();
55     private FileHandler uncompFileHandler = new DefaultFileHandler();
56
57     private boolean dontUseGzipFileHandler;
58
59     /**
60      * The modified date.
61      */

62     private Date modifiedDate;
63
64     /**
65      * The admin handler to use.
66      */

67     private AdminHandler adminHandler;
68
69     /**
70      * The local path, ie the path to the directory in which this command
71      * was executed.
72      */

73     private String JavaDoc localPath;
74
75     /**
76      * Whether any commands have been executed so far. This allows us to
77      * send some initialisation requests before the first command.
78      */

79     private boolean isFirstCommand = true;
80
81     /**
82      * The event manager.
83      */

84     private final EventManager eventManager = new EventManager(this);
85
86     /**
87      * The global options for the executing command.
88      */

89     private GlobalOptions globalOptions;
90     
91     private PrintStream stderr = System.err;
92
93     /**
94      * This is set to true if we should abort the current command.
95      */

96     private boolean abort;
97     
98     private ResponseFactory responseFactory;
99
100     private IgnoreFileFilter ignoreFileFilter;
101     
102     /*
103      * The valid list of requests that is valid for the CVS server
104      * corresponding to this client
105      */

106     private Map validRequests = new HashMap();
107     
108     /**
109      * A map of file patterns and keyword substitution options
110      */

111     private Map wrappersMap = null;
112     
113     /**
114      * This will be set to true after initialization requests are sent
115      * to the server. The initialization requests setup valid requests
116      * and send RootRequest to the server.
117      */

118     private boolean initialRequestsSent = false;
119     
120     private boolean printConnectionReuseWarning = false;
121     
122     private static final Set ALLOWED_CONNECTION_REUSE_REQUESTS =
123         new HashSet(Arrays.asList(new Class JavaDoc[] { ExpandModulesRequest.class, WrapperSendRequest.class }));
124
125     // processRequests & getCounter
126
private LoggedDataInputStream loggedDataInputStream;
127     private LoggedDataOutputStream loggedDataOutputStream;
128     private boolean warned;
129
130     /**
131      * Construct a Client using a given connection and file handler.
132      * You must initialize the connection and adminHandler first.
133      * <code>
134      * // establish connection to the given CVS pserver
135      * PServerConnection connection = new PServerConnection();
136      * connection.setUserName(userName);
137      * connection.setHostName(hostName);
138      * connection.setEncodedPassword(StandardScrambler.getInstance().scramble(password));
139      * connection.setRepository(repository);
140      * // test the connection
141      * try {
142      * connection.open();
143      * } catch (AuthenticationException e) {
144      * // do something
145      * }
146      *
147      * // create a CVS client
148      * Client cvsClient = new Client(connection,new StandardAdminHandler());
149      *
150      * // set the directory in which we work
151      * cvsClient.setLocalPath(localPath);
152      * </code>
153      * @param connection the connection to the cvs server
154      * @param adminHandler the admin handler to use
155      */

156     public Client(Connection connection, AdminHandler adminHandler) {
157         setConnection(connection);
158         setAdminHandler(adminHandler);
159         ignoreFileFilter = new DefaultIgnoreFileFilter();
160         dontUseGzipFileHandler = false;
161     }
162     
163     public void setErrorStream(PrintStream stderr) {
164         this.stderr = stderr;
165     }
166
167     /**
168      * Get the connection used for communicating with the server.
169      * Connection.
170      * @return the connection
171      */

172     public Connection getConnection() {
173         return connection;
174     }
175
176     /**
177      * Set the connection used for communicating with the server.
178      * @param c the connection to use for all communication with the server
179      */

180     public void setConnection(Connection connection) {
181         this.connection = connection;
182         initialRequestsSent = false;
183         setIsFirstCommand(true);
184     }
185
186     /**
187      * Get the admin handler uesd to read and write administrative information
188      * about files on the local machine.
189      * @return the admin handler
190      */

191     public AdminHandler getAdminHandler() {
192         return adminHandler;
193     }
194
195     /**
196      * Set the admin handler used to read and write administrative information
197      * about files on the local machine.
198      */

199     public void setAdminHandler(AdminHandler adminHandler) {
200         this.adminHandler = adminHandler;
201     }
202
203     /**
204      * Get the local path; that is, the path to the directory in which
205      * the currently executing command is referring.
206      */

207     public String JavaDoc getLocalPath() {
208         return localPath;
209     }
210
211     /**
212      * Set the local path, i.e. the path to the directory in which all
213      * commands are given (top level).
214      */

215     public void setLocalPath(String JavaDoc localPath) {
216         // remove trailing (back-) slash
217
localPath = localPath.replace('\\', '/');
218         while (localPath.endsWith("/")) { // NOI18N
219
localPath = localPath.substring(0, localPath.length() - 1);
220         }
221
222         this.localPath = localPath;
223     }
224
225     /**
226      * Returns true if no previous command was executed using thiz.
227      */

228     public boolean isFirstCommand() {
229         return isFirstCommand;
230     }
231
232     /**
233      * Set whether this is the first command. Normally you do not need to set
234      * this yourself - after execution the first command will have set this to
235      * false.
236      */

237     public void setIsFirstCommand(boolean isFirstCommand) {
238         this.isFirstCommand = isFirstCommand;
239     }
240
241     /**
242      * Return the uncompressed file handler.
243      */

244     public FileHandler getUncompressedFileHandler() {
245         return uncompFileHandler;
246     }
247
248     /**
249      * Set the uncompressed file handler.
250      */

251     public void setUncompressedFileHandler(FileHandler uncompFileHandler) {
252         this.uncompFileHandler = uncompFileHandler;
253     }
254
255     /**
256      * Return the Gzip stream handler.
257      */

258     public FileHandler getGzipFileHandler() {
259         return gzipFileHandler;
260     }
261
262     /**
263      * Set the handler for Gzip data.
264      */

265     public void setGzipFileHandler(FileHandler gzipFileHandler) {
266         this.gzipFileHandler = gzipFileHandler;
267     }
268
269     /**
270      * ReSet the filehandler for Gzip compressed data. Makes sure the
271      * requests for sending gzipped data are not sent..
272      */

273     public void dontUseGzipFileHandler() {
274         setGzipFileHandler(new DefaultFileHandler());
275         dontUseGzipFileHandler = true;
276     }
277
278     public boolean isAborted() {
279         return abort;
280     }
281
282     /**
283      * Ensures, that the connection is open.
284      *
285      * @throws AuthenticationException if it wasn't possible to connect
286      */

287     public void ensureConnection() throws AuthenticationException {
288         BugLog.getInstance().assertNotNull(getConnection());
289
290         if (getConnection().isOpen()) {
291             return;
292         }
293
294         // #69689 detect silent servers, possibly caused by proxy errors
295
final Throwable JavaDoc ex[] = new Throwable JavaDoc[1];
296         final boolean opened[] = new boolean[] {false};
297         Runnable JavaDoc probe = new Runnable JavaDoc() {
298             public void run() {
299                 try {
300                     getConnection().open();
301                     synchronized(opened) {
302                         opened[0] = true;
303                     }
304                 } catch (Throwable JavaDoc e) {
305                     synchronized(ex) {
306                         ex[0] = e;
307                     }
308                 }
309             }
310         };
311
312         Thread JavaDoc probeThread = new Thread JavaDoc(probe, "CVS Server Probe"); // NOI18N
313
probeThread.start();
314         try {
315
316             probeThread.join(60 * 1000); // 1 min
317

318             Throwable JavaDoc wasEx;
319             synchronized(ex) {
320                 wasEx = ex[0];
321             }
322             if (wasEx != null) {
323                 if (wasEx instanceof CommandAbortedException) {
324                     // User cancelled
325
abort();
326                     return;
327                 } else if (wasEx instanceof AuthenticationException) {
328                     throw (AuthenticationException) wasEx;
329                 } else if (wasEx instanceof RuntimeException JavaDoc) {
330                     throw (RuntimeException JavaDoc) wasEx;
331                 } else if (wasEx instanceof Error JavaDoc) {
332                     throw (Error JavaDoc) wasEx;
333                 } else {
334                     assert false : wasEx;
335                 }
336             }
337
338             boolean wasOpened;
339             synchronized(opened) {
340                 wasOpened = opened[0];
341             }
342             if (wasOpened == false) {
343                 probeThread.interrupt();
344                 throw new AuthenticationException("Timeout, no response from server.", "Timeout, no response from server.");
345             }
346
347         } catch (InterruptedException JavaDoc e) {
348
349             // User cancelled
350
probeThread.interrupt();
351             abort();
352         }
353     }
354
355     /**
356      * Process all the requests. The connection must have been opened and
357      * set first.
358      * @param requests the requets to process
359      */

360     public void processRequests(List requests)
361             throws IOException, UnconfiguredRequestException, ResponseException,
362             CommandAbortedException {
363
364         if (requests == null || requests.size() == 0) {
365             throw new IllegalArgumentException JavaDoc("[processRequests] requests " + // NOI18N
366
"was either null or empty."); // NOI18N
367
}
368
369         if (abort) {
370             throw new CommandAbortedException("Aborted during request processing", // NOI18N
371
CommandException.getLocalMessage("Client.commandAborted", null)); //NOI18N
372
}
373
374         loggedDataInputStream = null;
375         loggedDataOutputStream = null;
376
377         // send the initialisation requests if we are handling the first
378
// command
379
boolean filterRootRequest = true;
380         if (isFirstCommand()) {
381             setIsFirstCommand(false);
382             int pos = 0;
383             if (!initialRequestsSent) {
384                 pos = fillInitialRequests(requests);
385                 initialRequestsSent = true;
386                 filterRootRequest = false;
387             }
388             if (globalOptions != null) {
389                 // sends the global options that are to be sent to server (-q, -Q, -t, -n, l)
390
for (Iterator it = globalOptions.createRequestList().iterator(); it.hasNext();) {
391                     Request request = (Request)it.next();
392                     requests.add(pos++, request);
393                 }
394
395                 if (globalOptions.isUseGzip() && globalOptions.getCompressionLevel() != 0) {
396                     requests.add(pos++, new GzipFileContentsRequest(globalOptions.getCompressionLevel()));
397                 }
398             }
399         } else if (printConnectionReuseWarning) {
400             if (System.getProperty("javacvs.multiple_commands_warning") == null) { //NOI18N
401
System.err.println("WARNING TO DEVELOPERS:"); //NOI18N
402
System.err.println("Please be warned that attempting to reuse one open connection for more commands is not supported by cvs servers very well."); //NOI18N
403
System.err.println("You are advised to open a new Connection each time."); //NOI18N
404
System.err.println("If you still want to proceed, please do: System.setProperty(\"javacvs.multiple_commands_warning\", \"false\")"); //NOI18N
405
System.err.println("That will disable this message."); //NOI18N
406
}
407         }
408         
409         if (!ALLOWED_CONNECTION_REUSE_REQUESTS.contains(requests.get(requests.size() - 1).getClass())) {
410             printConnectionReuseWarning = true;
411         }
412
413         final boolean fireEnhancedEvents = getEventManager().isFireEnhancedEventSet();
414         int fileDetailRequestCount = 0;
415
416         if (fireEnhancedEvents) {
417             for (Iterator it = requests.iterator(); it.hasNext();) {
418                 Request request = (Request)it.next();
419
420                 FileDetails fileDetails = request.getFileForTransmission();
421                 if (fileDetails != null && fileDetails.getFile().exists()) {
422                     fileDetailRequestCount++;
423                 }
424             }
425             CVSEvent event = new EnhancedMessageEvent(this,
426                                                       EnhancedMessageEvent.REQUESTS_COUNT,
427                                                       new Integer JavaDoc(fileDetailRequestCount));
428             getEventManager().fireCVSEvent(event);
429         }
430
431         LoggedDataOutputStream dos = connection.getOutputStream();
432         loggedDataOutputStream = dos;
433
434         // this list stores stream modification requests, each to be called
435
// to modify the input stream the next time we need to process a
436
// response
437
List streamModifierRequests = new LinkedList();
438
439         // sending files does not seem to allow compression
440
transmitFileHandler = getUncompressedFileHandler();
441
442         for (Iterator it = requests.iterator(); it.hasNext();) {
443             if (abort) {
444                 throw new CommandAbortedException("Aborted during request processing", // NOI18N
445
CommandException.getLocalMessage("Client.commandAborted", null)); //NOI18N
446
}
447
448             final Request request = (Request)it.next();
449
450             if (request instanceof GzipFileContentsRequest) {
451                 if (dontUseGzipFileHandler) {
452                     stderr.println("Warning: The server is not supporting gzip-file-contents request, no compression is used.");
453                     continue;
454                 }
455             }
456             
457             // skip the root request if already sent
458
if (request instanceof RootRequest) {
459                 if (filterRootRequest) {
460                     continue;
461                 } else { // Even if we should not filter the RootRequest now, we must filter all successive RootRequests
462
filterRootRequest = true;
463                 }
464             }
465             // send request to server
466
String JavaDoc requestString = request.getRequestString();
467             dos.writeBytes(requestString);
468
469             // we must modify the outputstream now, but defer modification
470
// of the inputstream until we are about to read a response.
471
// This is because some modifiers (e.g. gzip) read the header
472
// on construction, and obviously no header is present when
473
// no response has been sent
474
request.modifyOutputStream(connection);
475             if (request.modifiesInputStream()) {
476                 streamModifierRequests.add(request);
477             }
478             dos = connection.getOutputStream();
479
480             FileDetails fileDetails = request.getFileForTransmission();
481             if (fileDetails != null) {
482                 final File file = fileDetails.getFile();
483                 // only transmit the file if it exists! When committing
484
// a remove request you cannot transmit the file
485
if (file.exists()) {
486                     Logger.logOutput(new String JavaDoc("<Sending file: " + // NOI18N
487
file.getAbsolutePath() + ">\n").getBytes("utf8")); // NOI18N
488

489                     if (fireEnhancedEvents) {
490                         CVSEvent event = new EnhancedMessageEvent(this,
491                                                                   EnhancedMessageEvent.FILE_SENDING,
492                                                                   file);
493                         getEventManager().fireCVSEvent(event);
494
495                         fileDetailRequestCount--;
496                     }
497
498                     if (fileDetails.isBinary()) {
499                         transmitFileHandler.transmitBinaryFile(file, dos);
500                     }
501                     else {
502                         transmitFileHandler.transmitTextFile(file, dos);
503                     }
504
505                     if (fireEnhancedEvents && fileDetailRequestCount == 0) {
506                         CVSEvent event = new EnhancedMessageEvent(this,
507                                                                   EnhancedMessageEvent.REQUESTS_SENT,
508                                                                   "Ok"); // NOI18N
509
getEventManager().fireCVSEvent(event);
510                     }
511                 }
512             }
513             if (request.isResponseExpected()) {
514                 dos.flush();
515
516                 // now perform the deferred modification of the input stream
517
Iterator modifiers = streamModifierRequests.iterator();
518                 while (modifiers.hasNext()) {
519                     System.err.println("Modifying the inputstream..."); // NOI18N
520
final Request smRequest = (Request)modifiers.next();
521                     System.err.println("Request is a: " + // NOI18N
522
smRequest.getClass().getName());
523                     smRequest.modifyInputStream(connection);
524                 }
525                 streamModifierRequests.clear();
526
527                 handleResponse();
528             }
529         }
530         dos.flush();
531
532         transmitFileHandler = null;
533     }
534     
535     private ResponseFactory getResponseFactory() {
536         if (responseFactory == null) {
537             responseFactory = new ResponseFactory();
538         }
539         return responseFactory;
540     }
541
542     /**
543      * Handle the response from a request.
544      * @throws ResponseException if there is a problem reading the response
545      */

546     private void handleResponse()
547             throws ResponseException, CommandAbortedException {
548         try {
549             LoggedDataInputStream dis = connection.getInputStream();
550             loggedDataInputStream = dis;
551
552             int ch = -1;
553             try {
554                 ch = dis.read();
555             } catch (InterruptedIOException ex) {
556                 abort();
557             }
558
559             while (!abort && ch != -1) {
560                 StringBuffer JavaDoc responseNameBuffer = new StringBuffer JavaDoc();
561                 // read in the response name
562
while (ch != -1 &&
563                         (char)ch != '\n' &&
564                         (char)ch != ' ') {
565                     responseNameBuffer.append((char)ch);
566                     try {
567                         ch = dis.read();
568                     } catch (InterruptedIOException ex) {
569                         abort();
570                         break;
571                     }
572                 }
573
574                 String JavaDoc responseString = responseNameBuffer.toString();
575                 Response response = getResponseFactory().createResponse(responseString);
576                 //Logger.logInput(new String("<" + responseString + " processing start>\n").getBytes()); // NOI18N
577
response.process(dis, this);
578                 boolean terminal = response.isTerminalResponse();
579
580                 // handle SpecialResponses
581
if (terminal && response instanceof ErrorMessageResponse) {
582                     ErrorMessageResponse errorResponce = (ErrorMessageResponse) response;
583                     String JavaDoc errMsg = errorResponce.getMessage();
584                     throw new CommandAbortedException(errMsg, errMsg);
585                 }
586                 //Logger.logInput(new String("<" + responseString + " processed " + terminal + ">\n").getBytes()); // NOI18N
587
if (terminal || abort) {
588                     break;
589                 }
590
591                 try {
592                     ch = dis.read();
593                 } catch (InterruptedIOException ex) {
594                     abort();
595                     break;
596                 }
597             }
598
599             if (abort) {
600                 String JavaDoc localMsg = CommandException.getLocalMessage("Client.commandAborted", null); //NOI18N
601
throw new CommandAbortedException("Aborted during request processing", localMsg); // NOI18N
602
}
603         }
604         catch (EOFException ex) {
605             throw new ResponseException(ex, ResponseException.getLocalMessage("CommandException.EndOfFile", null)); //NOI18N
606
}
607         catch (IOException ex) {
608             throw new ResponseException(ex);
609         }
610     }
611
612     /**
613      * Execute a command. Do not forget to initialize the CVS Root on globalOptions first!
614      * Example:
615      * <code>
616      * GlobalOptions options = new GlobalOptions();
617      * options.setCVSRoot(":pserver:"+userName+"@"+hostName+":"+cvsRoot);
618      * </code>
619      * @param command the command to execute
620      * @param options the global options to use for executing the command
621      * @throws CommandException if an error occurs when executing the command
622      * @throws CommandAbortedException if the command is aborted
623      */

624     public boolean executeCommand(Command command, GlobalOptions globalOptions)
625             throws CommandException, CommandAbortedException, AuthenticationException {
626         BugLog.getInstance().assertNotNull(command);
627         BugLog.getInstance().assertNotNull(globalOptions);
628
629         this.globalOptions = globalOptions;
630
631         getUncompressedFileHandler().setGlobalOptions(globalOptions);
632         getGzipFileHandler().setGlobalOptions(globalOptions);
633
634         try {
635             eventManager.addCVSListener(command);
636             command.execute(this, eventManager);
637         }
638         finally {
639             eventManager.removeCVSListener(command);
640         }
641         return !command.hasFailed();
642     }
643
644     /**
645      * Counts {@link #processRequests(java.util.List)}. send and received bytes.
646      *
647      * @thread it assumes that client is not run in paralel.
648      */

649     public long getCounter() {
650         long ret = 0;
651         if (loggedDataInputStream != null) {
652             ret += loggedDataInputStream.getCounter();
653         }
654         if (loggedDataOutputStream != null) {
655             ret += loggedDataOutputStream.getCounter();
656         }
657         return ret;
658     }
659
660     /**
661      * Convert a <i>pathname</i> in the CVS sense (see 5.10 in the protocol
662      * document) into a local absolute pathname for the file.
663      * @param localDirectory the name of the local directory, relative to the
664      * directory in which the command was given
665      * @param repository the full repository name for the file
666      */

667     public String JavaDoc convertPathname(String JavaDoc localDirectory, String JavaDoc repository) {
668         int lastIndexOfSlash = repository.lastIndexOf('/');
669         String JavaDoc filename = repository.substring(lastIndexOfSlash + 1);
670
671         if (localDirectory.startsWith("./")) { // NOI18N
672
// remove the dot
673
localDirectory = localDirectory.substring(1);
674         }
675         if (localDirectory.startsWith("/")) { // NOI18N
676
// remove the leading slash
677
localDirectory = localDirectory.substring(1);
678         }
679         // note that the localDirectory ends in a slash
680
return getLocalPath() + '/' + localDirectory + filename;
681     }
682
683     /**
684      * Get the repository path from the connection.
685      *
686      * @return the repository path, e.g. /home/bob/cvs. Delegated to the
687      * Connection in this case
688      * @see Connection#getRepository()
689      */

690     public String JavaDoc getRepository() {
691         return connection.getRepository();
692     }
693
694     /**
695      * Create or update the administration files for a particular file.
696      * This will create the CVS directory if necessary, and the
697      * Root and Repository files if necessary. It will also update
698      * the Entries file with the new entry
699      * @param localDirectory the local directory, relative to the directory
700      * in which the command was given, where the file in question lives
701      * @param repositoryPath the path of the file in the repository, in
702      * absolute form.
703      * @param entry the entry object for that file
704      */

705     public void updateAdminData(String JavaDoc localDirectory, String JavaDoc repositoryPath,
706                                 Entry entry)
707             throws IOException {
708         final String JavaDoc absolutePath = localPath + '/' + localDirectory;
709         if (repositoryPath.startsWith(getRepository())) {
710             repositoryPath = repositoryPath.substring(getRepository().length() + 1);
711         } else {
712             if (warned == false) {
713                 String JavaDoc warning = "#65188 warning C/S protocol error (section 5.10). It's regurarly observed with cvs 1.12.xx servers.\n"; // NOI18N
714
warning += " unexpected pathname=" + repositoryPath + " missing root prefix=" + getRepository() + "\n"; // NOI18N
715
warning += " relaxing, but who knows all consequences...."; // NOI18N
716
System.err.println(warning);
717                 warned = true;
718             }
719         }
720
721         adminHandler.updateAdminData(absolutePath, repositoryPath, entry,
722                                      globalOptions);
723     }
724
725     /**
726      * Set the modified date of the next file to be written. The next call
727      * to write<Type>File will use this date.
728      * @param modifiedDate the date the file should be marked as modified
729      */

730     public void setNextFileDate(Date modifiedDate) {
731         this.modifiedDate = modifiedDate;
732     }
733
734     /**
735      * Get the modified date for the next file.
736      * @return the date and then null the instance variable.
737      */

738     public Date getNextFileDate() {
739         //
740
// We null the instance variable so that future calls will not
741
// retrieve a date specified for a previous file
742
//
743
Date copy = modifiedDate;
744         modifiedDate = null;
745         return copy;
746     }
747
748     /**
749      * Get the Entry for the specified file, if one exists.
750      * @param f the file
751      * @throws IOException if the Entries file cannot be read
752      */

753     public Entry getEntry(File f)
754             throws IOException {
755         return adminHandler.getEntry(f);
756     }
757
758     /**
759      * Get the entries for a specified directory.
760      * @param directory the directory for which to get the entries
761      * @return an iterator of Entry objects
762      */

763     public Iterator getEntries(File directory)
764             throws IOException {
765         return adminHandler.getEntries(directory);
766     }
767
768     public boolean exists(File file) {
769         return adminHandler.exists(file);
770     }
771
772     /**
773      * Get the repository path for a given directory, for example in
774      * the directory /home/project/foo/bar, the repository directory
775      * might be /usr/cvs/foo/bar. The repository directory is commonly
776      * stored in the file <pre>Repository</pre> in the CVS directory on
777      * the client (this is the case in the standard CVS command-line tool).
778      *
779      * If no <pre>CVS/Repository</pre> file was found, the specified directory,
780      * the localpath are used to "guess" the repository path.
781      *
782      * @param directory the directory
783      */

784     public String JavaDoc getRepositoryForDirectory(String JavaDoc directory)
785             throws IOException {
786         try {
787             String JavaDoc repository = adminHandler.getRepositoryForDirectory(
788                     directory, getRepository());
789             return repository;
790         }
791         catch (IOException ex) {
792             // an IOException is thrown, if the adminHandler can't detect the repository
793
// by reading the CVS/Repository file, e.g. when checking out into a new directory
794
try {
795                 directory = new File(directory).getCanonicalPath();
796             } catch (IOException ioex) {}
797             directory = directory.replace('\\', '/');
798             while (directory.endsWith("/")) { // NOI18N
799
directory = directory.substring(0, directory.length() - 1);
800             }
801             
802             // must also canonicalize 'localPath' to be in sync with 'directory'
803
String JavaDoc localPathCanonical = getLocalPath();
804             try {
805                  localPathCanonical = new File(getLocalPath()).getCanonicalPath();
806             } catch (IOException ioex) {}
807             localPathCanonical = localPathCanonical.replace('\\', '/');
808             while (localPathCanonical.endsWith("/")) { // NOI18N
809
localPathCanonical = localPathCanonical.substring(0, localPathCanonical.length() - 1);
810             }
811             int localPathLength = localPathCanonical.length();
812             
813             String JavaDoc repository;
814             if (directory.length() >= localPathLength) {
815                 repository = getRepository() + directory.substring(localPathLength);
816             } else { // Asking for some folder upon the local working path
817
repository = getRepository();
818             }
819             return repository;
820         }
821     }
822     
823     public String JavaDoc getRepositoryForDirectory(File directory) throws IOException {
824         return adminHandler.getRepositoryForDirectory(directory.getAbsolutePath(), getRepository());
825     }
826
827     /**
828      * Set the Entry for the specified file.
829      * @param file the file
830      * @param entry the new entry
831      * @throws IOException if an error occurs writing the details
832      */

833     public void setEntry(File file, Entry entry)
834             throws IOException {
835         adminHandler.setEntry(file, entry);
836     }
837
838     /**
839      * Remove the Entry for the specified file.
840      * @param file the file whose entry is to be removed
841      * @throws IOException if an error occurs writing the Entries file
842      */

843     public void removeEntry(File file)
844             throws IOException {
845         adminHandler.removeEntry(file);
846     }
847
848     /**
849      * Remove the specified file from the local disk.
850      * If the file does not exist, the operation does nothing.
851
852      * @param pathname the full path to the file to remove
853      * @throws IOException if an IO error occurs while removing the file
854      */

855     public void removeLocalFile(String JavaDoc pathname)
856             throws IOException {
857         transmitFileHandler.removeLocalFile(pathname);
858     }
859
860     /**
861      * Removes the specified file determined by pathName and repositoryName.
862      * In this implementation the filename from repositoryPath is added
863      * to the localpath (which doesn't have the filename in it) and that file is deleted.
864      */

865     public void removeLocalFile(String JavaDoc pathName, String JavaDoc repositoryName)
866             throws IOException {
867         int ind = repositoryName.lastIndexOf('/');
868         if (ind <= 0) {
869             return;
870         }
871
872         String JavaDoc fileName = repositoryName.substring(ind + 1);
873         String JavaDoc localFile = pathName + fileName;
874         File fileToDelete = new File(getLocalPath(), localFile);
875         removeLocalFile(fileToDelete.getAbsolutePath());
876         removeEntry(fileToDelete);
877     }
878
879     /**
880      * Rename the local file.
881      * @param pathname the full path to the file to rename
882      * @param newName the new name of the file (not the full path)
883      * @throws IOException if an IO error occurs while renaming the file
884      */

885     public void renameLocalFile(String JavaDoc pathname, String JavaDoc newName)
886             throws IOException {
887         transmitFileHandler.renameLocalFile(pathname, newName);
888     }
889
890     /**
891      * Get the CVS event manager. This is generally called by response handlers
892      * that want to fire events.
893      * @return the eventManager
894      */

895     public EventManager getEventManager() {
896         return eventManager;
897     }
898     
899     /**
900      * Get the global options that are set to this client.
901      * Individual commands can get the global options via this method.
902      */

903     public GlobalOptions getGlobalOptions() {
904         return globalOptions;
905     }
906
907     /**
908      * Call this method to abort the current command. The command will be
909      * aborted at the next suitable time
910      */

911     public synchronized void abort() {
912         abort = true;
913     }
914
915     /**
916      * Get all the files contained within a given
917      * directory that are <b>known to CVS</b>.
918      * @param directory the directory to look in
919      * @return a set of all files.
920      */

921     public Set getAllFiles(File directory) throws IOException {
922         return adminHandler.getAllFiles(directory);
923     }
924
925     public void setIgnoreFileFilter(IgnoreFileFilter ignoreFileFilter) {
926         this.ignoreFileFilter = ignoreFileFilter;
927     }
928
929     public IgnoreFileFilter getIgnoreFileFilter() {
930         return ignoreFileFilter;
931     }
932
933     public boolean shouldBeIgnored(File directory, String JavaDoc noneCvsFile) {
934         if (ignoreFileFilter != null) {
935             return ignoreFileFilter.shouldBeIgnored(directory, noneCvsFile);
936         }
937         return false;
938     }
939
940     /**
941      * Checks for presence of CVS/Tag file and returns it's value.
942      * @return the value of CVS/Tag file for the specified directory
943      * null if file doesn't exist
944      */

945     public String JavaDoc getStickyTagForDirectory(File directory) {
946         return adminHandler.getStickyTagForDirectory(directory);
947     }
948
949     /**
950      * This method is called when a response for the ValidRequests request
951      * is received.
952      * @param requests A List of requests that is valid for this CVS server
953      * separated by spaces.
954      */

955     public void setValidRequests(String JavaDoc requests)
956     {
957         // We need to tokenize the requests and add it to our map
958

959         StringTokenizer tokenizer = new StringTokenizer(requests);
960         String JavaDoc token;
961         while (tokenizer.hasMoreTokens()) {
962             token = tokenizer.nextToken();
963             // we just add an object with the corresponding request
964
// as the key.
965
validRequests.put(token, this);
966         }
967         
968     }
969     
970     private int fillInitialRequests(List requests) {
971         int pos = 0;
972         requests.add(pos++, new RootRequest(getRepository()));
973         requests.add(pos++, new UseUnchangedRequest());
974         requests.add(pos++, new ValidRequestsRequest());
975         requests.add(pos++, new ValidResponsesRequest());
976         return pos;
977     }
978     
979     /** This method is called by WrapperSendResponse for each wrapper setting sent
980      * back by the CVS server
981      * @param pattern A StringPattern indicating the pattern for which the
982      * wrapper applies
983      * @param option A KeywordSubstituionOption corresponding to the setting
984      */

985     public void addWrapper(StringPattern pattern, KeywordSubstitutionOptions option) {
986         if (wrappersMap == null) {
987             throw new IllegalArgumentException JavaDoc("This method should be called "+
988                                                 "by WrapperSendResponse only.");
989         }
990         wrappersMap.put(pattern, option);
991     }
992     
993     /** Returns the wrappers map associated with the CVS server
994      * The map is valid only after the connection is established
995      */

996     public Map getWrappersMap() throws CommandException {
997         if (wrappersMap == null) {
998             wrappersMap = new HashMap();
999             ArrayList requests = new ArrayList();
1000            requests.add(new WrapperSendRequest());
1001            boolean isFirst = isFirstCommand();
1002            try {
1003                processRequests(requests);
1004            } catch (Exception JavaDoc ex) {
1005                throw new CommandException(ex, "An error during obtaining server wrappers.");
1006            } finally {
1007                // Do not alter isFirstCommand property
1008
setIsFirstCommand(isFirst);
1009            }
1010            wrappersMap = Collections.unmodifiableMap(wrappersMap);
1011        }
1012        return wrappersMap;
1013    }
1014
1015    /**
1016     * Factory for creating clients.
1017     */

1018    public static interface Factory {
1019
1020        /**
1021         * Creates new client instance. Never null.
1022         * It uses fresh connection.
1023         */

1024        Client createClient();
1025    }
1026}
1027
1028
Popular Tags