Creating the RMI Client

You need to create a client that can invoke methods on the remote Quartz Scheduler. The client will communicate with the RMI Registry, locate the remote Scheduler object, and will then be capable of invoking methods on it. This includes methods to pause and stop the Scheduler, schedule and unschedule jobs, and perform all other methods that are available to remote clients.

Configuring the Quartz RMI Client

As with the server in Table 9.1, Table 9.2 lists all of the properties that must be set for the Quartz RMI client. Two of these properties must be set for both the server and the client.

Table 9.2. The Quartz RMI Properties Necessary for the Client

Property

Default

org.quartz.scheduler.rmi.registryHost

localhost

Notes: This is the host at which the RMI Registry is running.

org.quartz.scheduler.rmi.registryPort

1099

Notes: This is the port on which the RMI Registry is listening (usually 1099).

org.quartz.scheduler.rmi.proxy

false

Notes: If you want to connect to a remotely served scheduler, set the org.quartz.scheduler.rmi.proxy flag to true. You must also then specify a host and port for the RMI Registry process.

For the client to locate the server object, it needs to know where the RMI Registry is running so that it can look up the object. The org.quartz.scheduler.rmi.registryHost and org.quartz.scheduler.rmi.registryPort should be the host and port of where the RMI Registry is running. If you configured the Quartz RMI server to start the Registry automatically, the RMI Registry is running on the same box as the RMI server.

Because you want the client to contact the remote Scheduler to schedule jobs, you need to set the property org.quartz.scheduler.rmi.proxy to true.

Listing 9.3 shows an example quartz.properties file that you can include with the RMI client to communicate with the server.

Listing 9.3. An Example quartz.properties File for Use with a Quartz RMI Client

#============================================================= # Configure Main Scheduler Properties #============================================================= org.quartz.scheduler.instanceName = RMIScheduler #org.quartz.scheduler.instanceId = AUTO #============================================================== #Configure RMI Properties #============================================================== org.quartz.scheduler.rmi.registryHost=localhost org.quartz.scheduler.rmi.registryPort=1099 org.quartz.scheduler.rmi.proxy= true

Other than the three RMI properties, you've seen many example quartz.properties file like the one in Listed 9.3.

Client and Server Instance Names Must Match

The values for the property org.quartz.scheduler.instanceName in both the RMI client and server must match. Otherwise, the client will not be capable of looking up the server object from the Registry, and you'll receive an exception that the client could not get a handle to the remote Scheduler.

 

Creating the Quartz RMI Client Class

When you have the properties file for the client configured, you need to build a client Java class that will get a handle to the remote Scheduler and do something with it. There's not much to creating this class, but just as with the server class, we changed the quartz.properties file to be called client.properties and told the client to load the properties from this file. Again, this is done just to help us remember where the properties are coming from and to avoid any confusion. Other than this change, you've seen the code in Listing 9.4 many times before throughout the examples in previous chapters.

Listing 9.4. An Example Quartz RMI Client That Schedules a Job with a Remote Scheduler

package org.cavaness.quartzbook.chapter9; import java.util.Date; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.CronTrigger; import org.quartz.JobDataMap; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.impl.StdSchedulerFactory; public class RMITestClient { public void run() throws Exception { Log log = LogFactory.getLog(RMITestClient.class); // Use this properties file instead of quartz.properties System.setProperty("org.quartz.properties", "client.properties"); // Get a reference to the remote scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // Define the job to add JobDetail job = new JobDetail("remotelyAddedJob", "default", SimpleJob.class); JobDataMap map = new JobDataMap(); map.put("msg", "Your remotely added job has executed!"); job.setJobDataMap(map); CronTrigger trigger = new CronTrigger("remotelyAddedTrigger", "default", "remotelyAddedJob", "default", new Date(), null, "/5 * * ? * *"); // schedule the remote job scheduler.scheduleJob(job, trigger); log.info("Remote job scheduled."); } public static void main(String[] args) throws Exception { RMITestClient example = new RMITestClient(); example.run(); } }

An interesting observation that seems almost magical is that we didn't have to tell the factory that we wanted a remote Scheduler. The factory determined this from the client.properties file that we told it to load. Specifically, setting this RMI property caused the factory to create a remote Scheduler:

org.quartz.scheduler.rmi.proxy = true

The following is a fragment of code from the StdSchedulerFactory that determines that the client wants to connect to a remote Scheduler:

if (rmiProxy) { if (autoId) schedInstId = DEFAULT_INSTANCE_ID; schedCtxt = new SchedulingContext(); schedCtxt.setInstanceId(schedInstId); String uid = QuartzSchedulerResources.getUniqueIdentifier( schedName, schedInstId); RemoteScheduler remoteScheduler = new RemoteScheduler(schedCtxt, uid, rmiHost, rmiPort); schedRep.bind(remoteScheduler); return remoteScheduler; }

The fragment takes place in the instantiate() method on the StdSchedulerFactory. In this fragment, the factory checks to see if the rmiProxy was set to TRue, which it is for the client. If it is true, a new instance of RemoteScheduler is instantiated and returned. This is why our client didn't have to do anything special. The Scheduler instance that is returned to our client is really an instance of RemoteScheduler, but RemoteScheduler implements the Scheduler interface, so the client code is none the wiser.

Testing the RMI Server and Client

Категории