1 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 43 public class Client implements ClientServices, ResponseServices { 44 47 private Connection connection; 48 49 52 private FileHandler transmitFileHandler; 53 54 private FileHandler gzipFileHandler = new GzippedFileHandler(); 55 private FileHandler uncompFileHandler = new DefaultFileHandler(); 56 57 private boolean dontUseGzipFileHandler; 58 59 62 private Date modifiedDate; 63 64 67 private AdminHandler adminHandler; 68 69 73 private String localPath; 74 75 79 private boolean isFirstCommand = true; 80 81 84 private final EventManager eventManager = new EventManager(this); 85 86 89 private GlobalOptions globalOptions; 90 91 private PrintStream stderr = System.err; 92 93 96 private boolean abort; 97 98 private ResponseFactory responseFactory; 99 100 private IgnoreFileFilter ignoreFileFilter; 101 102 106 private Map validRequests = new HashMap(); 107 108 111 private Map wrappersMap = null; 112 113 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 [] { ExpandModulesRequest.class, WrapperSendRequest.class })); 124 125 private LoggedDataInputStream loggedDataInputStream; 127 private LoggedDataOutputStream loggedDataOutputStream; 128 private boolean warned; 129 130 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 172 public Connection getConnection() { 173 return connection; 174 } 175 176 180 public void setConnection(Connection connection) { 181 this.connection = connection; 182 initialRequestsSent = false; 183 setIsFirstCommand(true); 184 } 185 186 191 public AdminHandler getAdminHandler() { 192 return adminHandler; 193 } 194 195 199 public void setAdminHandler(AdminHandler adminHandler) { 200 this.adminHandler = adminHandler; 201 } 202 203 207 public String getLocalPath() { 208 return localPath; 209 } 210 211 215 public void setLocalPath(String localPath) { 216 localPath = localPath.replace('\\', '/'); 218 while (localPath.endsWith("/")) { localPath = localPath.substring(0, localPath.length() - 1); 220 } 221 222 this.localPath = localPath; 223 } 224 225 228 public boolean isFirstCommand() { 229 return isFirstCommand; 230 } 231 232 237 public void setIsFirstCommand(boolean isFirstCommand) { 238 this.isFirstCommand = isFirstCommand; 239 } 240 241 244 public FileHandler getUncompressedFileHandler() { 245 return uncompFileHandler; 246 } 247 248 251 public void setUncompressedFileHandler(FileHandler uncompFileHandler) { 252 this.uncompFileHandler = uncompFileHandler; 253 } 254 255 258 public FileHandler getGzipFileHandler() { 259 return gzipFileHandler; 260 } 261 262 265 public void setGzipFileHandler(FileHandler gzipFileHandler) { 266 this.gzipFileHandler = gzipFileHandler; 267 } 268 269 273 public void dontUseGzipFileHandler() { 274 setGzipFileHandler(new DefaultFileHandler()); 275 dontUseGzipFileHandler = true; 276 } 277 278 public boolean isAborted() { 279 return abort; 280 } 281 282 287 public void ensureConnection() throws AuthenticationException { 288 BugLog.getInstance().assertNotNull(getConnection()); 289 290 if (getConnection().isOpen()) { 291 return; 292 } 293 294 final Throwable ex[] = new Throwable [1]; 296 final boolean opened[] = new boolean[] {false}; 297 Runnable probe = new Runnable () { 298 public void run() { 299 try { 300 getConnection().open(); 301 synchronized(opened) { 302 opened[0] = true; 303 } 304 } catch (Throwable e) { 305 synchronized(ex) { 306 ex[0] = e; 307 } 308 } 309 } 310 }; 311 312 Thread probeThread = new Thread (probe, "CVS Server Probe"); probeThread.start(); 314 try { 315 316 probeThread.join(60 * 1000); 318 Throwable wasEx; 319 synchronized(ex) { 320 wasEx = ex[0]; 321 } 322 if (wasEx != null) { 323 if (wasEx instanceof CommandAbortedException) { 324 abort(); 326 return; 327 } else if (wasEx instanceof AuthenticationException) { 328 throw (AuthenticationException) wasEx; 329 } else if (wasEx instanceof RuntimeException ) { 330 throw (RuntimeException ) wasEx; 331 } else if (wasEx instanceof Error ) { 332 throw (Error ) 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 e) { 348 349 probeThread.interrupt(); 351 abort(); 352 } 353 } 354 355 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 ("[processRequests] requests " + "was either null or empty."); } 368 369 if (abort) { 370 throw new CommandAbortedException("Aborted during request processing", CommandException.getLocalMessage("Client.commandAborted", null)); } 373 374 loggedDataInputStream = null; 375 loggedDataOutputStream = null; 376 377 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 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) { System.err.println("WARNING TO DEVELOPERS:"); System.err.println("Please be warned that attempting to reuse one open connection for more commands is not supported by cvs servers very well."); System.err.println("You are advised to open a new Connection each time."); System.err.println("If you still want to proceed, please do: System.setProperty(\"javacvs.multiple_commands_warning\", \"false\")"); System.err.println("That will disable this message."); } 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 (fileDetailRequestCount)); 428 getEventManager().fireCVSEvent(event); 429 } 430 431 LoggedDataOutputStream dos = connection.getOutputStream(); 432 loggedDataOutputStream = dos; 433 434 List streamModifierRequests = new LinkedList(); 438 439 transmitFileHandler = getUncompressedFileHandler(); 441 442 for (Iterator it = requests.iterator(); it.hasNext();) { 443 if (abort) { 444 throw new CommandAbortedException("Aborted during request processing", CommandException.getLocalMessage("Client.commandAborted", null)); } 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 if (request instanceof RootRequest) { 459 if (filterRootRequest) { 460 continue; 461 } else { filterRootRequest = true; 463 } 464 } 465 String requestString = request.getRequestString(); 467 dos.writeBytes(requestString); 468 469 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 if (file.exists()) { 486 Logger.logOutput(new String ("<Sending file: " + file.getAbsolutePath() + ">\n").getBytes("utf8")); 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"); getEventManager().fireCVSEvent(event); 510 } 511 } 512 } 513 if (request.isResponseExpected()) { 514 dos.flush(); 515 516 Iterator modifiers = streamModifierRequests.iterator(); 518 while (modifiers.hasNext()) { 519 System.err.println("Modifying the inputstream..."); final Request smRequest = (Request)modifiers.next(); 521 System.err.println("Request is a: " + 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 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 responseNameBuffer = new StringBuffer (); 561 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 responseString = responseNameBuffer.toString(); 575 Response response = getResponseFactory().createResponse(responseString); 576 response.process(dis, this); 578 boolean terminal = response.isTerminalResponse(); 579 580 if (terminal && response instanceof ErrorMessageResponse) { 582 ErrorMessageResponse errorResponce = (ErrorMessageResponse) response; 583 String errMsg = errorResponce.getMessage(); 584 throw new CommandAbortedException(errMsg, errMsg); 585 } 586 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 localMsg = CommandException.getLocalMessage("Client.commandAborted", null); throw new CommandAbortedException("Aborted during request processing", localMsg); } 603 } 604 catch (EOFException ex) { 605 throw new ResponseException(ex, ResponseException.getLocalMessage("CommandException.EndOfFile", null)); } 607 catch (IOException ex) { 608 throw new ResponseException(ex); 609 } 610 } 611 612 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 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 667 public String convertPathname(String localDirectory, String repository) { 668 int lastIndexOfSlash = repository.lastIndexOf('/'); 669 String filename = repository.substring(lastIndexOfSlash + 1); 670 671 if (localDirectory.startsWith("./")) { localDirectory = localDirectory.substring(1); 674 } 675 if (localDirectory.startsWith("/")) { localDirectory = localDirectory.substring(1); 678 } 679 return getLocalPath() + '/' + localDirectory + filename; 681 } 682 683 690 public String getRepository() { 691 return connection.getRepository(); 692 } 693 694 705 public void updateAdminData(String localDirectory, String repositoryPath, 706 Entry entry) 707 throws IOException { 708 final String absolutePath = localPath + '/' + localDirectory; 709 if (repositoryPath.startsWith(getRepository())) { 710 repositoryPath = repositoryPath.substring(getRepository().length() + 1); 711 } else { 712 if (warned == false) { 713 String warning = "#65188 warning C/S protocol error (section 5.10). It's regurarly observed with cvs 1.12.xx servers.\n"; warning += " unexpected pathname=" + repositoryPath + " missing root prefix=" + getRepository() + "\n"; warning += " relaxing, but who knows all consequences...."; System.err.println(warning); 717 warned = true; 718 } 719 } 720 721 adminHandler.updateAdminData(absolutePath, repositoryPath, entry, 722 globalOptions); 723 } 724 725 730 public void setNextFileDate(Date modifiedDate) { 731 this.modifiedDate = modifiedDate; 732 } 733 734 738 public Date getNextFileDate() { 739 Date copy = modifiedDate; 744 modifiedDate = null; 745 return copy; 746 } 747 748 753 public Entry getEntry(File f) 754 throws IOException { 755 return adminHandler.getEntry(f); 756 } 757 758 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 784 public String getRepositoryForDirectory(String directory) 785 throws IOException { 786 try { 787 String repository = adminHandler.getRepositoryForDirectory( 788 directory, getRepository()); 789 return repository; 790 } 791 catch (IOException ex) { 792 try { 795 directory = new File(directory).getCanonicalPath(); 796 } catch (IOException ioex) {} 797 directory = directory.replace('\\', '/'); 798 while (directory.endsWith("/")) { directory = directory.substring(0, directory.length() - 1); 800 } 801 802 String localPathCanonical = getLocalPath(); 804 try { 805 localPathCanonical = new File(getLocalPath()).getCanonicalPath(); 806 } catch (IOException ioex) {} 807 localPathCanonical = localPathCanonical.replace('\\', '/'); 808 while (localPathCanonical.endsWith("/")) { localPathCanonical = localPathCanonical.substring(0, localPathCanonical.length() - 1); 810 } 811 int localPathLength = localPathCanonical.length(); 812 813 String repository; 814 if (directory.length() >= localPathLength) { 815 repository = getRepository() + directory.substring(localPathLength); 816 } else { repository = getRepository(); 818 } 819 return repository; 820 } 821 } 822 823 public String getRepositoryForDirectory(File directory) throws IOException { 824 return adminHandler.getRepositoryForDirectory(directory.getAbsolutePath(), getRepository()); 825 } 826 827 833 public void setEntry(File file, Entry entry) 834 throws IOException { 835 adminHandler.setEntry(file, entry); 836 } 837 838 843 public void removeEntry(File file) 844 throws IOException { 845 adminHandler.removeEntry(file); 846 } 847 848 855 public void removeLocalFile(String pathname) 856 throws IOException { 857 transmitFileHandler.removeLocalFile(pathname); 858 } 859 860 865 public void removeLocalFile(String pathName, String repositoryName) 866 throws IOException { 867 int ind = repositoryName.lastIndexOf('/'); 868 if (ind <= 0) { 869 return; 870 } 871 872 String fileName = repositoryName.substring(ind + 1); 873 String localFile = pathName + fileName; 874 File fileToDelete = new File(getLocalPath(), localFile); 875 removeLocalFile(fileToDelete.getAbsolutePath()); 876 removeEntry(fileToDelete); 877 } 878 879 885 public void renameLocalFile(String pathname, String newName) 886 throws IOException { 887 transmitFileHandler.renameLocalFile(pathname, newName); 888 } 889 890 895 public EventManager getEventManager() { 896 return eventManager; 897 } 898 899 903 public GlobalOptions getGlobalOptions() { 904 return globalOptions; 905 } 906 907 911 public synchronized void abort() { 912 abort = true; 913 } 914 915 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 noneCvsFile) { 934 if (ignoreFileFilter != null) { 935 return ignoreFileFilter.shouldBeIgnored(directory, noneCvsFile); 936 } 937 return false; 938 } 939 940 945 public String getStickyTagForDirectory(File directory) { 946 return adminHandler.getStickyTagForDirectory(directory); 947 } 948 949 955 public void setValidRequests(String requests) 956 { 957 959 StringTokenizer tokenizer = new StringTokenizer(requests); 960 String token; 961 while (tokenizer.hasMoreTokens()) { 962 token = tokenizer.nextToken(); 963 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 985 public void addWrapper(StringPattern pattern, KeywordSubstitutionOptions option) { 986 if (wrappersMap == null) { 987 throw new IllegalArgumentException ("This method should be called "+ 988 "by WrapperSendResponse only."); 989 } 990 wrappersMap.put(pattern, option); 991 } 992 993 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 ex) { 1005 throw new CommandException(ex, "An error during obtaining server wrappers."); 1006 } finally { 1007 setIsFirstCommand(isFirst); 1009 } 1010 wrappersMap = Collections.unmodifiableMap(wrappersMap); 1011 } 1012 return wrappersMap; 1013 } 1014 1015 1018 public static interface Factory { 1019 1020 1024 Client createClient(); 1025 } 1026} 1027 1028 | Popular Tags |