Showing posts with label google. Show all posts
Showing posts with label google. Show all posts

Friday, September 9, 2011

Inject instances in Quartz jobs with Google Guice

This post explains how to use Quartz 2 with Google Guice. Before you read any further, I assume you have some basic understanding about Guice and Quartz 2, and what problems they solve.

Normally, Quartz will instantiate job classes itself. You only need to supply the job class, so Quartz knows which class to instantiate when a job is ready to be executed. The job itself is pretty hidden (encapsulated) by Quartz.

In some cases, you want to let Google Guice inject references of (singleton) objects to the job. Such as a Data Access Object, so the job can access or store data.

The solution is to supply our own job factory to the Quartz class that is responsible for job instantiation. Our factory will use Guice to create instances for Quartz to use.

package com.javaeenotes.guicequartz;

import org.quartz.Job;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;

import com.google.inject.Inject;
import com.google.inject.Injector;

public class MyJobFactory implements JobFactory {

    @Inject
    private Injector injector;


    @Override
    public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler)
            throws SchedulerException {

        return (Job) injector.getInstance(
            bundle.getJobDetail().getJobClass());
    }
}
To complete this example, we need an example DAO class, and a Quartz job class that will hold the injected DAO object.
package com.javaeenotes;

public interface Dao {
    public abstract String getData();
}
package com.javaeenotes;

import com.google.inject.Singleton;

@Singleton
public class DaoImpl implements Dao {

  @Override
  public String getData() {
    return "Data from DAO.";
  }
}
package com.javaeenotes;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import com.google.inject.Inject;

public class MyJob implements Job {

  @Inject
  private Dao dao;


  @Override
  public void execute(JobExecutionContext context)
        throws JobExecutionException {

    System.out.println(dao.getData());
  }
}
Now, we need a Guice module that defines and maps the factory and DAO classes.
package com.javaeenotes;

import org.quartz.spi.JobFactory;
import com.google.inject.AbstractModule;

public class MyModule extends AbstractModule {

  @Override
  protected void configure() {

    bind(JobFactory.class).to(MyJobFactory.class);
    bind(Dao.class).to(DaoImpl.class);
  }
}
Finally, a Main class to demonstrate the application:
package com.javaeenotes;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

import com.google.inject.Guice;
import com.google.inject.Injector;

public class Main {

