KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > hudson > scm > SubversionSCM


1 package hudson.scm;
2
3 import hudson.FilePath;
4 import hudson.FilePath.FileCallable;
5 import hudson.Launcher;
6 import hudson.Util;
7 import static hudson.Util.fixNull;
8 import hudson.model.AbstractBuild;
9 import hudson.model.AbstractProject;
10 import hudson.model.BuildListener;
11 import hudson.model.Descriptor;
12 import hudson.model.Hudson;
13 import hudson.model.TaskListener;
14 import hudson.remoting.Channel;
15 import hudson.remoting.VirtualChannel;
16 import hudson.util.FormFieldValidator;
17 import hudson.util.Scrambler;
18 import org.kohsuke.stapler.StaplerRequest;
19 import org.kohsuke.stapler.StaplerResponse;
20 import org.tmatesoft.svn.core.SVNErrorMessage;
21 import org.tmatesoft.svn.core.SVNException;
22 import org.tmatesoft.svn.core.SVNURL;
23 import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
24 import org.tmatesoft.svn.core.auth.ISVNAuthenticationProvider;
25 import org.tmatesoft.svn.core.auth.SVNAuthentication;
26 import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication;
27 import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
28 import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
29 import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
30 import org.tmatesoft.svn.core.internal.wc.DefaultSVNAuthenticationManager;
31 import org.tmatesoft.svn.core.io.SVNRepository;
32 import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
33 import org.tmatesoft.svn.core.wc.SVNClientManager;
34 import org.tmatesoft.svn.core.wc.SVNInfo;
35 import org.tmatesoft.svn.core.wc.SVNLogClient;
36 import org.tmatesoft.svn.core.wc.SVNRevision;
37 import org.tmatesoft.svn.core.wc.SVNUpdateClient;
38 import org.tmatesoft.svn.core.wc.SVNWCClient;
39 import org.tmatesoft.svn.core.wc.SVNWCUtil;
40 import org.tmatesoft.svn.core.wc.xml.SVNXMLLogHandler;
41 import org.xml.sax.helpers.LocatorImpl JavaDoc;
42
43 import javax.servlet.ServletException JavaDoc;
44 import javax.xml.transform.TransformerConfigurationException JavaDoc;
45 import javax.xml.transform.sax.SAXTransformerFactory JavaDoc;
46 import javax.xml.transform.sax.TransformerHandler JavaDoc;
47 import javax.xml.transform.stream.StreamResult JavaDoc;
48 import java.io.BufferedReader JavaDoc;
49 import java.io.File JavaDoc;
50 import java.io.FileOutputStream JavaDoc;
51 import java.io.FileReader JavaDoc;
52 import java.io.IOException JavaDoc;
53 import java.io.PrintStream JavaDoc;
54 import java.io.PrintWriter JavaDoc;
55 import java.io.Serializable JavaDoc;
56 import java.io.StringWriter JavaDoc;
57 import java.util.ArrayList JavaDoc;
58 import java.util.Collection JavaDoc;
59 import java.util.HashMap JavaDoc;
60 import java.util.Hashtable JavaDoc;
61 import java.util.List JavaDoc;
62 import java.util.Map JavaDoc;
63 import java.util.Map.Entry;
64 import java.util.StringTokenizer JavaDoc;
65 import java.util.logging.Logger JavaDoc;
66 import java.util.logging.Level JavaDoc;
67
68 /**
69  * Subversion.
70  *
71  * Check http://svn.collab.net/repos/svn/trunk/subversion/svn/schema/ for
72  * various output formats.
73  *
74  * @author Kohsuke Kawaguchi
75  */

