package hudson.plugins.perforce.browsers; import static hudson.Util.fixEmpty; import hudson.model.Descriptor; import hudson.plugins.perforce.*; import hudson.scm.RepositoryBrowser; import hudson.util.FormValidation; import hudson.Extension; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.DataBoundConstructor; import javax.servlet.ServletException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import com.tek42.perforce.model.Changelist; import net.sf.json.JSONObject; /** * {@link RepositoryBrowser} for Perforce's P4Web. * * @author Mike Wille */ public class P4Web extends PerforceRepositoryBrowser { /** * The URL of the P4Web server. * * This is normally like <tt>http://perforce.com:5000/</tt> Normalized to * have '/' at the tail. */ public final URL url; // 'ac' stands for action and corresponds to a unique screen in P4Web public final String p4WebEndShite = "?ac=22"; // The file contents screen public final String p4DifEndShite = "?ac=19"; // The file comparison screen (diff) public final String p4ClEndShite = "?ac=10"; // The CL screen @DataBoundConstructor public P4Web(URL url) throws MalformedURLException { this.url = normalizeToEndWithSlash(url); } @Override public URL getDiffLink(Changelist.FileEntry file) throws IOException { if(file.getAction() != Changelist.FileEntry.Action.EDIT && file.getAction() != Changelist.FileEntry.Action.INTEGRATE) return null; int r = new Integer(file.getRevision()); if(r <= 1) return null; return new URL(url.toString() + file.getFilename() + p4DifEndShite + "&rev1=" + (r - 1) + "&rev2=" + (r)); } @Override public URL getFileLink(Changelist.FileEntry file) throws IOException { return new URL(url.toString() + file.getFilename() + p4WebEndShite); } @Override public URL getChangeSetLink(PerforceChangeLogEntry changeSet) throws IOException { return new URL(url.toString() + changeSet.getChange().getChangeNumber() + p4ClEndShite); } public URL getURL() { return url; } @Extension public static class DescriptorImpl extends Descriptor<RepositoryBrowser<?>> { public String getDisplayName() { return "P4Web"; } /** * Performs on-the-fly validation of the URL. */ public FormValidation doCheck(final StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { return new FormValidation.URLCheck() { @Override protected FormValidation check() throws IOException, ServletException { String host = fixEmpty(req.getParameter("url")); String user = fixEmpty(req.getParameter("user")); String pass = fixEmpty(req.getParameter("pass")); if(host==null) {// nothing entered yet return FormValidation.ok(); } if(!host.endsWith("/")) host += '/'; if(!host.startsWith("http://") && !host.startsWith("https://")) { return FormValidation.errorWithMarkup("The URL should contain <tt>http://</tt> or <tt>https://</tt>"); } /** * We need a base64 encoder in order to do authentication. * String login = user + ":" + pass; String encodedLogin = new BASE64Encoder().encodeBuffer(login.getBytes()); URL url = new URL(host); HttpURLConnection con = (HttpURLConnection) url.openConnection(); if(encodedLogin != null) con.setRequestProperty("Authorization", "Basic " + encodedLogin); // really our only other option we care about. con.setInstanceFollowRedirects(true); try { if(!findText(open(con), "P4Web")) { return FormValidation.error("This is a valid URL but it doesn't look like P4Web is running"); } } catch (IOException e) { handleIOException(host, e); } */ return FormValidation.ok(); } }.check(); } @Override public P4Web newInstance(StaplerRequest req, JSONObject formData) throws FormException { return req.bindParameters(P4Web.class,"p4web."); } } private static final long serialVersionUID = 1L; }