package hudson.plugins.javanet; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.Hudson; import hudson.security.Permission; import static hudson.plugins.javanet.ItemListenerImpl.DAY; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.apache.commons.io.FileUtils; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.util.regex.Pattern; import java.net.URL; /** * UI for java.net stats. Added to the project. * * @author Kohsuke Kawaguchi */ public class JavaNetStatsAction implements Action { /** * Project that owns this action. */ public final AbstractProject<?,?> project; /** * Java.net project name. */ private String projectName; private File reportDir; public JavaNetStatsAction(AbstractProject<?, ?> project, String projectName) { this.project = project; this.projectName = projectName; this.reportDir = getReportDirectory(); } public String getProjectName() { return projectName; } public void scheduleGeneration() { new ReportGenerator(projectName,reportDir).schedule(); } public String getIconFileName() { return "graph.gif"; } public String getDisplayName() { return "Java.net Statistics"; } public String getUrlName() { return "java.net-stats"; } public boolean isReportReady() { return new File(reportDir,"index.html").exists(); } /** * Schedules the re-generation of the report if the report is too old. */ public void upToDateCheck() { File indexHtml = new File(reportDir,"index.html"); long diff = System.currentTimeMillis() - indexHtml.lastModified(); if(!indexHtml.exists() || (diff>7*DAY)) { scheduleGeneration(); } } public URL getIssueStatsIndexHtml() { return getClass().getClassLoader().getResource("org/jvnet/its/index.html"); } /** * Directory in which the report is stored. */ private File getReportDirectory() { return new File(Hudson.getInstance().getRootDir(), "java.net/issue-tracker-stats/" + projectName); } /** * Serves static files in the report directory. */ public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { String path = req.getRestOfPath().substring(1); // make sure we are not serving anything strange if(!PATH.matcher(path).matches()) { rsp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } rsp.serveFile(req,new File(reportDir,path).toURI().toURL()); } public HttpResponse doChangeProject(@QueryParameter("name") String name) throws IOException, ServletException { project.checkPermission(CONFIGURE); projectName = name.trim(); reportDir = getReportDirectory(); FileUtils.writeStringToFile(getOverrideFile(),projectName,"UTF-8"); return HttpResponses.redirectToDot(); } /** * Manually trigger the regeneration. */ public HttpResponse doRegenerate() throws IOException, ServletException { scheduleGeneration(); return HttpResponses.redirectToDot(); } /** * Returns true if the current user has a permission to reconfigure this action. */ public boolean hasConfigurePermission() { return project.hasPermission(CONFIGURE); } /** * File that stores the java.net project name, to manually override * the default project name inference. */ private File getOverrideFile() { return new File(project.getRootDir(),"java.net.projectName"); } /*package*/ static String readOverrideFile(AbstractProject<?,?> project) { try { return FileUtils.readFileToString(new File(project.getRootDir(),"java.net.projectName"),"UTF-8").trim(); } catch (IOException e) { return null; } } private static final Pattern PATH = Pattern.compile("[A-Za-z0-9\\-.]+"); /** * Permission to change project. */ public static final Permission CONFIGURE = Permission.CONFIGURE; }