  public void run() {

    // The Guice injector used to create instances.
    Injector injector = Guice.createInjector(new MyModule());

    // Object that contains the job class.
    JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
            .withIdentity("jobId", "jobGroup").build();

    // Create the trigger that will instantiate and execute the job.
    // Execute the job with a 3 seconds interval.
    Trigger trigger = TriggerBuilder
            .newTrigger()
            .withIdentity("triggerId")
            .withSchedule(
                    SimpleScheduleBuilder.simpleSchedule()
                            .withIntervalInSeconds(3).repeatForever())
            .build();

    try {
      // Retrieve the Quartz scheduler to schedule the job.
      SchedulerFactory schedulerFactory = new StdSchedulerFactory();
      Scheduler scheduler = schedulerFactory.getScheduler();

      // Here we tell the Quartz scheduler to use our factory.
      scheduler.setJobFactory(injector.getInstance(MyJobFactory.class));
      scheduler.scheduleJob(jobDetail, trigger);

      // Start the scheduler.
      scheduler.start();
    } catch (SchedulerException e) {
      e.printStackTrace();
    }

    try {
      Thread.sleep(10000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }


  public static void main(String[] args) {
    new Main().run();
  }
}
This will output the following every 3 seconds:
Data from DAO.

Installation of Quartz 2 and Google Guice

If you use Maven 2 for your project, you can install both frameworks by simply adding the following configuration to your pom.xml file.

  org.quartz-scheduler
  quartz
  2.0.2



  com.google.inject
  guice
  3.0

Tuesday, April 13, 2010

Using JavaMail API with Glassfish and GMail

In this post, I'll show you how to configure JavaMail to use the SMTP server of GMail in Glassfish. This way, you avoid hardcoding server addresses in your application and make your application more portable. It also minimalizes the amount of "plumping" code.

Setup Glassfish

First, fire up the admin screen of Glassfish and click on JavaMail Sessions. Then create a new session configuration by clicking "new".

Make sure the following fields are filled in:

  • JNDI name: mail/<name>
  • Mail Host: smtp.gmail.com
  • Default User: <email>
  • Default Return Address: <email>

The JNDI name must be prefixed with "mail/". Use your GMail email address in last two fields.

Skip the Advanced settings and create additional properties at the bottom of the screen:

  • mail.smtp.socketFactory.port: 465
  • mail.smtp.port: 465
  • mail.smtp.socketFactory.fallback: false
  • mail.smtp.auth: true
  • mail.smtp.password: <gmail_password>
  • mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory

Use your valid GMail password in the password field. Save, and your configuration is ready for use.

Example client to send email with attachments

Next, we create a client to use the newly created JavaMail service in Glassfish. Before we can do that, we need the application server libraries: appserv-rt.jar and javaee.jar. You can find them in the lib directory of your Glassfish installation. Make sure all the libraries are in your build/class-path.

If you still get unresolved classes related to JavaMail, then you might also need the JavaMail libraries, which you can download here.

The example client below builds an email with three attachments from three different sources, and sends the email to two recipients. You have to use MIME-types to indicate the type of attachments. Save the code below as Main.java, compile, and run!

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.mail.util.ByteArrayDataSource;
import javax.naming.InitialContext;

public class Main {

public void runTest() throws Exception {
InitialContext ctx = new InitialContext();
Session session =
(Session) ctx.lookup("mail/<name>");
// Or by injection.
//@Resource(name = "mail/<name>")
//private Session session;

// Create email and headers.
Message msg = new MimeMessage(session);
msg.setSubject("My Subject");
msg.setRecipient(RecipientType.TO,
new InternetAddress(
"tony@email.com",
"Tony"));
msg.setRecipient(RecipientType.CC,
new InternetAddress(
"michelle@email.com",
"Michelle"));
msg.setFrom(new InternetAddress(
"jack@email.com",
"Jack"));

// Body text.
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText("Here are the files.");

// Multipart message.
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);

// Attachment file from string.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README1.txt");
messageBodyPart.setContent(new String(
"file 1 content"),
"text/plain");
multipart.addBodyPart(messageBodyPart);

// Attachment file from file.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README2.txt");
DataSource src = new FileDataSource("file.txt");
messageBodyPart.setDataHandler(new DataHandler(src));
multipart.addBodyPart(messageBodyPart);

// Attachment file from byte array.
messageBodyPart = new MimeBodyPart();
messageBodyPart.setFileName("README3.txt");
src = new ByteArrayDataSource(
"file 3 content".getBytes(),
"text/plain");
messageBodyPart.setDataHandler(new DataHandler(src));
multipart.addBodyPart(messageBodyPart);

// Add multipart message to email.
msg.setContent(multipart);

// Send email.
Transport.send(msg);
}

public static void main(String[] args) {
Main cli = new Main();
try {
cli.runTest();
} catch (Exception e) {
e.printStackTrace();
}
}
}

Wednesday, March 17, 2010

Google Maps API

As a joke, I used Google Maps on the company's intranet to show where I was in real-time. This blog post will show you how it's done with the Google Maps API V3. The complete documentation of the API can be found here.

With Google Maps API you can create custom Google Maps applications that can include:

  • Custom overlays
  • Geocoding (translating place names to world coordinates and plot them or other way around)
  • Showing user photos
  • Street view
  • Plotting directions to a coordinate

First, create or use an existing HTML-page to include the following lines of code in the HTML-header:

<meta name="viewport"
content="initial-scale=1.0,
user-scalable=no" />
<script type=\"text/javascript\"
src="http://maps.google.com/maps/api/js?sensor=false"></script>

This will enable us to use the Google Map API. The first line specifies that the map should be displayed full-screen and that the user is not allowed to be resize the map. The second line loads the API. The sensor parameter is set to false, because we don't have a sensor to track the user's current location.

Second we create the initialization code in JavaScript. This fragment will load and draw the map. You can put the code in the HTML-header or in a separate file. The code is explained as comments.

<script type="text/javascript">

function initialize() {
// Our location.
var latlng = new google.maps.LatLng(51.999018,4.374168);

// Map display options.
var myOptions = {
zoom: 15,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};

// The map object, which has to displayed in the div with
// id="map_canvas".
var map = new google.maps.Map(
document.getElementById("map_canvas"),
myOptions
);

// This is the URL to a small picture of me, which is used
// as marker on the map.
var myPicture = 'me.jpg';

// Create the Marker object to be drawn on the map.
// Use the coordinates and picture defined earlier.
var chengMarker = new google.maps.Marker({
position: latlng,
map: map,
icon: myPicture
});

// Only display the whole map during office hours
// to increase realism.
var d = new Date();
if (d.getHours() < 10 || d.getHours() > 18) {
var m = document.getElementById('map_canvas');
//m.style.display = 'none';
}
}

</script>

Finally, we create a <div> with id="map_canvas" that will contain the map. Don't forget to put the initialization function in the onload-attribute, so the browser will initialize and draw the map when the page is fully loaded.

<body onload="initialize()">
<div id="map_canvas" style="width: 600px; height: 250px"></div>
</body>