76 public class SubversionSCM extends SCM implements Serializable JavaDoc {
77     private final String JavaDoc modules;
78     private boolean useUpdate;
79     private String JavaDoc username;
80
81     /**
82      * @deprecated
83      * No longer in use but left for serialization compatibility.
84      */

85     private transient String JavaDoc otherOptions;
86
87     SubversionSCM(String JavaDoc modules, boolean useUpdate, String JavaDoc username) {
88         StringBuilder JavaDoc normalizedModules = new StringBuilder JavaDoc();
89         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(modules);
90         while(tokens.hasMoreTokens()) {
91             if(normalizedModules.length()>0) normalizedModules.append(' ');
92             String JavaDoc m = tokens.nextToken();
93             if(m.endsWith("/"))
94                 // the normalized name is always without the trailing '/'
95
m = m.substring(0,m.length()-1);
96             normalizedModules.append(m);
97        }
98
99         this.modules = normalizedModules.toString();
100         this.useUpdate = useUpdate;
101         this.username = nullify(username);
102     }
103
104     /**
105      * Whitespace-separated list of SVN URLs that represent
106      * modules to be checked out.
107      */

108     public String JavaDoc getModules() {
109         return modules;
110     }
111
112     public boolean isUseUpdate() {
113         return useUpdate;
114     }
115
116     public String JavaDoc getUsername() {
117         return username;
118     }
119
120     private Collection JavaDoc<String JavaDoc> getModuleDirNames() {
121         List JavaDoc<String JavaDoc> dirs = new ArrayList JavaDoc<String JavaDoc>();
122         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(modules);
123         while(tokens.hasMoreTokens()) {
124             dirs.add(getLastPathComponent(tokens.nextToken()));
125         }
126         return dirs;
127     }
128
129     private boolean calcChangeLog(AbstractBuild<?, ?> build, File JavaDoc changelogFile, BuildListener listener) throws IOException JavaDoc {
130         if(build.getPreviousBuild()==null) {
131             // nothing to compare against
132
return createEmptyChangeLog(changelogFile, listener, "log");
133         }
134
135         PrintStream JavaDoc logger = listener.getLogger();
136
137         Map JavaDoc<String JavaDoc,Long JavaDoc> previousRevisions = parseRevisionFile(build.getPreviousBuild());
138         Map JavaDoc<String JavaDoc,Long JavaDoc> thisRevisions = parseRevisionFile(build);
139
140         boolean changelogFileCreated = false;
141
142         SVNLogClient svnlc = createSvnClientManager(getDescriptor().createAuthenticationProvider()).getLogClient();
143
144         TransformerHandler JavaDoc th = createTransformerHandler();
145         th.setResult(new StreamResult JavaDoc(changelogFile));
146         SVNXMLLogHandler logHandler = new SVNXMLLogHandler(th);
147         // work around for http://svnkit.com/tracker/view.php?id=175
148
th.setDocumentLocator(DUMMY_LOCATOR);
149         logHandler.startDocument();
150
151
152         StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(modules);
153         while(tokens.hasMoreTokens()) {
154             String JavaDoc url = tokens.nextToken();
155             Long JavaDoc prevRev = previousRevisions.get(url);
156             if(prevRev==null) {
157                 logger.println("no revision recorded for "+url+" in the previous build");
158                 continue;
159             }
160             Long JavaDoc thisRev = thisRevisions.get(url);
161             if(thisRev.equals(prevRev)) {
162                 logger.println("no change for "+url+" since the previous build");
163                 continue;
164             }
165
166             try {
167                 svnlc.doLog(SVNURL.parseURIEncoded(url),null,
168                 SVNRevision.create(prevRev), SVNRevision.create(prevRev+1),
169                     SVNRevision.create(thisRev),
170                     false, true, Long.MAX_VALUE, logHandler);
171             } catch (SVNException e) {
172                 e.printStackTrace(listener.error("revision check failed on "+url));
173             }
174             changelogFileCreated = true;
175         }
176
177         if(changelogFileCreated) {
178             logHandler.endDocument();
179         }
180
181         if(!changelogFileCreated)
182             createEmptyChangeLog(changelogFile, listener, "log");
183
184         return true;
185     }
186
187     /**
188      * Creates an identity transformer.
189      */

190     private static TransformerHandler JavaDoc createTransformerHandler() {
191         try {
192             return ((SAXTransformerFactory JavaDoc) SAXTransformerFactory.newInstance()).newTransformerHandler();
193         } catch (TransformerConfigurationException JavaDoc e) {
194             throw new Error JavaDoc(e); // impossible
195
}
196     }
197
198     /*package*/ static Map JavaDoc<String JavaDoc,Long JavaDoc> parseRevisionFile(AbstractBuild build) throws IOException JavaDoc {
199         Map JavaDoc<String JavaDoc,Long JavaDoc> revisions = new HashMap JavaDoc<String JavaDoc,Long JavaDoc>(); // module -> revision
200
{// read the revision file of the last build
201
File JavaDoc file = getRevisionFile(build);
202             if(!file.exists())
203                 // nothing to compare against
204
return revisions;
205
206             BufferedReader JavaDoc br = new BufferedReader JavaDoc(new FileReader JavaDoc(file));
207             String JavaDoc line;
208             while((line=br.readLine())!=null) {
209                 int index = line.lastIndexOf('/');
210                 if(index<0) {
211                     continue; // invalid line?
212
}
213                 try {
214                     revisions.put(line.substring(0,index), Long.parseLong(line.substring(index+1)));
215                 } catch (NumberFormatException JavaDoc e) {
216                     // perhaps a corrupted line. ignore
217
}
218             }
219         }
220
221         return revisions;
222     }
223
224     public boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, final BuildListener listener, File JavaDoc changelogFile) throws IOException JavaDoc, InterruptedException JavaDoc {
225         if(!checkout(launcher,workspace, listener))
226             return false;
227
228         // write out the revision file
229
PrintWriter JavaDoc w = new PrintWriter JavaDoc(new FileOutputStream JavaDoc(getRevisionFile(build)));
230         try {
231             Map JavaDoc<String JavaDoc,SvnInfo> revMap = buildRevisionMap(workspace, listener);
232             for (Entry<String JavaDoc,SvnInfo> e : revMap.entrySet()) {
233                 w.println( e.getKey() +'/'+ e.getValue().revision );
234             }
235         } finally {
236             w.close();
237         }
238
239         return calcChangeLog(build, changelogFile, listener);
240     }
241
242     public boolean checkout(Launcher launcher, FilePath workspace, final TaskListener listener) throws IOException JavaDoc, InterruptedException JavaDoc {
243         if(useUpdate && isUpdatable(workspace, listener)) {
244             return update(launcher,workspace,listener);
245         } else {
246             final ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider();
247             return workspace.act(new FileCallable<Boolean JavaDoc>() {
248                 public Boolean JavaDoc invoke(File JavaDoc ws, VirtualChannel channel) throws IOException JavaDoc {
249                     Util.deleteContentsRecursive(ws);
250                     SVNUpdateClient svnuc = createSvnClientManager(authProvider).getUpdateClient();
251                     svnuc.setEventHandler(new SubversionUpdateEventHandler(listener));
252
253                     StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(modules);
254                     while(tokens.hasMoreTokens()) {
255                         try {
256                             SVNURL url = SVNURL.parseURIEncoded(tokens.nextToken());
257                             listener.getLogger().println("Checking out "+url);
258
259                             svnuc.doCheckout(url, new File JavaDoc(ws, getLastPathComponent(url.getPath())), SVNRevision.HEAD, SVNRevision.HEAD, true );
260                         } catch (SVNException e) {
261                             e.printStackTrace(listener.error("Error in subversion"));
262                             return false;
263                         }
264                     }
265
266                     return true;
267                 }
268             });
269         }
270     }
271
272     /**
273      * Creates {@link SVNClientManager}.
274      *
275      * <p>
276      * This method must be executed on the slave where svn operations are performed.
277      *
278      * @param authProvider
279      * The value obtained from {@link DescriptorImpl#createAuthenticationProvider()}.
280      * If the operation runs on slaves,
281      * (and properly remoted, if the svn operations run on slaves.)
282      */

