KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > cvsclient > command > add > AddCommand


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.command.add;
23
24 import java.io.*;
25 import java.util.*;
26
27 import org.netbeans.lib.cvsclient.*;
28 import org.netbeans.lib.cvsclient.util.SimpleStringPattern;
29 import org.netbeans.lib.cvsclient.admin.*;
30 import org.netbeans.lib.cvsclient.command.*;
31 import org.netbeans.lib.cvsclient.connection.*;
32 import org.netbeans.lib.cvsclient.event.*;
33 import org.netbeans.lib.cvsclient.request.*;
34
35 /**
36  * Adds a file or directory.
37  * @author Robert Greig
38  */

39 public class AddCommand extends BuildableCommand {
40     /**
41      * Constants that identify a message that creates a directory in
42      * repository.
43      */

44     private static final String JavaDoc DIR_ADDED = " added to the repository"; //NOI18N
45
private static final String JavaDoc DIRECTORY = "Directory "; //NOI18N
46

47     /**
48      * The requests that are sent and processed.
49      */

50     private List requests;
51
52     /**
53      * The argument requests that are collected and sent in the end just before the
54      * add request.
55      */

56     private final List argumentRequests = new LinkedList();
57
58     /**
59      * The list of new directories.
60      */

61     /*
62         private HashMap newDirList;
63     */

64     private final List newDirList = new LinkedList();
65
66     /**
67      * The client services that are provided to this command.
68      */

69     private ClientServices clientServices;
70
71     /**
72      * The files and/or directories to operate on.
73      */

74     private File[] files;
75
76     /**
77      * Holds value of property message, (add's switch -m).
78      */

79     private String JavaDoc message;
80
81     /**
82      * Holds value of property keywordSubst.
83      */

84     private KeywordSubstitutionOptions keywordSubst;
85
86
87
88     /**
89      *This is the merged wrapper map that contains has both server side
90      *and client side wrapper settings merged except for the .cvswrappers
91      *in the individual directories
92      */

93     private Map wrapperMap;
94
95     /**
96      * Holds the cvswrappers map for each directory, keyed
97      * by directory name
98      */

99     private HashMap dir2WrapperMap = new HashMap(16);
100
101     private static final Map EMPTYWRAPPER = new HashMap(1);
102     /**
103      * Constructor.
104      */

105     public AddCommand() {
106         resetCVSCommand();
107     }
108
109     /**
110      * Set the files and/or directories on which to execute the command.
111      * Sorts the paameter so that directories are first and files follow.
112      * That way a directory and it's content will be passed correctly.
113      * The user of the library has to specify all the files+dirs being added though.
114      * This is just a sanity check, so that no unnessesary errors occur.
115      */

116     public void setFiles(File[] files) {
117         this.files = files;
118         if (files == null) {
119             return;
120         }
121
122         // sort array: directories first, files follow
123
this.files = new File[files.length];
124         int dirCount = 0;
125         int fileCount = 0;
126         int totalCount = files.length;
127         for (int index = 0; index < totalCount; index++) {
128             File currentFile = files[index];
129             if (currentFile.isDirectory()) {
130                 this.files[dirCount] = currentFile;
131                 dirCount++;
132             }
133             else {
134                 this.files[totalCount - (1 + fileCount)] = currentFile;
135                 fileCount++;
136             }
137         }
138     }
139
140     /**
141      * Get the files and/or directories specified for this command to operate
142      * on.
143      * @return the array of Files
144      */

145     public File[] getFiles() {
146         return files;
147     }
148
149     /**
150      * @param ending - the ending part of the file's pathname.. path separator is cvs's default '/'
151      */

152     public File getFileEndingWith(String JavaDoc ending) {
153         String JavaDoc locEnding = ending.replace('\\', '/');
154         String JavaDoc localDir = getLocalDirectory().replace('\\','/');
155         int index = 0;
156         for (index = 0; index < files.length; index++) {
157             String JavaDoc path = files[index].getAbsolutePath();
158             String JavaDoc parentPath = files[index].getParentFile().getAbsolutePath().replace('\\', '/');
159             path = path.replace('\\', '/');
160             if ((path.endsWith(locEnding) && locEnding.indexOf('/') >= 0) ||
161                    (files[index].getName().equals(locEnding) && parentPath.equals(localDir))) {
162                 return files[index];
163             }
164         }
165         return null;
166     }
167
168     /**
169      * Getter for property message.
170      * @return Value of property message.
171      */

172     public String JavaDoc getMessage() {
173         return message;
174     }
175
176     /**
177      * Setter for property message.
178      * @param message New value of property message.
179      */

180     public void setMessage(String JavaDoc message) {
181         this.message = message;
182     }
183
184     /**
185      * Getter for property keywordSubst.
186      * @return Value of property keywordSubst.
187      */

188     public KeywordSubstitutionOptions getKeywordSubst() {
189         return keywordSubst;
190     }
191
192     /**
193      * Setter for property keywordSubst.
194      * @param keywordSubst New value of property keywordSubst.
195      */

196     public void setKeywordSubst(KeywordSubstitutionOptions keywordSubst) {
197         this.keywordSubst = keywordSubst;
198     }
199
200     /**
201      * Add requests for a particular file or directory to be added.
202      */

203     protected void addRequests(File file)
204             throws IOException, CommandException {
205         if (file.isDirectory()) {
206             addRequestsForDirectory(file, false);
207         }
208         else {
209             addRequestsForFile(file);
210         }
211     }
212
213     /**
214      * Add requests for a particular directory.
215      * @param directory the directory to add
216      * @param adding - for the directory to be added, set to true.
217      * used internally to recurse Directory requests.
218      * @throws IOException if an error occurs
219      */

220     private void addRequestsForDirectory(File directory, boolean recursion)
221             throws IOException {
222
223         File parentDirectory = directory.getParentFile();
224         String JavaDoc dir = recursion
225                 ? getRelativeToLocalPathInUnixStyle(directory)
226                 : getRelativeToLocalPathInUnixStyle(parentDirectory);
227
228         String JavaDoc partPath;
229         if (dir.equals(".")) { //NOI18N
230
partPath = directory.getName();
231         }
232         else {
233             // trim the leading slash from the pathname we end up with
234
// (e.g. we end up with something like \banana\foo
235
// and this gives us banana\foo). Also replace backslashes with
236
// forward slashes. The standard CVS server doesn't like
237
// backslashes very much.
238
partPath = dir + "/" + directory.getName(); //NOI18N
239
// recursively scroll back to the localPath..
240
addRequestsForDirectory(parentDirectory, true);
241         }
242
243         if (recursion) {
244             partPath = dir;
245         }
246
247         // Note that the repository file for the directory being added has not
248
// been created yet, so we are forced to read the repository for
249
// the parent directory and build the appropriate entry by tagging
250
// on the directory name (called partPath here)
251
String JavaDoc repository;
252         String JavaDoc tag;
253
254         if (recursion) {
255             repository = clientServices.getRepositoryForDirectory(
256                     directory.getAbsolutePath());
257             tag = clientServices.getStickyTagForDirectory(directory);
258         }
259         else {
260             repository = clientServices.getRepositoryForDirectory(
261                     parentDirectory.getAbsolutePath());
262             if (repository.endsWith(".")) {
263                 repository = repository.substring(0, repository.length() - 1) + directory.getName();
264             } else {
265                 repository = repository + "/" + directory.getName(); //NOI18N
266
}
267             tag = clientServices.getStickyTagForDirectory(parentDirectory);
268         }
269
270         requests.add(new DirectoryRequest(partPath, repository));
271         if (tag != null) {
272             requests.add(new StickyRequest(tag));
273         }
274
275         if (!recursion) {
276             argumentRequests.add(new ArgumentRequest(partPath));
277 /*
278             newDirList.put(partPath, repository);
279 */

280             newDirList.add(new Paths(partPath, repository));
281         }
282         // MK argument after Dir request.. also with the rel path from the current working dir
283
}
284
285     /**
286      * Add requests for a particular file.
287      */

288     protected void addRequestsForFile(File file)
289             throws IOException, CommandException {
290         File directory = file.getParentFile();
291         String JavaDoc dir = getRelativeToLocalPathInUnixStyle(directory);
292
293         String JavaDoc repository = clientServices.getRepositoryForDirectory(
294                 directory.getAbsolutePath());
295         requests.add(new DirectoryRequest(dir, repository));
296         String JavaDoc tag = clientServices.getStickyTagForDirectory(directory);
297         if (tag != null) {
298             requests.add(new StickyRequest(tag));
299         }
300
301         Entry entry = clientServices.getEntry(file);
302
303         if (entry != null) {
304             requests.add(new EntryRequest(entry));
305         }
306         else {
307
308             Map directoryLevelWrapper = (Map) dir2WrapperMap.get(dir);
309             if (directoryLevelWrapper == null) {
310
311                 // we have not parsed the cvs wrappers for this directory
312
// read the wrappers for this directory
313

314                 File wrapperFile = new File(directory, ".cvswrappers"); // NOI18N
315
if (wrapperFile.exists()) {
316                     directoryLevelWrapper = new HashMap(5);
317                     WrapperUtils.readWrappersFromFile(wrapperFile, directoryLevelWrapper);
318                 }
319                 else {
320                     directoryLevelWrapper = EMPTYWRAPPER;
321                 }
322
323                 // store the wrapper map indexed by directory name
324
dir2WrapperMap.put(dir, directoryLevelWrapper);
325             }
326
327             boolean isBinary = isBinary(clientServices, file.getName(), directoryLevelWrapper);
328
329             if (isBinary) {
330                 requests.add(new KoptRequest("-kb")); // NOI18N
331
}
332             requests.add(new IsModifiedRequest(file));
333         }
334
335         if (dir.equals(".")) { //NOI18N
336
argumentRequests.add(new ArgumentRequest(file.getName()));
337         }
338         else {
339             argumentRequests.add(new ArgumentRequest(dir + "/" + file.getName())); //NOI18N
340
}
341     }
342
343
344     /**
345      * Returns true, if the file for the specified filename should be treated as
346      * a binary file.
347      *
348      * The information comes from the wrapper map and the set keywordsubstitution.
349      */

350     private boolean isBinary(ClientServices client, String JavaDoc filename, Map directoryLevelWrappers) throws CommandException {
351         KeywordSubstitutionOptions keywordSubstitutionOptions = getKeywordSubst();
352
353         if (keywordSubstitutionOptions == KeywordSubstitutionOptions.BINARY) {
354             return true;
355         }
356
357         // The keyWordSubstitutions was set based on MIME-types by
358
// CVSAdd which had no notion of cvswrappers. Therefore some
359
// filetypes returned as text may actually be binary within CVS
360
// We check for those files here
361

362         boolean wrapperFound = false;
363
364         if (wrapperMap == null) {
365             // process the wrapper settings as we have not done it before.
366
wrapperMap = WrapperUtils.mergeWrapperMap(client);
367         }
368
369
370         for (Iterator it = wrapperMap.keySet().iterator(); it.hasNext();) {
371             SimpleStringPattern pattern = (SimpleStringPattern)it.next();
372             if (pattern.doesMatch(filename)) {
373                 keywordSubstitutionOptions = (KeywordSubstitutionOptions)wrapperMap.get(pattern);
374                 wrapperFound = true;
375                 break;
376             }
377         }
378
379         // if no wrappers are found to match the server and local settings, try
380
// the wrappers for this local directory
381
if (!wrapperFound && (directoryLevelWrappers != null) && (directoryLevelWrappers!=EMPTYWRAPPER)) {
382             for (Iterator it = directoryLevelWrappers.keySet().iterator(); it.hasNext();) {
383                 SimpleStringPattern pattern = (SimpleStringPattern)it.next();
384                 if (pattern.doesMatch(filename)) {
385                     keywordSubstitutionOptions = (KeywordSubstitutionOptions)directoryLevelWrappers.get(pattern);
386                     wrapperFound = true;
387                     break;
388                 }
389             }
390         }
391
392         return keywordSubstitutionOptions == KeywordSubstitutionOptions.BINARY;
393     }
394
395     /**
396      * Execute a command.
397      * @param client the client services object that provides any necessary
398      * services to this command, including the ability to actually process
399      * all the requests
400      */

401     public void execute(ClientServices client, EventManager em)
402             throws CommandException, AuthenticationException {
403         if (files == null || files.length == 0) {
404             throw new CommandException("No files have been specified for " + //NOI18N
405
"adding.", CommandException.getLocalMessage("AddCommand.noFilesSpecified", null)); //NOI18N
406
}
407
408         client.ensureConnection();
409
410         clientServices = client;
411         setLocalDirectory(client.getLocalPath());
412         
413         String JavaDoc directory = client.getLocalPath();
414         File cvsfolder = new File(directory, "CVS");
415         if (!cvsfolder.isDirectory()) {
416             //setFailed();
417
MessageEvent event = new MessageEvent(this, "cvs [add aborted]: there is no version here; do 'cvs checkout' first", true);
418             messageSent(event);
419             em.fireCVSEvent(event);
420             return ;
421         }
422 /*
423         newDirList = new HashMap();
424 */

425         newDirList.clear();
426
427         super.execute(client, em);
428
429         requests = new LinkedList();
430
431         if (client.isFirstCommand()) {
432             requests.add(new RootRequest(client.getRepository()));
433         }
434
435         // sets the message argument -m .. one for all files being sent..
436
String JavaDoc message = getMessage();
437         if (message != null) {
438             message = message.trim();
439         }
440         if (message != null
441                 && message.length() > 0) {
442             addMessageRequest(message);
443         }
444
445         if (getKeywordSubst() != null && !getKeywordSubst().equals("")) { //NOI18N
446
requests.add(new ArgumentRequest("-k" + getKeywordSubst())); //NOI18N
447
}
448
449         try {
450             // current dir sent to server BEFORE and AFTER - kinda hack??
451
for (int i = 0; i < files.length; i++) {
452                 addRequests(files[i]);
453             }
454
455             // now add the request that indicates the working directory for the
456
// command
457
requests.add(new DirectoryRequest(".", //NOI18N
458
client.getRepositoryForDirectory(getLocalDirectory())));
459
460             requests.addAll(argumentRequests);
461             argumentRequests.clear(); // MK sanity check.
462
requests.add(CommandRequest.ADD);
463             client.processRequests(requests);
464         }
465         catch (CommandException ex) {
466             throw ex;
467         }
468         catch (Exception JavaDoc ex) {
469             throw new CommandException(ex, ex.getLocalizedMessage());
470         }
471         finally {
472             requests.clear();
473         }
474     }
475
476     private void addMessageRequest(String JavaDoc message) {
477         requests.add(new ArgumentRequest("-m")); //NOI18N
478
StringTokenizer token = new StringTokenizer(message, "\n", false); //NOI18N
479
boolean first = true;
480         while (token.hasMoreTokens()) {
481             if (first) {
482                 requests.add(new ArgumentRequest(token.nextToken()));
483                 first = false;
484             }
485             else {
486                 requests.add(new ArgumentxRequest(token.nextToken()));
487             }
488         }
489     }
490
491     /**
492      * This method returns how the command would look like when typed on the
493      * command line.
494      * Each command is responsible for constructing this information.
495      * @returns <command's name> [<parameters>] files/dirs. Example: checkout -p CvsCommand.java
496      */

497     public String JavaDoc getCVSCommand() {
498         StringBuffer JavaDoc toReturn = new StringBuffer JavaDoc("add "); //NOI18N
499
toReturn.append(getCVSArguments());
500         File[] files = getFiles();
501         if (files != null) {
502             for (int index = 0; index < files.length; index++) {
503                 toReturn.append(files[index].getName());
504                 toReturn.append(' ');
505             }
506         }
507         return toReturn.toString();
508     }
509
510     /**
511      * Method that is called while the command is being executed.
512      * Descendants can override this method to return a Builder instance
513      * that will parse the server's output and create data structures.
514      */

515     public Builder createBuilder(EventManager eventManager) {
516         return new AddBuilder(eventManager, this);
517     }
518
519     /**
520      * Takes the arguments and sets the command.
521      * To be mainly used for automatic settings (like parsing the .cvsrc file)
522      * @return true if the option (switch) was recognized and set
523      */

524     public boolean setCVSCommand(char opt, String JavaDoc optArg) {
525         if (opt == 'm') {
526             setMessage(optArg);
527         }
528         else if (opt == 'k') {
529             KeywordSubstitutionOptions keywordSubst =
530                     KeywordSubstitutionOptions.findKeywordSubstOption(optArg);
531             setKeywordSubst(keywordSubst);
532         }
533         else {
534             return false;
535         }
536         return true;
537     }
538
539     /**
540      * Returns a string indicating the available options.
541      */

542     public String JavaDoc getOptString() {
543         return "m:k:"; //NOI18N
544
}
545
546     /**
547      * Listens for output of the command.
548      * If new directory is added, executes the createCvsFiles() method.
549      */

550     public void messageSent(MessageEvent e) {
551         String JavaDoc str = e.getMessage();
552         if (str.endsWith(DIR_ADDED)) {
553             str = str.substring(DIRECTORY.length(), str.indexOf(DIR_ADDED)).trim();
554             createCvsFiles(str);
555         }
556         super.messageSent(e);
557     }
558
559     /**
560      * For new directory that was added to the repository, creates the admin
561      * files in CVS subdir.
562      */

563     private void createCvsFiles(String JavaDoc newDirInRepository) {
564         String JavaDoc repository = newDirInRepository;
565         String JavaDoc dirName = repository;
566         if (dirName.lastIndexOf('/') >= 0) {
567             dirName = dirName.substring(dirName.lastIndexOf('/') + 1,
568                                         dirName.length());
569         }
570
571         if (newDirList.size() == 0) {
572             System.err.println("JavaCVS: Bug in AddCommand|createCvsFiles"); // NOI18N
573
System.err.println(" newDirInRepository = " + newDirInRepository); // NOI18N
574
return;
575         }
576
577         Paths paths = null;
578         for (Iterator i = newDirList.iterator(); i.hasNext();) {
579             paths = (Paths) i.next();
580             if (paths.getRepositoryPath().equals(newDirInRepository)) {
581                 i.remove();
582                 break;
583             }
584         }
585         
586         String JavaDoc local = paths.getPartPath();
587         String JavaDoc part = paths.getRepositoryPath();
588         repository = paths.getRepositoryPath();
589         
590         String JavaDoc tempDirName = part;
591         if (part.lastIndexOf('/') >= 0) {
592             tempDirName = part.substring(part.lastIndexOf('/') + 1,
593                                          part.length());
594         }
595
596         if (!tempDirName.equalsIgnoreCase(dirName)) {
597             System.err.println("JavaCVS: Bug in AddCommand|createCvsFiles"); // NOI18N
598
System.err.println(" newDirInRepository = " + newDirInRepository); // NOI18N
599
System.err.println(" tempDirName = " + tempDirName); // NOI18N
600
System.err.println(" dirName = " + dirName); // NOI18N
601
return;
602         }
603
604         try {
605             if (repository.startsWith(".")) { //NOI18N
606
repository = repository.substring(1);
607             }
608             clientServices.updateAdminData(local, repository, null);
609             createCvsTagFile(local, repository);
610         }
611         catch (IOException ex) {
612             System.err.println("TODO: couldn't create/update Cvs admin files"); // NOI18N
613
}
614 /*
615         Iterator it = newDirList.keySet().iterator();
616         while (it.hasNext())
617         {
618             String local = (String)it.next();
619             String part = (String)newDirList.get(local);
620             String tempDirName = part;
621             if (part.lastIndexOf('/') >= 0)
622             {
623                 tempDirName = part.substring(part.lastIndexOf('/') + 1,
624                                              part.length());
625             }
626
627             if (tempDirName.equalsIgnoreCase(dirName))
628             {
629                 try
630                 {
631                     clientServices.updateAdminData(local, repository, null);
632                     createCvsTagFile(local, repository);
633                     it.remove(); // hack.. in case 2 dirs being added have the same name??
634                     break;
635                 }
636                 catch (IOException exc)
637                 {
638                     System.out.println("TODO: couldn't create/update Cvs admin files");
639                 }
640             }
641         }
642 */

643     }
644
645     private void createCvsTagFile(String JavaDoc local, String JavaDoc repository) throws IOException {
646         File current = new File(getLocalDirectory(), local);
647         File parent = current.getParentFile();
648         String JavaDoc tag = clientServices.getStickyTagForDirectory(parent);
649         if (tag != null) {
650             File tagFile = new File(current, "CVS/Tag"); // NOI18N
651
tagFile.createNewFile();
652             PrintWriter w = new PrintWriter(new BufferedWriter(new FileWriter(tagFile)));
653             w.println(tag);
654             w.close();
655         }
656     }
657
658     /**
659      * resets all switches in the command. After calling this method,
660      * the command should have no switches defined and should behave defaultly.
661      */

662     public void resetCVSCommand() {
663         setMessage(null);
664         setKeywordSubst(null);
665     }
666
667     /**
668      * Returns the arguments of the command in the command-line style.
669      * Similar to getCVSCommand() however without the files and command's name
670      */

671     public String JavaDoc getCVSArguments() {
672         StringBuffer JavaDoc toReturn = new StringBuffer JavaDoc();
673         if (getMessage() != null) {
674             toReturn.append("-m \""); //NOI18N
675
toReturn.append(getMessage());
676             toReturn.append("\" "); //NOI18N
677
}
678         if (getKeywordSubst() != null) {
679             toReturn.append("-k"); //NOI18N
680
toReturn.append(getKeywordSubst().toString());
681             toReturn.append(" "); //NOI18N
682
}
683         return toReturn.toString();
684     }
685
686     private static class Paths {
687         private final String JavaDoc partPath;
688         private final String JavaDoc repositoryPath;
689
690         public Paths(String JavaDoc partPath, String JavaDoc repositoryPath) {
691             this.partPath = partPath;
692             this.repositoryPath = repositoryPath;
693         }
694
695         public String JavaDoc getPartPath() {
696             return partPath;
697         }
698
699         public String JavaDoc getRepositoryPath() {
700             return repositoryPath;
701         }
702     }
703 }
704
Popular Tags