Skip to content
Browse files

fixes bug #73 (scheduled jobs support)

  • Loading branch information...
1 parent 4b4e19d commit 7801aa01c55b4ca393b0be32b58ee5bb8218f35b @mindcrime mindcrime committed Feb 4, 2012
View
146 .classpath
@@ -9,6 +9,7 @@
<classpathentry kind="src" path="test/unit"/>
<classpathentry kind="src" path="test/integration"/>
<classpathentry kind="src" path="src/groovy"/>
+ <classpathentry kind="src" path="grails-app/jobs"/>
<classpathentry kind="lib" path="lib/activation.jar"/>
<classpathentry kind="lib" path="lib/commons-math-2.1.jar"/>
<classpathentry kind="lib" path="lib/lucene-core-3.0.1.jar"/>
@@ -69,6 +70,66 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry exported="true" kind="con" path="GROOVY_SUPPORT"/>
<classpathentry kind="con" path="com.springsource.sts.grails.core.CLASSPATH_CONTAINER"/>
+ <classpathentry kind="lib" path="/usr/java/junit3.8.1/junit.jar"/>
+ <classpathentry kind="lib" path="lib/arq-2.8.7.jar"/>
+ <classpathentry kind="lib" path="lib/concurrent.jar"/>
+ <classpathentry kind="lib" path="lib/iri-0.8.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-aop-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-appclient.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-aspect-jdk50-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-common-core.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-deployers-client-spi.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-deployers-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-deployers-core-spi.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-deployers-core.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-deployment.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ejb3-common-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ejb3-core-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ejb3-ext-api.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ejb3-proxy-clustered-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ejb3-proxy-impl-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ejb3-proxy-spi-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ejb3-security-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ha-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-ha-legacy-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-iiop-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-integration.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-j2se.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-javaee.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-jsr77-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-logging-jdk.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-logging-log4j.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-logging-spi.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-main-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-mdr.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-messaging-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-remoting.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-security-spi.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-serialization.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-srp-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-system-client.jar"/>
+ <classpathentry kind="lib" path="lib/jboss-system-jmx-client.jar"/>
+ <classpathentry kind="lib" path="lib/jbosscx-client.jar"/>
+ <classpathentry kind="lib" path="lib/jbossjts-integration.jar"/>
+ <classpathentry kind="lib" path="lib/jbossjts.jar"/>
+ <classpathentry kind="lib" path="lib/jbosssx-as-client.jar"/>
+ <classpathentry kind="lib" path="lib/jbosssx-client.jar"/>
+ <classpathentry kind="lib" path="lib/jena-2.6.4.jar"/>
+ <classpathentry kind="lib" path="lib/jmx-client.jar"/>
+ <classpathentry kind="lib" path="lib/jmx-invoker-adaptor-client.jar"/>
+ <classpathentry kind="lib" path="lib/jnp-client.jar"/>
+ <classpathentry kind="lib" path="lib/log4j-1.2.16.jar"/>
+ <classpathentry kind="lib" path="lib/sample.jar"/>
+ <classpathentry kind="lib" path="lib/shiro-core-1.1.0.jar"/>
+ <classpathentry kind="lib" path="lib/shiro-web-1.1.0.jar"/>
+ <classpathentry kind="lib" path="lib/stax-api-1.0.1.jar"/>
+ <classpathentry kind="lib" path="lib/trove.jar"/>
+ <classpathentry kind="lib" path="lib/wstx-asl-3.2.9.jar"/>
+ <classpathentry kind="lib" path="lib/xercesImpl-2.9.1.jar"/>
+ <classpathentry kind="lib" path="lib/jackson-all-1.9.3.jar"/>
+ <classpathentry kind="lib" path="lib/ical4j-1.0.3.jar"/>
+ <classpathentry kind="lib" path="lib/postgresql-9.1-901.jdbc4.jar"/>
<classpathentry kind="src" path=".link_to_grails_plugins/navigation-1.1.1/grails-app/taglib">
<attributes>
<attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
@@ -104,6 +165,31 @@
<attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
</attributes>
</classpathentry>
+ <classpathentry kind="src" path=".link_to_grails_plugins/quartz-1.0-SNAPSHOT/grails-app/services">
+ <attributes>
+ <attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry excluding="BuildConfig.groovy|*DataSource.groovy|UrlMappings.groovy|Config.groovy|BootStrap.groovy|spring/resources.groovy" kind="src" path=".link_to_grails_plugins/quartz-1.0-SNAPSHOT/grails-app/conf">
+ <attributes>
+ <attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" path=".link_to_grails_plugins/quartz-1.0-SNAPSHOT/grails-app/i18n">
+ <attributes>
+ <attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" path=".link_to_grails_plugins/quartz-1.0-SNAPSHOT/src/java">
+ <attributes>
+ <attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" path=".link_to_grails_plugins/quartz-1.0-SNAPSHOT/src/groovy">
+ <attributes>
+ <attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
+ </attributes>
+ </classpathentry>
<classpathentry kind="src" path=".link_to_grails_plugins/code-coverage-1.2/grails-app/i18n">
<attributes>
<attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
@@ -139,65 +225,5 @@
<attribute name="com.springsource.sts.grails.core.SOURCE_FOLDER" value="true"/>
</attributes>
</classpathentry>
- <classpathentry kind="lib" path="/usr/java/junit3.8.1/junit.jar"/>
- <classpathentry kind="lib" path="lib/arq-2.8.7.jar"/>
- <classpathentry kind="lib" path="lib/concurrent.jar"/>
- <classpathentry kind="lib" path="lib/iri-0.8.jar"/>
- <classpathentry kind="lib" path="lib/jboss-aop-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-appclient.jar"/>
- <classpathentry kind="lib" path="lib/jboss-aspect-jdk50-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-common-core.jar"/>
- <classpathentry kind="lib" path="lib/jboss-deployers-client-spi.jar"/>
- <classpathentry kind="lib" path="lib/jboss-deployers-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-deployers-core-spi.jar"/>
- <classpathentry kind="lib" path="lib/jboss-deployers-core.jar"/>
- <classpathentry kind="lib" path="lib/jboss-deployment.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ejb3-common-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ejb3-core-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ejb3-ext-api.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ejb3-proxy-clustered-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ejb3-proxy-impl-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ejb3-proxy-spi-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ejb3-security-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ha-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-ha-legacy-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-iiop-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-integration.jar"/>
- <classpathentry kind="lib" path="lib/jboss-j2se.jar"/>
- <classpathentry kind="lib" path="lib/jboss-javaee.jar"/>
- <classpathentry kind="lib" path="lib/jboss-jsr77-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-logging-jdk.jar"/>
- <classpathentry kind="lib" path="lib/jboss-logging-log4j.jar"/>
- <classpathentry kind="lib" path="lib/jboss-logging-spi.jar"/>
- <classpathentry kind="lib" path="lib/jboss-main-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-mdr.jar"/>
- <classpathentry kind="lib" path="lib/jboss-messaging-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-remoting.jar"/>
- <classpathentry kind="lib" path="lib/jboss-security-spi.jar"/>
- <classpathentry kind="lib" path="lib/jboss-serialization.jar"/>
- <classpathentry kind="lib" path="lib/jboss-srp-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-system-client.jar"/>
- <classpathentry kind="lib" path="lib/jboss-system-jmx-client.jar"/>
- <classpathentry kind="lib" path="lib/jbosscx-client.jar"/>
- <classpathentry kind="lib" path="lib/jbossjts-integration.jar"/>
- <classpathentry kind="lib" path="lib/jbossjts.jar"/>
- <classpathentry kind="lib" path="lib/jbosssx-as-client.jar"/>
- <classpathentry kind="lib" path="lib/jbosssx-client.jar"/>
- <classpathentry kind="lib" path="lib/jena-2.6.4.jar"/>
- <classpathentry kind="lib" path="lib/jmx-client.jar"/>
- <classpathentry kind="lib" path="lib/jmx-invoker-adaptor-client.jar"/>
- <classpathentry kind="lib" path="lib/jnp-client.jar"/>
- <classpathentry kind="lib" path="lib/log4j-1.2.16.jar"/>
- <classpathentry kind="lib" path="lib/sample.jar"/>
- <classpathentry kind="lib" path="lib/shiro-core-1.1.0.jar"/>
- <classpathentry kind="lib" path="lib/shiro-web-1.1.0.jar"/>
- <classpathentry kind="lib" path="lib/stax-api-1.0.1.jar"/>
- <classpathentry kind="lib" path="lib/trove.jar"/>
- <classpathentry kind="lib" path="lib/wstx-asl-3.2.9.jar"/>
- <classpathentry kind="lib" path="lib/xercesImpl-2.9.1.jar"/>
- <classpathentry kind="lib" path="lib/jackson-all-1.9.3.jar"/>
- <classpathentry kind="lib" path="lib/ical4j-1.0.3.jar"/>
- <classpathentry kind="lib" path="lib/postgresql-9.1-901.jdbc4.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
View
6 .settings/org.eclipse.wst.common.component
@@ -10,5 +10,11 @@
<wb-resource deploy-path="/" source-path="/.link_to_grails_plugins/jms-1.2/src/java"/>
<wb-resource deploy-path="/" source-path="/.link_to_grails_plugins/jms-1.2/src/groovy"/>
<wb-resource deploy-path="/" source-path="/src/groovy"/>
+ <wb-resource deploy-path="/" source-path="/grails-app/jobs"/>
+ <wb-resource deploy-path="/" source-path="/.link_to_grails_plugins/quartz-1.0-SNAPSHOT/grails-app/services"/>
+ <wb-resource deploy-path="/" source-path="/.link_to_grails_plugins/quartz-1.0-SNAPSHOT/grails-app/conf"/>
+ <wb-resource deploy-path="/" source-path="/.link_to_grails_plugins/quartz-1.0-SNAPSHOT/grails-app/i18n"/>
+ <wb-resource deploy-path="/" source-path="/.link_to_grails_plugins/quartz-1.0-SNAPSHOT/src/java"/>
+ <wb-resource deploy-path="/" source-path="/.link_to_grails_plugins/quartz-1.0-SNAPSHOT/src/groovy"/>
</wb-module>
</project-modules>
View
26 grails-app/conf/QuartzConfig.groovy
@@ -0,0 +1,26 @@
+
+quartz {
+ autoStartup=true
+ jdbcStore=true
+ waitForJobsToCompleteOnShutdown=true
+ exposeSchedulerInRepository = false
+
+ props {
+ scheduler.instanceName="mySchedulerInstance"
+ scheduler.skipUpdateCheck=true
+ threadPool.threadCount=10
+ threadPool.class='org.quartz.simpl.SimpleThreadPool'
+ jobStore.class='org.quartz.impl.jdbcjobstore.JobStoreTX'
+ jobStore.driverDelegateClass='org.quartz.impl.jdbcjobstore.PostgreSQLDelegate'
+ jobStore.tablePrefix='QRTZ_'
+ jobStore.dataSource='myDS'
+ }
+}
+
+environments {
+ test {
+ quartz {
+ autoStartup = false
+ }
+ }
+}
View
158 grails-app/controllers/org/fogbeam/quoddy/ScheduleController.groovy
@@ -0,0 +1,158 @@
+package org.fogbeam.quoddy
+
+import java.util.List
+
+import org.codehaus.groovy.grails.commons.ArtefactHandler
+import org.codehaus.groovy.grails.commons.GrailsClass
+import org.quartz.JobDetail
+import org.quartz.SimpleTrigger
+import org.quartz.Trigger
+
+class ScheduleController {
+
+ def jobManagerService;
+
+ def index = {
+
+ // get all the "Job" Artefacts
+ GrailsClass[] artefacts = grailsApplication.getArtefacts( "Job" );
+
+
+ ArtefactHandler[] handlers = grailsApplication.getArtefactHandlers();
+
+ Class[] artefacts2 = grailsApplication.getAllArtefacts();
+
+ for( Class clazz : artefacts2 )
+ {
+ ArtefactHandler h = grailsApplication.getArtefactType( clazz );
+ }
+
+
+ [artefacts:artefacts];
+
+ }
+
+ def editSchedule =
+ {
+ log.debug( "received id: ${params.id}" );
+
+ List<String> jobGroups = jobManagerService.quartzScheduler.getJobGroupNames();
+ def triggers = null;
+ def jobGroup = null;
+ def jobName = null;
+ def jobFullName = null;
+ for( String aJobGroup : jobGroups )
+ {
+ for(String aJobName : jobManagerService.quartzScheduler.getJobNames(aJobGroup))
+ {
+ JobDetail detail = jobManagerService.quartzScheduler.getJobDetail(aJobName, aJobGroup);
+
+ if( detail.fullName.contains( params.id ))
+ {
+ triggers = jobManagerService.quartzScheduler.getTriggersOfJob(aJobName, aJobGroup);
+ jobName = aJobName;
+ jobGroup = aJobGroup;
+ jobFullName = detail.fullName;
+ }
+
+ }
+ }
+
+ [existingTriggers:triggers, jobGroup: jobGroup, jobName: jobName, jobFullName: jobFullName];
+ }
+
+ def createTrigger =
+ {
+ log.debug( "createTrigger:" );
+
+ List<String> jobGroups = jobManagerService.quartzScheduler.getJobGroupNames();
+ def triggers = null;
+ def jobGroup = null;
+ def jobName = null;
+ def jobFullName = null;
+ for( String aJobGroup : jobGroups )
+ {
+ for(String aJobName : jobManagerService.quartzScheduler.getJobNames(aJobGroup))
+ {
+
+ JobDetail detail = jobManagerService.quartzScheduler.getJobDetail(aJobName, aJobGroup);
+
+ if( detail?.fullName?.contains( params.id ))
+ {
+ triggers = jobManagerService.quartzScheduler.getTriggersOfJob(aJobName, aJobGroup);
+ jobName = aJobName;
+ jobGroup = aJobGroup;
+ jobFullName = detail.fullName;
+ }
+ else {
+ log.debug( "no job detail or no fullname found!" );
+ }
+ }
+ }
+
+ [existingTriggers:triggers, jobGroup: jobGroup, jobName: jobName, jobFullName:jobFullName];
+
+ }
+
+ def addTrigger =
+ {
+ String jobGroup = params.jobGroup;
+ String jobName = params.jobName;
+ String recurrenceInterval = params.recurrenceInterval;
+
+ log.debug( "adding Trigger for jobName: ${jobName}" );
+
+ GrailsClass jobClass = grailsApplication.getArtefact( "Job", jobName );
+
+ if( jobClass == null )
+ {
+ log.error( "Could not load GrailsClass for ${jobName}" );
+ }
+ else
+ {
+ // SimpleTrigger(String name, String group, int repeatCount, long repeatInterval)
+ Trigger trigger = new SimpleTrigger( params.triggerName, params.triggerGroup, Integer.parseInt(params.repeatCount), Long.parseLong(params.recurrenceInterval));
+ // jobClass.newInstance().schedule( Long.parseLong( recurrenceInterval ), SimpleTrigger.REPEAT_INDEFINITELY, sparams );
+ jobClass.newInstance().schedule( trigger );
+ }
+
+
+ redirect(action:"index");
+ }
+
+ def executeJobNow =
+ {
+ GrailsClass jobClass = grailsApplication.getArtefact( "Job", params.jobName );
+ jobClass.newInstance().triggerNow();
+
+ redirect(action:"index");
+ }
+
+ def editTrigger =
+ {
+ log.debug( "Edit Trigger, params: ${params}" );
+
+ Trigger theTrigger = jobManagerService.quartzScheduler.getTrigger(params.triggerName, params.triggerGroup);
+ [trigger: theTrigger];
+ }
+
+
+ def deleteTrigger =
+ {
+ jobManagerService.quartzScheduler.unscheduleJob(params.triggerName, params.triggerGroup);
+ redirect(action:"index");
+ }
+
+ def saveTrigger =
+ {
+
+ Trigger theTrigger = jobManagerService.quartzScheduler.getTrigger(params.oldTriggerName, params.oldTriggerGroup);
+ Trigger newTrigger = theTrigger.clone();
+ newTrigger.name = params.triggerName;
+ newTrigger.group = params.triggerGroup;
+ newTrigger.repeatInterval = Long.parseLong( params.recurrenceInterval );
+ jobManagerService.quartzScheduler.rescheduleJob(params.oldTriggerName, params.oldTriggerGroup, newTrigger);
+
+ redirect(action:"index");
+ }
+}
View
25 grails-app/jobs/org/fogbeam/quoddy/DummyJob.groovy
@@ -0,0 +1,25 @@
+package org.fogbeam.quoddy
+
+
+import java.text.SimpleDateFormat
+
+
+class DummyJob
+{
+
+ def group = "MyGroup";
+ def volatility = false;
+
+ static triggers = {
+ }
+
+ def execute()
+ {
+
+ Date now = new Date();
+ SimpleDateFormat sdf = SimpleDateFormat.getDateTimeInstance();
+
+ println( "TRIGGER: sending rebuild cache message: ${sdf.format( now )}" );
+
+ }
+}
View
1 grails-app/views/_rightSidebar.gsp
@@ -22,6 +22,7 @@
<li><a href="${createLink(controller:'search', action:'searchIFollow')}">Search People I Follow</a></li>
<li><a href="${createLink(controller:'user', action:'listOpenFriendRequests')}">List Pending Friend Requests</a></li>
<li><a href="${createLink(controller:'userGroup', action:'list')}">List All Groups</a></li>
+ <li><a href="${createLink(controller:'schedule', action:'index')}">Manage Scheduled Jobs</a></li>
</g:if>
</ul>
</div>
View
72 grails-app/views/layouts/admin.gsp
@@ -0,0 +1,72 @@
+<html>
+ <head>
+ <title>
+ <g:layoutTitle default="Quoddy" />
+ </title>
+ <nav:resources />
+ <link rel="stylesheet" type="text/css" href="${createLinkTo(dir:'css', file:'main.css')}" />
+ <link rel="stylesheet" type="text/css" href="${createLinkTo(dir:'css', file:'bootstrap.min.css')}" />
+ <link rel="stylesheet" type="text/css" href="/css/reset-min.css">
+ <link rel="stylesheet" type="text/css" href="/css/fonts-min.css">
+ <link rel="stylesheet" type="text/css" href="/css/grids-min.css">
+ <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.3.0/build/cssgrids/grids-min.css" />
+
+
+ <g:javascript library="jquery-1.4" />
+ <g:javascript library="jquery.timers-1.2" />
+ <g:javascript>
+ var $j = jQuery.noConflict();
+ </g:javascript>
+
+ <script type="text/javascript">
+ <g:render template="/javascript/application.js"/>
+ </script>
+
+ <g:layoutHead />
+
+ </head>
+ <body>
+
+<!-- begin customizable header -->
+
+ <div id="gbw" class="headerNavContainer">
+ <div class="headerNav">
+ <ul class="customNav">
+ <li><h1>Quoddy</h1></li>
+ <li><a href="#">Email</a></li>
+ <li><a href="${createLink(controller:'user', action:'listFriends')}">Friends</a></li>
+ <li><a href="${createLink(controller:'user', action:'listFollowers')}">Followers</a></li>
+ <li><a href="#">Reports</a></li>
+ <li><a href="#">Calendar</a></li>
+ <li><a href="#">Apps</a></li>
+ </ul>
+ <div id="gbg" class="settingsNav">
+ <a href="${createLink(controller:'user', action:'editProfile')}">Edit Profile</a>
+ </div>
+ </div>
+ </div>
+
+ <div id="header">
+ </div>
+
+ <div id="body" class="yui3-g">
+
+ <div class="yui3-u-7-12">
+
+ <!-- layout main content area -->
+ <g:layoutBody />
+
+ </div>
+
+ </div> <!-- "body" -->
+
+ <div id="footer">
+
+ <!-- TODO: replace this with a template gsp -->
+ <!-- footer -->
+ <div>
+ <center>Footer for Quoddy</center>
+ </div>
+ </div>
+ </body>
+</html>
View
23 grails-app/views/layouts/admin_dialog.gsp
@@ -3,23 +3,30 @@
<title>
<g:layoutTitle default="Quoddy:Admin:Import Users" />
</title>
- <link rel="stylesheet" type="text/css" href="/css/main.css">
+ <nav:resources />
+ <link rel="stylesheet" type="text/css" href="${createLinkTo(dir:'css', file:'main.css')}" />
+ <link rel="stylesheet" type="text/css" href="${createLinkTo(dir:'css', file:'bootstrap.min.css')}" />
<link rel="stylesheet" type="text/css" href="/css/reset-min.css">
<link rel="stylesheet" type="text/css" href="/css/fonts-min.css">
<link rel="stylesheet" type="text/css" href="/css/grids-min.css">
+ <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.3.0/build/cssgrids/grids-min.css" />
+
- <g:javascript library="prototype" />
- <g:javascript library="scriptaculous" />
- <g:javascript library="application" />
-
-
+ <g:javascript library="jquery-1.4" />
+ <g:javascript library="jquery.timers-1.2" />
<g:javascript>
-
- </g:javascript>
+ var $j = jQuery.noConflict();
+ </g:javascript>
+
+ <script type="text/javascript">
+ <g:render template="/javascript/application.js"/>
+ </script>
<g:layoutHead />
</head>
+
+ </head>
<body>
<div id="doc3" class="yui-t4">
View
1 grails-app/views/menu.gsp
@@ -30,6 +30,7 @@
<li><a href="${createLink(controller:'search', action:'searchIFollow')}">Search People I Follow</a></li>
<li><a href="${createLink(controller:'user', action:'listOpenFriendRequests')}">List Pending Friend Requests</a></li>
<li><a href="${createLink(controller:'userGroup', action:'list')}">List All Groups</a></li>
+ <li><a href="${createLink(controller:'schedule', action:'index')}">Manage Scheduled Jobs</a></li>
</g:if>
</ul>
View
90 grails-app/views/schedule/createTrigger.gsp
@@ -0,0 +1,90 @@
+<html>
+ <head>
+ <title>Welcome to Grails</title>
+ <meta name="layout" content="admin" />
+ <nav:resources />
+ </head>
+ <body>
+ <div id="bodyContent" style="height:600px;margin-left:100px;">
+ <h1 style="margin-top:7px;margin-bottom:8px;font-size:18pt;font-weight:bold;">Add New Trigger:</h1>
+ <table border="1" width="90%">
+ <tr>
+ <th>Name:</th>
+ <th>Group:</th>
+ <!-- <th>Full Name:</th> -->
+ <th>Job Name:</th>
+ <!-- <th>Full Job Name:</th> -->
+ <th>Previous Fire Time:</th>
+ <!-- <th>Last Result:</th> -->
+ <th>Next Fire Time:</th>
+ <th>Times Triggered:</th>
+ <th>Repeat Interval:</th>
+ <th>Repeat Count</th>
+ <th colspan="3">&nbsp;</th>
+ </tr>
+ <g:each in="${existingTriggers}" var="trigger">
+ <tr style="padding-top:15px;">
+ <td>${trigger.name}</td>
+ <td>${trigger.group}</td>
+ <!-- <td>${trigger.fullName}</td> -->
+ <td>${trigger.jobName}</td>
+ <!-- <td>${trigger.fullJobName}</td> -->
+ <td>${trigger.previousFireTime}</td>
+ <!-- <td>${trigger.jobDataMap?.getBooleanValue("result")}</td> -->
+ <td>${trigger.nextFireTime}</td>
+ <td>${trigger.timesTriggered}</td>
+ <td>${trigger.repeatInterval}</td>
+ <td>${trigger.repeatCount}</td>
+ <td><g:link controller="schedule" action="editTrigger" params="[jobName:jobName,jobGroup:jobGroup, triggerName:trigger.name, triggerGroup:trigger.group, fullName:trigger.fullName, fullJobName:trigger.fullJobName]">edit trigger</g:link></td>
+ <td><g:link controller="schedule" action="deleteTrigger" params="[jobName:jobName,jobGroup:jobGroup, triggerName:trigger.name, triggerGroup:trigger.group, fullName:trigger.fullName, fullJobName:trigger.fullJobName]">delete trigger</g:link></td>
+ <td><g:link controller="schedule" action="executeJobNow" params="[jobName:jobName,jobGroup:jobGroup, triggerName:trigger.name, triggerGroup:trigger.group, fullName:trigger.fullName, fullJobName:trigger.fullJobName]">execute now</g:link></td>
+ </tr>
+ </g:each>
+ </table>
+ <div style="margin-top:15px;">
+
+ <g:form controller="schedule" action="addTrigger" >
+ <g:hiddenField name="jobName" value="${jobName}"/>
+ <g:hiddenField name="jobGroup" value="${jobGroup}"/>
+ <table>
+ <tr>
+ <td>
+ <label for="triggerName">Trigger Name:</label>
+ </td>
+ <td>
+ <g:textField name="triggerName" value=""></g:textField>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label for="triggerGroup">Trigger Group:</label>
+ </td>
+ <td>
+ <g:textField name="triggerGroup" value=""></g:textField>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label for="recurrenceInterval">Recurrence Interval:</label>
+ </td>
+ <td>
+ <g:textField name="recurrenceInterval" value=""></g:textField>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label for="repeatCount">Repeat Count:</label>
+ </td>
+ <td>
+ <g:textField name="repeatCount" value=""></g:textField>
+ </td>
+ </tr>
+
+ </table>
+ <g:submitButton name="addTrigger" value="Create">Create</g:submitButton>
+ </g:form>
+
+ </div>
+ </div>
+ </body>
+</html>
View
49 grails-app/views/schedule/editSchedule.gsp
@@ -0,0 +1,49 @@
+<html>
+ <head>
+ <title>Welcome to Grails</title>
+ <meta name="layout" content="admin" />
+ <nav:resources />
+ </head>
+ <body>
+ <div id="bodyContent" style="height:600px;margin-left:100px;">
+ <h1 style="margin-top:7px;margin-bottom:8px;font-size:18pt;font-weight:bold;">Manage Job Schedule</h1>
+ <table border="1" width="90%">
+ <tr>
+ <th>Name:</th>
+ <th>Group:</th>
+ <!-- <th>Full Name:</th> -->
+ <th>Job Name:</th>
+ <!-- <th>Full Job Name:</th> -->
+ <th>Previous Fire Time:</th>
+ <!-- <th>Last Result:</th> -->
+ <th>Next Fire Time:</th>
+ <th>Times Triggered:</th>
+ <th>Repeat Interval:</th>
+ <th>Repeat Count</th>
+ <th colspan="3">&nbsp;</th>
+ </tr>
+ <g:each in="${existingTriggers}" var="trigger">
+ <tr style="padding-top:15px;">
+ <td>${trigger.name}</td>
+ <td>${trigger.group}</td>
+ <!-- <td>${trigger.fullName}</td> -->
+ <td>${trigger.jobName}</td>
+ <!-- <td>${trigger.fullJobName}</td> -->
+ <td>${trigger.previousFireTime}</td>
+ <!-- <td>${trigger.jobDataMap?.getBooleanValue("result")}</td> -->
+ <td>${trigger.nextFireTime}</td>
+ <td>${trigger.timesTriggered}</td>
+ <td>${trigger.repeatInterval}</td>
+ <td>${trigger.repeatCount}</td>
+ <td><g:link controller="schedule" action="editTrigger" params="[jobName:jobName,jobGroup:jobGroup, triggerName:trigger.name, triggerGroup:trigger.group, fullName:trigger.fullName, fullJobName:trigger.fullJobName]">edit trigger</g:link></td>
+ <td><g:link controller="schedule" action="deleteTrigger" params="[jobName:jobName,jobGroup:jobGroup, triggerName:trigger.name, triggerGroup:trigger.group, fullName:trigger.fullName, fullJobName:trigger.fullJobName]">delete trigger</g:link></td>
+ <td><g:link controller="schedule" action="executeJobNow" params="[jobName:jobName,jobGroup:jobGroup, triggerName:trigger.name, triggerGroup:trigger.group, fullName:trigger.fullName, fullJobName:trigger.fullJobName]">execute now</g:link></td>
+ </tr>
+ </g:each>
+ </table>
+ <div style="margin-top:8px;">
+ <g:link controller="schedule" id="${jobFullName}" action="createTrigger" params="[jobName:jobName,jobGroup:jobGroup]">add new trigger</g:link>
+ </div>
+ </div>
+ </body>
+</html>
View
58 grails-app/views/schedule/editTrigger.gsp
@@ -0,0 +1,58 @@
+<html>
+ <head>
+ <title>Welcome to Grails</title>
+ <meta name="layout" content="admin" />
+ <nav:resources />
+ </head>
+ <body>
+ <div id="bodyContent" style="height:600px;margin-left:100px;">
+ <h1>Edit Trigger</h1>
+ <p />
+ <div>
+ <g:form controller="schedule" action="saveTrigger" >
+ <g:hiddenField name="jobName" value="${jobName}"/>
+ <g:hiddenField name="jobGroup" value="${jobGroup}"/>
+ <g:hiddenField name="oldTriggerName" value="${trigger.name}" />
+ <g:hiddenField name="oldTriggerGroup" value="${trigger.group}" />
+ <table>
+ <tr>
+ <td>
+ <label for="triggerName">Trigger Name:</label>
+ </td>
+ <td>
+ <g:textField name="triggerName" value="${trigger.name}"></g:textField>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label for="triggerGroup">Trigger Group:</label>
+ </td>
+ <td>
+ <g:textField name="triggerGroup" value="${trigger.group}"></g:textField>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label for="recurrenceInterval">Recurrence Interval:</label>
+ </td>
+ <td>
+ <g:textField name="recurrenceInterval" value="${trigger.repeatInterval}"></g:textField>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <label for="repeatCount">Repeat Count:</label>
+ </td>
+ <td>
+ <g:textField name="repeatCount" value="${trigger.repeatCount}"></g:textField>
+ </td>
+ </tr>
+
+ </table>
+ <g:submitButton name="saveTrigger" value="Save">Save</g:submitButton>
+ </g:form>
+ </div>
+
+ </div>
+ </body>
+</html>
View
18 grails-app/views/schedule/index.gsp
@@ -0,0 +1,18 @@
+<html>
+ <head>
+ <title>Welcome to Grails</title>
+ <meta name="layout" content="admin" />
+ <nav:resources />
+ </head>
+ <body>
+ <div id="bodyContent" style="height:600px;margin-left:100px;">
+ <h1 style="margin-top:7px;font-size:18pt;font-weight:bold;">Schedule Jobs</h1>
+ <h2 style="margin-top:10px;font-size:13pt;font-weight:bold;">Available Jobs:</h2>
+ <ul>
+ <g:each var="job" in="${artefacts}">
+ <li style="padding-top:8px;"><g:link controller="schedule" action="editSchedule" id="${job.fullName}">${job.shortName}</g:link> </li>
+ </g:each>
+ </ul>
+ </div>
+ </body>
+</html>
View
177 sql/quartz_sql.sql
@@ -0,0 +1,177 @@
+-- Thanks to Patrick Lightbody for submitting this...
+--
+-- In your Quartz properties file, you'll need to set
+-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
+
+drop table qrtz_job_listeners;
+drop table qrtz_trigger_listeners;
+drop table qrtz_fired_triggers;
+DROP TABLE QRTZ_PAUSED_TRIGGER_GRPS;
+DROP TABLE QRTZ_SCHEDULER_STATE;
+DROP TABLE QRTZ_LOCKS;
+drop table qrtz_simple_triggers;
+drop table qrtz_cron_triggers;
+DROP TABLE QRTZ_BLOB_TRIGGERS;
+drop table qrtz_triggers;
+drop table qrtz_job_details;
+drop table qrtz_calendars;
+
+CREATE TABLE qrtz_job_details
+ (
+ JOB_NAME VARCHAR(200) NOT NULL,
+ JOB_GROUP VARCHAR(200) NOT NULL,
+ DESCRIPTION VARCHAR(250) NULL,
+ JOB_CLASS_NAME VARCHAR(250) NOT NULL,
+ IS_DURABLE BOOL NOT NULL,
+ IS_VOLATILE BOOL NOT NULL,
+ IS_STATEFUL BOOL NOT NULL,
+ REQUESTS_RECOVERY BOOL NOT NULL,
+ JOB_DATA BYTEA NULL,
+ PRIMARY KEY (JOB_NAME,JOB_GROUP)
+);
+
+CREATE TABLE qrtz_job_listeners
+ (
+ JOB_NAME VARCHAR(200) NOT NULL,
+ JOB_GROUP VARCHAR(200) NOT NULL,
+ JOB_LISTENER VARCHAR(200) NOT NULL,
+ PRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER),
+ FOREIGN KEY (JOB_NAME,JOB_GROUP)
+ REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
+);
+
+CREATE TABLE qrtz_triggers
+ (
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ JOB_NAME VARCHAR(200) NOT NULL,
+ JOB_GROUP VARCHAR(200) NOT NULL,
+ IS_VOLATILE BOOL NOT NULL,
+ DESCRIPTION VARCHAR(250) NULL,
+ NEXT_FIRE_TIME BIGINT NULL,
+ PREV_FIRE_TIME BIGINT NULL,
+ PRIORITY INTEGER NULL,
+ TRIGGER_STATE VARCHAR(16) NOT NULL,
+ TRIGGER_TYPE VARCHAR(8) NOT NULL,
+ START_TIME BIGINT NOT NULL,
+ END_TIME BIGINT NULL,
+ CALENDAR_NAME VARCHAR(200) NULL,
+ MISFIRE_INSTR SMALLINT NULL,
+ JOB_DATA BYTEA NULL,
+ PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
+ FOREIGN KEY (JOB_NAME,JOB_GROUP)
+ REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)
+);
+
+CREATE TABLE qrtz_simple_triggers
+ (
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ REPEAT_COUNT BIGINT NOT NULL,
+ REPEAT_INTERVAL BIGINT NOT NULL,
+ TIMES_TRIGGERED BIGINT NOT NULL,
+ PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
+ FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
+);
+
+CREATE TABLE qrtz_cron_triggers
+ (
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ CRON_EXPRESSION VARCHAR(120) NOT NULL,
+ TIME_ZONE_ID VARCHAR(80),
+ PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
+ FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
+);
+
+CREATE TABLE qrtz_blob_triggers
+ (
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ BLOB_DATA BYTEA NULL,
+ PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),
+ FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
+);
+
+CREATE TABLE qrtz_trigger_listeners
+ (
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ TRIGGER_LISTENER VARCHAR(200) NOT NULL,
+ PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER),
+ FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)
+ REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)
+);
+
+
+CREATE TABLE qrtz_calendars
+ (
+ CALENDAR_NAME VARCHAR(200) NOT NULL,
+ CALENDAR BYTEA NOT NULL,
+ PRIMARY KEY (CALENDAR_NAME)
+);
+
+
+CREATE TABLE qrtz_paused_trigger_grps
+ (
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ PRIMARY KEY (TRIGGER_GROUP)
+);
+
+CREATE TABLE qrtz_fired_triggers
+ (
+ ENTRY_ID VARCHAR(95) NOT NULL,
+ TRIGGER_NAME VARCHAR(200) NOT NULL,
+ TRIGGER_GROUP VARCHAR(200) NOT NULL,
+ IS_VOLATILE BOOL NOT NULL,
+ INSTANCE_NAME VARCHAR(200) NOT NULL,
+ FIRED_TIME BIGINT NOT NULL,
+ PRIORITY INTEGER NOT NULL,
+ STATE VARCHAR(16) NOT NULL,
+ JOB_NAME VARCHAR(200) NULL,
+ JOB_GROUP VARCHAR(200) NULL,
+ IS_STATEFUL BOOL NULL,
+ REQUESTS_RECOVERY BOOL NULL,
+ PRIMARY KEY (ENTRY_ID)
+);
+
+CREATE TABLE qrtz_scheduler_state
+ (
+ INSTANCE_NAME VARCHAR(200) NOT NULL,
+ LAST_CHECKIN_TIME BIGINT NOT NULL,
+ CHECKIN_INTERVAL BIGINT NOT NULL,
+ PRIMARY KEY (INSTANCE_NAME)
+);
+
+CREATE TABLE qrtz_locks
+ (
+ LOCK_NAME VARCHAR(40) NOT NULL,
+ PRIMARY KEY (LOCK_NAME)
+);
+
+
+INSERT INTO qrtz_locks values('TRIGGER_ACCESS');
+INSERT INTO qrtz_locks values('JOB_ACCESS');
+INSERT INTO qrtz_locks values('CALENDAR_ACCESS');
+INSERT INTO qrtz_locks values('STATE_ACCESS');
+INSERT INTO qrtz_locks values('MISFIRE_ACCESS');
+
+create index idx_qrtz_j_req_recovery on qrtz_job_details(REQUESTS_RECOVERY);
+create index idx_qrtz_t_next_fire_time on qrtz_triggers(NEXT_FIRE_TIME);
+create index idx_qrtz_t_state on qrtz_triggers(TRIGGER_STATE);
+create index idx_qrtz_t_nft_st on qrtz_triggers(NEXT_FIRE_TIME,TRIGGER_STATE);
+create index idx_qrtz_t_volatile on qrtz_triggers(IS_VOLATILE);
+create index idx_qrtz_ft_trig_name on qrtz_fired_triggers(TRIGGER_NAME);
+create index idx_qrtz_ft_trig_group on qrtz_fired_triggers(TRIGGER_GROUP);
+create index idx_qrtz_ft_trig_nm_gp on qrtz_fired_triggers(TRIGGER_NAME,TRIGGER_GROUP);
+create index idx_qrtz_ft_trig_volatile on qrtz_fired_triggers(IS_VOLATILE);
+create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(INSTANCE_NAME);
+create index idx_qrtz_ft_job_name on qrtz_fired_triggers(JOB_NAME);
+create index idx_qrtz_ft_job_group on qrtz_fired_triggers(JOB_GROUP);
+create index idx_qrtz_ft_job_stateful on qrtz_fired_triggers(IS_STATEFUL);
+create index idx_qrtz_ft_job_req_recovery on qrtz_fired_triggers(REQUESTS_RECOVERY);
+
+commit;

0 comments on commit 7801aa0

Please sign in to comment.
Something went wrong with that request. Please try again.