283     private static SVNClientManager createSvnClientManager(ISVNAuthenticationProvider authProvider) {
284         ISVNAuthenticationManager sam = SVNWCUtil.createDefaultAuthenticationManager();
285         sam.setAuthenticationProvider(authProvider);
286         return SVNClientManager.newInstance(SVNWCUtil.createDefaultOptions(true),sam);
287     }
288
289     public static final class SvnInfo implements Serializable JavaDoc {
290         /**
291          * Decoded repository URL.
292          */

293         final String JavaDoc url;
294         final long revision;
295
296         public SvnInfo(String JavaDoc url, long revision) {
297             this.url = url;
298             this.revision = revision;
299         }
300
301         public SvnInfo(SVNInfo info) {
302             this( info.getURL().toDecodedString(), info.getCommittedRevision().getNumber() );
303         }
304
305         public SVNURL getSVNURL() throws SVNException {
306             return SVNURL.parseURIDecoded(url);
307         }
308
309         private static final long serialVersionUID = 1L;
310     }
311
312     /**
313      * Gets the SVN metadata for the given local workspace.
314      *
315      * @param workspace
316      * The target to run "svn info".
317      */

318     private SVNInfo parseSvnInfo(File JavaDoc workspace, ISVNAuthenticationProvider authProvider) throws SVNException {
319         SVNWCClient svnWc = createSvnClientManager(authProvider).getWCClient();
320         return svnWc.doInfo(workspace,SVNRevision.WORKING);
321     }
322
323     /**
324      * Gets the SVN metadata for the remote repository.
325      *
326      * @param remoteUrl
327      * The target to run "svn info".
328      */

