From 84fb49088a14cff8b453e0e32f6ad7007eb2184a Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Sat, 29 Dec 2012 18:11:08 +0100 Subject: o Adding jobs view for jenkins app. --- .../trygvis/esper/testing/jenkins/JenkinsDao.java | 67 ++++++----- .../testing/web/resource/AbstractResource.java | 11 ++ .../testing/web/resource/JenkinsResource.java | 130 ++++++++++++++++----- .../webapp/apps/jenkinsApp/JenkinsResources.js | 8 ++ src/main/webapp/apps/jenkinsApp/jenkinsApp.js | 41 ++++--- src/main/webapp/apps/jenkinsApp/job.html | 59 ++++++++++ src/main/webapp/apps/jenkinsApp/server-list.html | 52 +++++---- src/main/webapp/apps/jenkinsApp/server.html | 1 + .../jenkins/CreateMissingMavenModuleJobsApp.java | 29 ++--- .../esper/testing/jenkins/SetJobTypeApp.java | 28 ++--- 10 files changed, 282 insertions(+), 144 deletions(-) create mode 100644 src/main/webapp/apps/jenkinsApp/job.html diff --git a/src/main/java/io/trygvis/esper/testing/jenkins/JenkinsDao.java b/src/main/java/io/trygvis/esper/testing/jenkins/JenkinsDao.java index 117d91d..e94c7fd 100644 --- a/src/main/java/io/trygvis/esper/testing/jenkins/JenkinsDao.java +++ b/src/main/java/io/trygvis/esper/testing/jenkins/JenkinsDao.java @@ -12,6 +12,7 @@ import java.util.List; import static fj.data.Option.*; import static io.trygvis.esper.testing.Util.toList; import static io.trygvis.esper.testing.Util.toUuidArray; +import static io.trygvis.esper.testing.util.sql.ResultSetF.getInt; import static io.trygvis.esper.testing.util.sql.SqlOption.fromRs; import static java.lang.System.*; @@ -29,22 +30,16 @@ public class JenkinsDao { this.c = c; } - private JenkinsServerDto jenkinsServer(ResultSet rs) throws SQLException { - int i = 1; - return new JenkinsServerDto( - UUID.fromString(rs.getString(i++)), - new DateTime(rs.getTimestamp(i++).getTime()), - URI.create(rs.getString(i++)), - rs.getBoolean(i)); - } - - private List toServerList(ResultSet rs) throws SQLException { - List list = new ArrayList<>(); - while (rs.next()) { - list.add(jenkinsServer(rs)); + private SqlF jenkinsServer = new SqlF() { + public JenkinsServerDto apply(ResultSet rs) throws SQLException { + int i = 1; + return new JenkinsServerDto( + UUID.fromString(rs.getString(i++)), + new DateTime(rs.getTimestamp(i++).getTime()), + URI.create(rs.getString(i++)), + rs.getBoolean(i)); } - return list; - } + }; public static final SqlF jenkinsJob = new SqlF() { public JenkinsJobDto apply(ResultSet rs) throws SQLException { @@ -58,14 +53,6 @@ public class JenkinsDao { } }; - public List toJobList(ResultSet rs) throws SQLException { - List list = new ArrayList<>(); - while (rs.next()) { - list.add(jenkinsJob.apply(rs)); - } - return list; - } - public static final String JENKINS_BUILD = "uuid, created_date, job, file, entry_id, url, result, number, duration, timestamp, users"; public static final SqlF jenkinsBuild = new SqlF() { @@ -111,18 +98,14 @@ public class JenkinsDao { sql += " ORDER BY url"; try (PreparedStatement s = c.prepareStatement(sql)) { - return toServerList(s.executeQuery()); + return toList(s, jenkinsServer); } } - public Option selectServer(UUID uuid) throws SQLException { + public SqlOption selectServer(UUID uuid) throws SQLException { try (PreparedStatement s = c.prepareStatement("SELECT " + JENKINS_SERVER + " FROM jenkins_server WHERE uuid=?")) { s.setString(1, uuid.toString()); - ResultSet rs = s.executeQuery(); - if (!rs.next()) { - return none(); - } - return some(jenkinsServer(rs)); + return fromRs(s.executeQuery()).map(jenkinsServer); } } @@ -138,7 +121,7 @@ public class JenkinsDao { } public List selectJobsByServer(UUID server, PageRequest page) throws SQLException { - try (PreparedStatement s = c.prepareStatement("SELECT " + JENKINS_JOB + " FROM jenkins_job WHERE server=? ORDER BY created_date LIMIT ? OFFSET ?")) { + try (PreparedStatement s = c.prepareStatement("SELECT " + JENKINS_JOB + " FROM jenkins_job WHERE server=? ORDER BY created_date DESC LIMIT ? OFFSET ?")) { int i = 1; s.setString(i++, server.toString()); s.setInt(i++, page.count.orSome(10)); @@ -157,9 +140,7 @@ public class JenkinsDao { public int selectJobCountForServer(UUID uuid) throws SQLException { try (PreparedStatement s = c.prepareStatement("SELECT count(1) FROM jenkins_job WHERE server=?")) { s.setString(1, uuid.toString()); - ResultSet rs = s.executeQuery(); - rs.next(); - return rs.getInt(1); + return fromRs(s.executeQuery()).map(getInt).get(); } } @@ -192,6 +173,24 @@ public class JenkinsDao { } } + public List selectBuildByJob(UUID job, PageRequest page) throws SQLException { + try (PreparedStatement s = c.prepareStatement("SELECT " + JENKINS_BUILD + " FROM jenkins_build WHERE job=? ORDER BY created_date DESC LIMIT ? OFFSET ?")) { + int i = 1; + s.setString(i++, job.toString()); + s.setInt(i++, page.count.orSome(10)); + s.setInt(i, page.startIndex.orSome(0)); + return toList(s, jenkinsBuild); + } + } + + public int selectBuildCountByJob(UUID job) throws SQLException { + try (PreparedStatement s = c.prepareStatement("SELECT count(1) FROM jenkins_build WHERE job=?")) { + int i = 1; + s.setString(i, job.toString()); + return fromRs(s.executeQuery()).map(getInt).get(); + } + } + public UUID insertBuild(UUID job, UUID file, String entryId, URI url, String result, int number, int duration, long timestamp, UUID[] users) throws SQLException { try (PreparedStatement s = c.prepareStatement("INSERT INTO jenkins_build(" + JENKINS_BUILD + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) { UUID uuid = UUID.randomUUID(); diff --git a/src/main/java/io/trygvis/esper/testing/web/resource/AbstractResource.java b/src/main/java/io/trygvis/esper/testing/web/resource/AbstractResource.java index cddec2c..929a48a 100644 --- a/src/main/java/io/trygvis/esper/testing/web/resource/AbstractResource.java +++ b/src/main/java/io/trygvis/esper/testing/web/resource/AbstractResource.java @@ -2,6 +2,7 @@ package io.trygvis.esper.testing.web.resource; import fj.data.*; import io.trygvis.esper.testing.*; +import io.trygvis.esper.testing.util.sql.*; import javax.ws.rs.*; import javax.ws.rs.core.*; @@ -23,4 +24,14 @@ public class AbstractResource { return server.some(); } + + public T sql(DatabaseAccess.DaosCallback> callback) throws SQLException { + SqlOption server = da.inTransaction(callback); + + if(server.isNone()) { + throw new WebApplicationException(Response.Status.NOT_FOUND); + } + + return server.get(); + } } diff --git a/src/main/java/io/trygvis/esper/testing/web/resource/JenkinsResource.java b/src/main/java/io/trygvis/esper/testing/web/resource/JenkinsResource.java index 33b3f88..292be71 100644 --- a/src/main/java/io/trygvis/esper/testing/web/resource/JenkinsResource.java +++ b/src/main/java/io/trygvis/esper/testing/web/resource/JenkinsResource.java @@ -1,6 +1,5 @@ package io.trygvis.esper.testing.web.resource; -import fj.data.*; import io.trygvis.esper.testing.*; import io.trygvis.esper.testing.jenkins.*; import io.trygvis.esper.testing.util.sql.*; @@ -14,8 +13,6 @@ import java.sql.*; import java.util.*; import java.util.List; -import static fj.data.Option.*; - @Path("/resource/jenkins") public class JenkinsResource extends AbstractResource { @@ -27,11 +24,11 @@ public class JenkinsResource extends AbstractResource { @Path("/server") @Produces(MediaType.APPLICATION_JSON) public List getServers() throws Exception { - return da.inTransaction(new DatabaseAccess.DaosCallback>() { - public List run(Daos daos) throws SQLException { + return da.inTransaction(new JenkinsDaosCallback>() { + protected List run() throws SQLException { List list = new ArrayList<>(); for (JenkinsServerDto server : daos.jenkinsDao.selectServers(false)) { - list.add(getJenkinsServerJson(daos, server)); + list.add(getJenkinsServerJson.apply(server)); } return list; } @@ -44,15 +41,9 @@ public class JenkinsResource extends AbstractResource { public JenkinsServerJson getServer(@PathParam("uuid") String s) throws Exception { final UUID uuid = parseUuid(s); - return get(new DatabaseAccess.DaosCallback>() { - public Option run(final Daos daos) throws SQLException { - Option o = daos.jenkinsDao.selectServer(uuid); - - if (o.isNone()) { - return Option.none(); - } - - return some(getJenkinsServerJson(daos, o.some())); + return sql(new JenkinsDaosCallback>() { + protected SqlOption run() throws SQLException { + return daos.jenkinsDao.selectServer(uuid).map(getJenkinsServerJson); } }); } @@ -61,30 +52,41 @@ public class JenkinsResource extends AbstractResource { @Path("/job") @Produces(MediaType.APPLICATION_JSON) public List getJobs(@MagicParam(query = "server") final UUID server, @MagicParam final PageRequest page) throws Exception { - return da.inTransaction(new DatabaseAccess.DaosCallback>() { - public List run(final Daos daos) throws SQLException { + return da.inTransaction(new JenkinsDaosCallback>() { + protected List run() throws SQLException { List jobs = new ArrayList<>(); for (JenkinsJobDto job : daos.jenkinsDao.selectJobsByServer(server, page)) { - jobs.add(getJenkinsJobJson(job)); + jobs.add(getJenkinsJobJson.apply(job)); } return jobs; } }); } - private JenkinsServerJson getJenkinsServerJson(Daos daos, JenkinsServerDto server) throws SQLException { - int count = daos.jenkinsDao.selectJobCountForServer(server.uuid); - - List jobs = new ArrayList<>(); - for (JenkinsJobDto jobDto : daos.jenkinsDao.selectJobsByServer(server.uuid, PageRequest.FIRST_PAGE)) { - jobs.add(getJenkinsJobJson(jobDto)); - } - - return new JenkinsServerJson(server.uuid, server.createdDate, server.url, server.enabled, count, jobs); + @GET + @Path("/job/{uuid}") + @Produces(MediaType.APPLICATION_JSON) + public JenkinsJobJson getJob(@MagicParam final UUID uuid) throws Exception { + return sql(new JenkinsDaosCallback>() { + protected SqlOption run() throws SQLException { + return daos.jenkinsDao.selectJob(uuid).map(getJenkinsJobJsonDetail); + } + }); } - private JenkinsJobJson getJenkinsJobJson(JenkinsJobDto job) { - return new JenkinsJobJson(job.uuid, job.createdDate, job.displayName.toNull()); + @GET + @Path("/build") + @Produces(MediaType.APPLICATION_JSON) + public List getBuilds(@MagicParam(query = "job") final UUID job, @MagicParam final PageRequest page) throws Exception { + return da.inTransaction(new JenkinsDaosCallback>() { + protected List run() throws SQLException { + List builds = new ArrayList<>(); + for (JenkinsBuildDto dto : daos.jenkinsDao.selectBuildByJob(job, page)) { + builds.add(getJenkinsBuildJson.apply(dto)); + } + return builds; + } + }); } public static UUID parseUuid(String s) { @@ -94,6 +96,49 @@ public class JenkinsResource extends AbstractResource { throw new WebApplicationException(Response.Status.BAD_REQUEST); } } + + abstract class JenkinsDaosCallback implements DatabaseAccess.DaosCallback { + protected Daos daos; + + protected abstract T run() throws SQLException; + + public T run(Daos daos) throws SQLException { + this.daos = daos; + return run(); + } + + protected SqlF getJenkinsServerJson = new SqlF() { + public JenkinsServerJson apply(JenkinsServerDto server) throws SQLException { + int count = daos.jenkinsDao.selectJobCountForServer(server.uuid); + + List jobs = new ArrayList<>(); + for (JenkinsJobDto jobDto : daos.jenkinsDao.selectJobsByServer(server.uuid, PageRequest.FIRST_PAGE)) { + jobs.add(getJenkinsJobJson.apply(jobDto)); + } + + return new JenkinsServerJson(server.uuid, server.createdDate, server.url, server.enabled, count, jobs); + } + }; + + protected SqlF getJenkinsJobJson = new SqlF() { + public JenkinsJobJson apply(JenkinsJobDto job) throws SQLException { + return new JenkinsJobJson(job.uuid, job.createdDate, job.server, job.displayName.toNull()); + } + }; + + protected SqlF getJenkinsJobJsonDetail = new SqlF() { + public JenkinsJobJson apply(JenkinsJobDto job) throws SQLException { + int buildCount = daos.jenkinsDao.selectBuildCountByJob(job.uuid); + return new JenkinsJobJson(job.uuid, job.createdDate, job.server, job.displayName.toNull(), buildCount); + } + }; + + protected SqlF getJenkinsBuildJson = new SqlF() { + public JenkinsBuildJson apply(JenkinsBuildDto dto) throws SQLException { + return new JenkinsBuildJson(dto.uuid, dto.createdDate, dto.result); + } + }; + } } class JenkinsServerJson { @@ -117,11 +162,36 @@ class JenkinsServerJson { class JenkinsJobJson { public final UUID uuid; public final DateTime createdDate; + public final UUID server; public final String displayName; - JenkinsJobJson(UUID uuid, DateTime createdDate, String displayName) { + public final Integer buildCount; + + JenkinsJobJson(UUID uuid, DateTime createdDate, UUID server, String displayName) { this.uuid = uuid; this.createdDate = createdDate; + this.server = server; this.displayName = displayName; + this.buildCount = null; + } + + JenkinsJobJson(UUID uuid, DateTime createdDate, UUID server, String displayName, int buildCount) { + this.uuid = uuid; + this.createdDate = createdDate; + this.server = server; + this.displayName = displayName; + this.buildCount = buildCount; + } +} + +class JenkinsBuildJson { + public final UUID uuid; + public final DateTime createdDate; + public final String result; + + JenkinsBuildJson(UUID uuid, DateTime createdDate, String result) { + this.uuid = uuid; + this.createdDate = createdDate; + this.result = result; } } diff --git a/src/main/webapp/apps/jenkinsApp/JenkinsResources.js b/src/main/webapp/apps/jenkinsApp/JenkinsResources.js index 0026932..89f3139 100644 --- a/src/main/webapp/apps/jenkinsApp/JenkinsResources.js +++ b/src/main/webapp/apps/jenkinsApp/JenkinsResources.js @@ -15,3 +15,11 @@ function JenkinsJob($resource) { angular. module('jenkinsJob', ['ngResource']). factory('JenkinsJob', JenkinsJob); + +function JenkinsBuild($resource) { + return $resource('/resource/jenkins/build/:uuid', {uuid: '@uuid'}); +} + +angular. + module('jenkinsBuild', ['ngResource']). + factory('JenkinsBuild', JenkinsBuild); diff --git a/src/main/webapp/apps/jenkinsApp/jenkinsApp.js b/src/main/webapp/apps/jenkinsApp/jenkinsApp.js index e51c9f3..19d107d 100644 --- a/src/main/webapp/apps/jenkinsApp/jenkinsApp.js +++ b/src/main/webapp/apps/jenkinsApp/jenkinsApp.js @@ -1,14 +1,10 @@ 'use strict'; -var jenkinsApp = angular.module('jenkinsApp', ['jenkinsServer', 'jenkinsJob', 'pagingTableService']).config(function ($routeProvider) { +var jenkinsApp = angular.module('jenkinsApp', ['jenkinsServer', 'jenkinsJob', 'jenkinsBuild', 'pagingTableService']).config(function ($routeProvider) { $routeProvider. - when('/', {controller: ServerListCtrl, templateUrl: '/apps/jenkinsApp/server-list.html?noCache=' + noCache}); - $routeProvider. - when('/server/:uuid', {controller: ServerCtrl, templateUrl: '/apps/jenkinsApp/server.html?noCache=' + noCache}); -// $routeProvider.otherwise({ redirectTo: '/' }); - - // This fucks shit up -// $locationProvider.html5Mode(true); + when('/', {controller: ServerListCtrl, templateUrl: '/apps/jenkinsApp/server-list.html?noCache=' + noCache}). + when('/server/:uuid', {controller: ServerCtrl, templateUrl: '/apps/jenkinsApp/server.html?noCache=' + noCache}). + when('/job/:uuid', {controller: JobCtrl, templateUrl: '/apps/jenkinsApp/job.html?noCache=' + noCache}); }); function ServerListCtrl($scope, $location, JenkinsServer) { @@ -16,13 +12,8 @@ function ServerListCtrl($scope, $location, JenkinsServer) { $scope.servers = servers; }); - $scope.showServers = function () { - $location.path('/'); - }; - - $scope.showServer = function (uuid) { - $location.path('/server/' + uuid); - }; + $scope.showServers = function () { $location.path('/'); }; + $scope.showServer = function (uuid) { $location.path('/server/' + uuid); }; } function ServerCtrl($scope, $location, $routeParams, JenkinsServer, JenkinsJob, PagingTableService) { @@ -34,11 +25,19 @@ function ServerCtrl($scope, $location, $routeParams, JenkinsServer, JenkinsJob, $scope.jobs = PagingTableService.create($scope, PagingTableService.defaultCallback(JenkinsJob, {server: serverUuid})); - $scope.showServers = function () { - $location.path('/'); - }; + $scope.showServers = function () { $location.path('/'); }; + $scope.showJob = function (uuid) { $location.path('/job/' + uuid); }; +} + +function JobCtrl($scope, $location, $routeParams, JenkinsJob, JenkinsBuild, PagingTableService) { + var jobUuid = $routeParams.uuid; + + JenkinsJob.get({uuid: jobUuid}, function (job) { + $scope.job = job; + }); + + $scope.builds = PagingTableService.create($scope, PagingTableService.defaultCallback(JenkinsBuild, {job: jobUuid})); - $scope.showServer = function (uuid) { - $location.path('/server/' + uuid); - }; + $scope.showServers = function () { $location.path('/'); }; + $scope.showServer = function (uuid) { $location.path('/server/' + $scope.job.server); }; } diff --git a/src/main/webapp/apps/jenkinsApp/job.html b/src/main/webapp/apps/jenkinsApp/job.html new file mode 100644 index 0000000..5113d2e --- /dev/null +++ b/src/main/webapp/apps/jenkinsApp/job.html @@ -0,0 +1,59 @@ +
+ + + + + +

Overview

+ + + + + + + + + + + + +
URL{{job.displayName}}
Build count{{job.buildCount}}
+ +

Recent Builds

+ + + + + + + + + + + + + + + + + + + + +
BuildResult
{{build.createdDate | date:'medium'}}{{build.result}}
+ +
+
diff --git a/src/main/webapp/apps/jenkinsApp/server-list.html b/src/main/webapp/apps/jenkinsApp/server-list.html index f335c1f..e488186 100644 --- a/src/main/webapp/apps/jenkinsApp/server-list.html +++ b/src/main/webapp/apps/jenkinsApp/server-list.html @@ -1,27 +1,29 @@ - +
+ - + - - - - - - - - - - - - - - - -
URLEnabled
{{server.url}}{{server.enabled}} - Visit - Details -
+ + + + + + + + + + + + + + + + + +
URLEnabled
{{server.url}}{{server.enabled}}Visit +
+
diff --git a/src/main/webapp/apps/jenkinsApp/server.html b/src/main/webapp/apps/jenkinsApp/server.html index 8a784e8..03be57e 100644 --- a/src/main/webapp/apps/jenkinsApp/server.html +++ b/src/main/webapp/apps/jenkinsApp/server.html @@ -39,6 +39,7 @@ {{job.createdDate | date:'medium'}} {{job.displayName}} {{job.uuid}} + diff --git a/src/test/java/io/trygvis/esper/testing/jenkins/CreateMissingMavenModuleJobsApp.java b/src/test/java/io/trygvis/esper/testing/jenkins/CreateMissingMavenModuleJobsApp.java index 13a78d7..bdf4018 100644 --- a/src/test/java/io/trygvis/esper/testing/jenkins/CreateMissingMavenModuleJobsApp.java +++ b/src/test/java/io/trygvis/esper/testing/jenkins/CreateMissingMavenModuleJobsApp.java @@ -1,24 +1,20 @@ package io.trygvis.esper.testing.jenkins; -import java.net.URI; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.util.List; -import java.util.UUID; - +import com.jolbox.bonecp.*; import fj.*; +import fj.data.*; +import io.trygvis.esper.testing.*; import io.trygvis.esper.testing.core.db.*; -import org.apache.abdera.Abdera; -import org.codehaus.httpcache4j.cache.HTTPCache; +import io.trygvis.esper.testing.util.*; +import org.apache.abdera.*; +import org.codehaus.httpcache4j.cache.*; -import com.jolbox.bonecp.BoneCPDataSource; - -import fj.data.Option; -import io.trygvis.esper.testing.Config; -import io.trygvis.esper.testing.util.HttpClient; +import java.net.*; +import java.sql.*; +import java.util.List; +import java.util.*; -import static io.trygvis.esper.testing.jenkins.JenkinsClient.apiXml; +import static io.trygvis.esper.testing.jenkins.JenkinsClient.*; public class CreateMissingMavenModuleJobsApp { public static void main(String[] args) throws Exception { @@ -33,12 +29,11 @@ public class CreateMissingMavenModuleJobsApp { // PreparedStatement s2 = c.prepareStatement("UPDATE jenkins_job SET job_type=? WHERE uuid=?"); PreparedStatement s = c.prepareStatement("SELECT " + JenkinsDao.JENKINS_JOB + " FROM jenkins_job WHERE job_type='MAVEN_MODULE'"); - ResultSet rs = s.executeQuery(); JenkinsDao dao = new JenkinsDao(c); FileDao fileDao = new FileDao(c); - List jobs = dao.toJobList(rs); + List jobs = Util.toList(s, JenkinsDao.jenkinsJob); System.out.println("jobs.size() = " + jobs.size()); diff --git a/src/test/java/io/trygvis/esper/testing/jenkins/SetJobTypeApp.java b/src/test/java/io/trygvis/esper/testing/jenkins/SetJobTypeApp.java index f272feb..25e629c 100644 --- a/src/test/java/io/trygvis/esper/testing/jenkins/SetJobTypeApp.java +++ b/src/test/java/io/trygvis/esper/testing/jenkins/SetJobTypeApp.java @@ -1,21 +1,18 @@ package io.trygvis.esper.testing.jenkins; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.util.List; - +import com.jolbox.bonecp.*; import fj.*; -import org.apache.abdera.Abdera; -import org.codehaus.httpcache4j.cache.HTTPCache; - -import com.jolbox.bonecp.BoneCPDataSource; +import fj.data.*; +import io.trygvis.esper.testing.*; +import io.trygvis.esper.testing.util.*; +import org.apache.abdera.*; +import org.codehaus.httpcache4j.cache.*; -import fj.data.Option; -import io.trygvis.esper.testing.Config; -import io.trygvis.esper.testing.util.HttpClient; +import java.sql.*; +import java.util.List; -import static io.trygvis.esper.testing.jenkins.JenkinsClient.apiXml; +import static io.trygvis.esper.testing.jenkins.JenkinsClient.*; +import static io.trygvis.esper.testing.jenkins.JenkinsDao.*; public class SetJobTypeApp { public static void main(String[] args) throws Exception { @@ -30,11 +27,8 @@ public class SetJobTypeApp { PreparedStatement s2 = c.prepareStatement("UPDATE jenkins_job SET job_type=? WHERE uuid=?"); PreparedStatement s = c.prepareStatement("SELECT " + JenkinsDao.JENKINS_JOB + " FROM jenkins_job WHERE job_type IS NULL"); - ResultSet rs = s.executeQuery(); - - JenkinsDao dao = new JenkinsDao(c); - List jobs = dao.toJobList(rs); + List jobs = Util.toList(s, jenkinsJob); System.out.println("jobs.size() = " + jobs.size()); -- cgit v1.2.3