package hudson.plugins.mercurial.browser; import hudson.Util; import hudson.model.Descriptor; import hudson.plugins.mercurial.MercurialChangeSet; import hudson.scm.RepositoryBrowser; import hudson.util.FormValidation; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import org.kohsuke.stapler.QueryParameter; /** * Parent class, as there is more than one browser. * {@link HgBrowser#readResolve()} will return the old default {@link HgWeb}. * Direct calls on this class will always throw {@link UnsupportedOperationException}s. */ public abstract class HgBrowser extends RepositoryBrowser<MercurialChangeSet> { transient MercurialChangeSet current; private final URL url; private static final long serialVersionUID = 1L; /** * {@inheritDoc} */ @Override public URL getChangeSetLink(MercurialChangeSet changeset) throws IOException { throw new UnsupportedOperationException("Method is not implemented for HgBrowser"); } /** * Returns a link to a specific revision of a file. * * @param path to a file. * @return URL pointing to a specific revision of the file. * * @throws MalformedURLException */ public URL getFileLink(String path) throws MalformedURLException { throw new UnsupportedOperationException("Method is not implemented for HgBrowser"); } /** * Returns a link to a diff for a file. * * @param path to a file. * @return URL pointing to a specific revision of the file. * * @throws MalformedURLException */ public URL getDiffLink(String path) throws MalformedURLException { throw new UnsupportedOperationException("Method is not implemented for HgBrowser"); } /** * Throws an {@link IllegalStateException} if current is null. This is used in subclasses. * * @throws IllegalStateException if current is null. */ void checkCurrentIsNotNull() { if (current == null) { throw new IllegalStateException("current changeset must not be null, did you forget to call 'getChangeSetLink'?"); } } HgBrowser(String url) throws MalformedURLException { this.url = normalizeToEndWithSlash(new URL(url)); } public URL getUrl() { return url; } // compatibility with earlier plugins public Object readResolve() { if (!this.getClass().equals(HgBrowser.class)) { return this; } // make sure to return the default HgWeb only if we no class is given in config. try { return new HgWeb(url.toExternalForm()); } catch (MalformedURLException e) { throw new RuntimeException(e); } } protected static abstract class HgBrowserDescriptor extends Descriptor<RepositoryBrowser<?>> { /** * Stapler does not seem to (reliably) find the web method on subclasses, so each needs to implement this to call {@link #_doCheckUrl}. * {@link #check} may be used for browser-specific checks. */ public abstract FormValidation doCheckUrl(@QueryParameter String url); protected final FormValidation _doCheckUrl(@QueryParameter String url) { url = Util.fixNull(url); if (url.length() == 0) { return FormValidation.error("URL is mandatory"); } try { URL u = new URL(url); if (u.getPath().endsWith("/")) { return check(u); } else { return FormValidation.warning("Browser URL should end with a slash (/)"); } } catch (MalformedURLException x) { return FormValidation.error(x, "Invalid URL"); } } /** Perform optional additional checks on URL, such as that it uses a particular host. */ protected FormValidation check(URL url) { return FormValidation.ok(); } } }