329     private SVNInfo parseSvnInfo(SVNURL remoteUrl, ISVNAuthenticationProvider authProvider) throws SVNException {
330         SVNWCClient svnWc = createSvnClientManager(authProvider).getWCClient();
331         return svnWc.doInfo(remoteUrl, SVNRevision.HEAD, SVNRevision.HEAD);
332     }
333
334     /**
335      * Checks .svn files in the workspace and finds out revisions of the modules
336      * that the workspace has.
337      *
338      * @return
339      * null if the parsing somehow fails. Otherwise a map from the repository URL to revisions.
340      */

341     private Map JavaDoc<String JavaDoc,SvnInfo> buildRevisionMap(FilePath workspace, final TaskListener listener) throws IOException JavaDoc, InterruptedException JavaDoc {
342         final ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider();
343         return workspace.act(new FileCallable<Map JavaDoc<String JavaDoc,SvnInfo>>() {
344             public Map JavaDoc<String JavaDoc,SvnInfo> invoke(File JavaDoc ws, VirtualChannel channel) throws IOException JavaDoc {
345                 Map JavaDoc<String JavaDoc/*module name*/,SvnInfo> revisions = new HashMap JavaDoc<String JavaDoc,SvnInfo>();
346
347                 SVNWCClient svnWc = createSvnClientManager(authProvider).getWCClient();
348                 // invoke the "svn info"
349
for( String JavaDoc module : getModuleDirNames() ) {
350                     try {
351                         SvnInfo info = new SvnInfo(svnWc.doInfo(new File JavaDoc(ws,module),SVNRevision.WORKING));
352                         revisions.put(info.url,info);
353                     } catch (SVNException e) {
354                         e.printStackTrace(listener.error("Failed to parse svn info for "+module));
355                     }
356                 }
357
358                 return revisions;
359             }
360         });
361     }
362
363     /**
364      * Gets the file that stores the revision.
365      */

366     private static File JavaDoc getRevisionFile(AbstractBuild build) {
367         return new File JavaDoc(build.getRootDir(),"revision.txt");
368     }
369
370     public boolean update(Launcher launcher, FilePath workspace, final TaskListener listener) throws IOException JavaDoc, InterruptedException JavaDoc {
371         final ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider();
372         return workspace.act(new FileCallable<Boolean JavaDoc>() {
373             public Boolean JavaDoc invoke(File JavaDoc ws, VirtualChannel channel) throws IOException JavaDoc {
374                 SVNUpdateClient svnuc = createSvnClientManager(authProvider).getUpdateClient();
375                 svnuc.setEventHandler(new SubversionUpdateEventHandler(listener));
376
377                 StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(modules);
378                 while(tokens.hasMoreTokens()) {
379                     try {
380                         String JavaDoc url = tokens.nextToken();
381                         listener.getLogger().println("Updating "+url);
382                         svnuc.doUpdate(new File JavaDoc(ws, getLastPathComponent(url)), SVNRevision.HEAD, true );
383                     } catch (SVNException e) {
384                         e.printStackTrace(listener.error("Error in subversion"));
385                         return false;
386                     }
387                 }
388                 return true;
389             }
390         });
391     }
392
393     /**
394      * Returns true if we can use "svn update" instead of "svn checkout"
395      */

396     private boolean isUpdatable(FilePath workspace, final TaskListener listener) throws IOException JavaDoc, InterruptedException JavaDoc {
397         final ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider();
398
399         return workspace.act(new FileCallable<Boolean JavaDoc>() {
400             public Boolean JavaDoc invoke(File JavaDoc ws, VirtualChannel channel) throws IOException JavaDoc {
401                 StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(modules);
402                 while(tokens.hasMoreTokens()) {
403                     String JavaDoc url = tokens.nextToken();
404                     String JavaDoc moduleName = getLastPathComponent(url);
405                     File JavaDoc module = new File JavaDoc(ws,moduleName);
406
407                     if(!module.exists()) {
408                         listener.getLogger().println("Checking out a fresh workspace because "+module+" doesn't exist");
409                         return false;
410                     }
411
412                     try {
413                         SvnInfo svnInfo = new SvnInfo(parseSvnInfo(module,authProvider));
414                         if(!svnInfo.url.equals(url)) {
415                             listener.getLogger().println("Checking out a fresh workspace because the workspace is not "+url);
416                             return false;
417                         }
418                     } catch (SVNException e) {
419                         listener.getLogger().println("Checking out a fresh workspace because Hudson failed to detect the current workspace "+module);
420                         e.printStackTrace(listener.error(e.getMessage()));
421                         return false;
422                     }
423                 }
424                 return true;
425             }
426         });
427     }
428
429     public boolean pollChanges(AbstractProject project, Launcher launcher, FilePath workspace, TaskListener listener) throws IOException JavaDoc, InterruptedException JavaDoc {
430         // current workspace revision
431
Map JavaDoc<String JavaDoc,SvnInfo> wsRev = buildRevisionMap(workspace, listener);
432
433         ISVNAuthenticationProvider authProvider = getDescriptor().createAuthenticationProvider();
434
435         // check the corresponding remote revision
436
for (SvnInfo localInfo : wsRev.values()) {
437             try {
438                 SvnInfo remoteInfo = new SvnInfo(parseSvnInfo(localInfo.getSVNURL(),authProvider));
439                 listener.getLogger().println("Revision:"+remoteInfo.revision);
440                 if(remoteInfo.revision > localInfo.revision)
441                     return true; // change found
442
} catch (SVNException e) {
443                 e.printStackTrace(listener.error("Failed to check repository revision for "+localInfo.url));
444             }
445         }
446
447         return false; // no change
448
}
449
450     public ChangeLogParser createChangeLogParser() {
451         return new SubversionChangeLogParser();
452     }
453
454
455     public DescriptorImpl getDescriptor() {
456         return DescriptorImpl.DESCRIPTOR;
457     }
458
459     public void buildEnvVars(Map JavaDoc<String JavaDoc,String JavaDoc> env) {
460         // no environment variable
461
}
462
463     public FilePath getModuleRoot(FilePath workspace) {
464         String JavaDoc s;
465
466         // if multiple URLs are specified, pick the first one
467
int idx = modules.indexOf(' ');
468         if(idx>=0) s = modules.substring(0,idx);
469         else s = modules;
470
471         return workspace.child(getLastPathComponent(s));
472     }
473
474     private static String JavaDoc getLastPathComponent(String JavaDoc s) {
475         String JavaDoc[] tokens = s.split("/");
476         return tokens[tokens.length-1]; // return the last token
477
}
478
479     public static final class DescriptorImpl extends Descriptor<SCM> {
480         public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
481
482         /**
483          * Path to <tt>svn.exe</tt>. Null to default.
484          *
485          * @deprecated
486          * No longer in use.
487          */

488         private volatile String JavaDoc svnExe;
489
490         /**
491          * SVN authentication realm to its associated credentials.
492          */

493         private final Map JavaDoc<String JavaDoc,Credential> credentials = new Hashtable JavaDoc<String JavaDoc,Credential>();
494
495         /**
496          * Stores {@link SVNAuthentication} for a single realm.
497          */

498         private static abstract class Credential implements Serializable JavaDoc {
499             abstract SVNAuthentication createSVNAuthentication();
500         }
501
502         private static final class PasswordCredential extends Credential {
503             private final String JavaDoc userName;
504             private final String JavaDoc password; // scrambled by base64
505

506             public PasswordCredential(String JavaDoc userName, String JavaDoc password) {
507                 this.userName = userName;
508                 this.password = Scrambler.scramble(password);
509             }
510
511             @Override JavaDoc
512             SVNPasswordAuthentication createSVNAuthentication() {
513                 return new SVNPasswordAuthentication(userName,Scrambler.descramble(password),false);
514             }
515         }
516
517         /**
518          * Remoting interface that allows remote {@link ISVNAuthenticationProvider}
519          * to read from local {@link DescriptorImpl#credentials}.
520          */

521         private interface RemotableSVNAuthenticationProvider {
522             Credential getCredential(String JavaDoc realm);
523         }
524
525         private final class RemotableSVNAuthenticationProviderImpl implements RemotableSVNAuthenticationProvider, Serializable JavaDoc {
526             public Credential getCredential(String JavaDoc realm) {
527                 return credentials.get(realm);
528             }
529
530             /**
531              * When sent to the remote node, send a proxy.
532              */

533             private Object JavaDoc writeReplace() {
534                 return Channel.current().export(RemotableSVNAuthenticationProvider.class, this);
535             }
536         }
537
538         /**
539          * See {@link DescriptorImpl#createAuthenticationProvider()}.
540          */

541         private static final class SVNAuthenticationProviderImpl implements ISVNAuthenticationProvider, Serializable JavaDoc {
542             private final RemotableSVNAuthenticationProvider source;
543
544             public SVNAuthenticationProviderImpl(RemotableSVNAuthenticationProvider source) {
545                 this.source = source;
546             }
547
548             public SVNAuthentication requestClientAuthentication(String JavaDoc kind, SVNURL url, String JavaDoc realm, SVNErrorMessage errorMessage, SVNAuthentication previousAuth, boolean authMayBeStored) {
549                 Credential cred = source.getCredential(realm);
550                 if(cred==null) return null;
551                 return cred.createSVNAuthentication();
552             }
553
554             public int acceptServerAuthentication(SVNURL url, String JavaDoc realm, Object JavaDoc certificate, boolean resultMayBeStored) {
555                 return ACCEPTED_TEMPORARY;
556             }
557
558             private static final long serialVersionUID = 1L;
559         }
560
561         private DescriptorImpl() {
562             super(SubversionSCM.class);
563             load();
564         }
565
566         public String JavaDoc getDisplayName() {
567             return "Subversion";
568         }
569
570         public SCM newInstance(StaplerRequest req) {
571             return new SubversionSCM(
572                 req.getParameter("svn_modules"),
573                 req.getParameter("svn_use_update")!=null,
574                 req.getParameter("svn_username")
575             );
576         }
577
578         /**
579          * Creates {@link ISVNAuthenticationProvider} backed by {@link #credentials}.
580          * This method must be invoked on the master, but the returned object is remotable.
581          */

582         public ISVNAuthenticationProvider createAuthenticationProvider() {
583             return new SVNAuthenticationProviderImpl(new RemotableSVNAuthenticationProviderImpl());
584         }
585
586         /**
587          * Used in the job configuration page to check if authentication for the SVN URLs
588          * are available.
589          */

590         public void doAuthenticationCheck(final StaplerRequest req, StaplerResponse rsp) throws IOException JavaDoc, ServletException JavaDoc {
591             new FormFieldValidator(req,rsp,true) {
592                 protected void check() throws IOException JavaDoc, ServletException JavaDoc {
593                     StringTokenizer JavaDoc tokens = new StringTokenizer JavaDoc(fixNull(request.getParameter("value")));
594                     String JavaDoc message="";
595
596                     while(tokens.hasMoreTokens()) {
597                         String JavaDoc url = tokens.nextToken();
598
599                         try {
600                             SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIDecoded(url));
601
602                             ISVNAuthenticationManager sam = SVNWCUtil.createDefaultAuthenticationManager();
603                             sam.setAuthenticationProvider(createAuthenticationProvider());
604                             repository.setAuthenticationManager(sam);
605                             
606                             repository.testConnection();
607                         } catch (SVNException e) {
608                             StringWriter JavaDoc sw = new StringWriter JavaDoc();
609                             e.printStackTrace(new PrintWriter JavaDoc(sw));
610
611                             message += "Unable to access "+url+" : "+Util.escape( e.getErrorMessage().getFullMessage());
612                             message += " <a HREF='#' id=svnerrorlink onclick='javascript:" +
613                                 "document.getElementById(\"svnerror\").style.display=\"block\";" +
614                                 "document.getElementById(\"svnerrorlink\").style.display=\"none\";" +
615                                 "return false;'>(show details)</a>";
616                             message += "<pre id=svnerror style='display:none'>"+sw+"</pre>";
617                             message += " (Maybe you need to <a HREF='"+req.getContextPath()+"/scm/SubversionSCM/enterCredential?"+url+"'>enter credential</a>?)";
618                             message += "<br>";
619                             logger.log(Level.INFO, "Failed to access subversion repository "+url,e);
620                         }
621                     }
622
623                     if(message.length()==0)
624                         ok();
625                     else
626                         error(message);
627                 }
628             }.process();
629         }
630
631         /**
632          * Submits the authentication info.
633          */

634         public void doPostCredential(final StaplerRequest req, StaplerResponse rsp) throws IOException JavaDoc, ServletException JavaDoc {
635             final String JavaDoc url = req.getParameter("url");
636             final String JavaDoc username = req.getParameter("username");
637             final String JavaDoc password = req.getParameter("password");
638
639             try {
640                 // the way it works with SVNKit is that
641
// 1) svnkit calls AuthenticationManager asking for a credential.
642
// this is when we can see the 'realm', which identifies the user domain.
643
// 2) DefaultSVNAuthenticationManager returns the username and password we set below
644
// 3) if the authentication is successful, svnkit calls back acknowledgeAuthentication
645
// (so we store the password info here)
646
SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIDecoded(url));
647                 repository.setAuthenticationManager(new DefaultSVNAuthenticationManager(SVNWCUtil.getDefaultConfigurationDirectory(),true,username,password) {
648                     public void acknowledgeAuthentication(boolean accepted, String JavaDoc kind, String JavaDoc realm, SVNErrorMessage errorMessage, SVNAuthentication authentication) throws SVNException {
649                         if(accepted) {
650                             credentials.put(realm,new PasswordCredential(username,password));
651                             save();
652                         }
653                         super.acknowledgeAuthentication(accepted, kind, realm, errorMessage, authentication);
654                     }
655                 });
656                 repository.testConnection();
657                 rsp.sendRedirect("credentialOK");
658             } catch (SVNException e) {
659                 req.setAttribute("message",e.getErrorMessage());
660                 rsp.forward(Hudson.getInstance(),"error",req);
661             }
662         }
663
664         static { new Initializer(); }
665     }
666
667     private static final long serialVersionUID = 1L;
668
669     private static final Logger JavaDoc logger = Logger.getLogger(SubversionSCM.class.getName());
670
671     private static final LocatorImpl JavaDoc DUMMY_LOCATOR = new LocatorImpl JavaDoc();
672
673     static {
674         new Initializer();
675         DUMMY_LOCATOR.setLineNumber(-1);
676         DUMMY_LOCATOR.setColumnNumber(-1);
677     }
678     
679     private static final class Initializer {
680         static {
681             DAVRepositoryFactory.setup(); // http, https
682
SVNRepositoryFactoryImpl.setup(); // svn, svn+xxx
683
FSRepositoryFactory.setup(); // file
684
}
685     }
686 }
687
Popular Tags