Integrating Apple Push notifications functionality in Scala

Recently i’ve implemented the Apple push notification functionality in our application. Its just a few lines of code and you’ll find it in action.

Go through this , one of the good blog for getting the Apple’s certificates and other required stuff ready.

(i’m being lazy i know 😉 but the above specified blog is enough i think for getting the certificate & other stuff ready)

Once you’ve private key file & certificate with you , select both of them together and export it as .p12 file. You’ll be prompted for a pass-phrase , enter the pass-phrase and export the file (Remember this pass-phrase)

Now you’ve :

1. .p12 file.
2. Pass-phrase in your mind.

Lets write the code :

A. Add this dependency in your build.sbt ( or in appropriate) file

"com.notnoop.apns" % "apns" % "0.1.6"

B. Prepare the APNS service as :

 val service = APNS.newService.withCert("APNSCertPath", "APNSCertPassword").withSandboxDestination.build

Here APNSCertPath is being referred to the above created .p12 file path & APNSCertPassword is the pass-phrase that you’ve given while exporting that .p12 file.

(Good news we’re near to be done with code 🙂 )

C. Lets create the payload (The data we want to send in the push notification)

 val payload = APNS.newPayload.alertBody("msgToSend").build

D. We can add other attributes for the things like Sound , Badge , Custom Data etc.

val payload=APNS.newPayload.alertBody("msgToSend").badge(1).sound("default").customField("myField","myFieldValue")
build

E. Lets push the notification to device.

service.push(deviceToken, payload)

And we’re done !

Go ahead. Write a test case & test it.

@Test
  def testAPNSPush {
    log info "Starting..."
    val APNSCertPath = "/home/neelkanth/Desktop/cert.p12"
    val APNSCertPassword = "**********"
    val service = APNS.newService
      .withCert(APNSCertPath, APNSCertPassword).withSandboxDestination.build
    log debug s"Build The Service........."
    val payload = APNS.newPayload.alertBody("Hello From Neelkanth Sachdeva").badge(1).sound("default").customField("name", "neel").build
    log debug s"Build The Payload........."
    val token = "<<<<<<<<<<<<<<<<<<<<<<---Device Token--->>>>>>>>>>>>>>>>>>>>>>"
    val notif = service.push(token, payload)
    log debug s"Result Received Is $notif"
  }

Cheers 🙂

Advertisements

Training on Play Framework at Scala Traits Event by Knoldus Software LLP

We had a great & successful Scala Traits Event at Hotel Regent Grand on last Saturday. I’ve presented on Play Framework. My Presentation has got three modules from basic Play learning to deploying the application. Now this fruit is here as well.

Integrating Google Drive infrastructure in Play Scala application

This blog talks about integrating the Google Drive infrastructure in our Play Scala application as like Assembla and some others. We used oauth2 in order to communicate with the Google using Access Token and Refresh Token. Let us see the process step by step.

1. Prepare the browser request URL in order to get the authorization code.

val redirectURI = "http://localhost:9000/driveAuth"

  def authenticateToGoogle = Action { implicit request =>
    val urlToRedirect = new GoogleBrowserClientRequestUrl("Client ID", redirectURI, Arrays.asList("https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/drive")).set("access_type", "offline").set("response_type", "code").build()
    Redirect(urlToRedirect)
  }

Parameters required by this URL :

ClientId : Your Google application’s client Id. Looks like xxxxxxxxxxxx.apps.googleusercontent.com
Redirect URI : The registered URI with the application.
Scopes : : Specific information type that you want to demand from user.
Access Type : Should be set as “offline”.
Response Type : Should be set as “code” as we are demanding the authorization code. This code will be exchanged for the access token and the one time refresh token.

2. When the users will hit this url , they’ll be asked to Log in and allowing the application to access of their Google Drive’s documents and the other basic information (Depends upon the scope that we’ve defined in url). Once the users have successfully authenticated their Google accounts , the authorization code will be sent to the Redirect URI specified in the browser’s request url as request’s query parameter.

3. Once you receive the authorization code over the redirect uri that you’ve specified as like above , use this code for getting the Access Token and one time Refresh Token from Google by making a POST request on https://accounts.google.com/o/oauth2/token url. Again you’ve to send the basic credentials like Client_Id , Client_Secret , Redirect_URI etc along with this request.


import com.google.api.client.googleapis.auth.oauth2.GoogleCredential
import com.google.api.client.http.FileContent
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.jackson.JacksonFactory
import com.google.api.services.drive.Drive
import com.google.api.services.drive.model.File

......................................................
......................................................

 /**
   * Google Oauth2 accessing code and exchanging it for Access & Refresh Token
   */
  def googleDriveAuthentication = Action { implicit request =>
    val code = request.queryString("code").toList(0)
    val url = "https://accounts.google.com/o/oauth2/token"
    val obj = new URL(url)
    val con = obj.openConnection().asInstanceOf[HttpsURLConnection]

    con.setRequestMethod("POST");
    con.setRequestProperty("User-Agent", USER_AGENT);
    con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");

    val urlParameters = "code=" + code + "&client_id=************.apps.googleusercontent.com&client_secret=xxxxxxxxxx&redirect_uri=http://localhost:9000/driveAuth&grant_type=authorization_code&Content-Type=application/x-www-form-urlencoded";
    con.setDoOutput(true)
    val wr = new DataOutputStream(con.getOutputStream)
    wr.writeBytes(urlParameters)
    wr.flush
    wr.close
    val in = new BufferedReader(
      new InputStreamReader(con.getInputStream))
    val response = new StringBuffer

    while (in.readLine != null) {
      response.append(in.readLine)
    }
    in.close
    Ok
}

You’ll get the following data in response.

"access_token" : "ya29.AHES6ZSyNMy0btyYrYflOPkYGEF6ijCKjCASjYoxK5CuqHPOHLDG0og",  "expires_in" : 3600,  "refresh_token" : "1/U33p2VTgqIqtll2P43x6PVen156ys0EMGcrkYW4lYuMI"

5. Extract out the access token and the refresh token from the response.

Remember Refresh token will be obtained only first time when the user will allow the access to their information. Don’t forget to save it in to your database. Next time when you’ll generate access token using this refresh token.

6. Now we are having access token so its time to set the Google credentials in order to make the Drive ready.

 val CLIENT_ID = "************.apps.googleusercontent.com"
  val CLIENT_SECRET = "****************"
  val httpTransport = new NetHttpTransport
  val jsonFactory = new JacksonFactory
  /**
   * Set Up Google App Credentials
   */
  def prepareGoogleDrive(accessToken: String): Drive = {

    //Build the Google credentials and make the Drive ready to interact
    val credential = new GoogleCredential.Builder()
      .setJsonFactory(jsonFactory)
      .setTransport(httpTransport)
      .setClientSecrets(CLIENT_ID, CLIENT_SECRET)
      .build();
    credential.setAccessToken(accessToken);
    //Create a new authorized API client
    new Drive.Builder(httpTransport, jsonFactory, credential).build()
  }

7. Now our Drive is ready. We can now upload the documents or fetch all the documents of a user’s Google drive and more depending upon the scope defined. Below is how you’ve to upload a file to Google drive and viewing the already existing files of a user.

/**
   * Upload To Google Drive
   */
  def uploadToGoogleDrive(accessToken: String, fileToUpload: java.io.File, fileName: String, contentType: String): String = {
    val service = prepareGoogleDrive(accessToken)
    //Insert a file  
    val body = new File
    body.setTitle(fileName)
    body.setDescription(fileName)
    body.setMimeType(contentType)
    val fileContent: java.io.File = fileToUpload
    val mediaContent = new FileContent(contentType, fileContent)
    //Inserting the files
    val file = service.files.insert(body, mediaContent).execute()
    file.getId

  }
  /**
   * Get All Files From Google Drive
   */

  def getAllDocumentsFromGoogleDocs(code: String): List[(String, String)] = {
    val service = prepareGoogleDrive(code)
    var result: List[File] = Nil
    val request = service.files.list

    do {
      val files = request.execute
      result ++= (files.getItems)
      request.setPageToken(files.getNextPageToken)
    } while (request.getPageToken() != null && request.getPageToken().length() > 0)

    result map {
      case a => (a.getOriginalFilename, a.getAlternateLink)
    }
  }

8. Next time when the user will Log in to the system , you’d having refresh token already of the Google account of that particular user. You can use this refresh token in order to generate the new access token for the communication with user’s Google drive. Here is how you can generate the new access token from the previously existing refresh token.

/**
   * Get Access token Using refresh Token
   */

  def getNewAccessToken(refreshToken: String):String = {
    val credentialBuilder = new GoogleCredential.Builder()
      .setTransport(httpTransport).setJsonFactory(jsonFactory)
      .setClientSecrets(CLIENT_ID, CLIENT_SECRET);

    val credential = credentialBuilder.build()
    credential.setRefreshToken(refreshToken)
    credential.refreshToken()
    credential.getAccessToken
  }

This is the pretty straightforward way of how you can communicate with the Google Drive. Thank you folks !

Quick Tip : How to make Jetty webserver listen on port 80 as a non-root user

We had a requirement to run an application on a different port which was running at port 8080 (Jetty) by default . One of our Lift application was running at port 8080 on Linux (Ubuntu 13.04 ) machine. We wanted to run it at port 80. Usually on Linux machines, port 80 is protected. Typically only the superuser root can open it and ports below 1024 can be opened only by root. Here is how we did it as a normal user ( Non-root user) :

1. Install Xinetd .

 apt-get install xinetd

2. Go to /etc/xinetd.d/ and create a new file say redirect_file and put these contents in this file

service my_redirector_80
{
 disable = no
 socket_type = stream
 protocol = tcp
 user = root
 wait = no
 port = 80
 redirect = localhost 8080
 type = UNLISTED
}

3. Restart the xinetd service as :

service xinetd restart

4. This is all you’ve to do. Now you should be able to find the application running ( which is running at port 8080 ) on port 80.

Integrating Scala Code Coverage Tool (SCCT) in Play Scala project

In my last blog i’ve elaborated the steps to integrate the JaCoCo with your Play Scala project. This time we’ll learn about how to integrate the Scala Code Coverage Tool ( SCCT ) in your Play Scala project.

Just some easy steps and you’re done with SCCT integration. Lets see it in action.

1. Add the following resolvers in your plugin.sbt file.

resolvers += Classpaths.typesafeResolver

resolvers += "scct-github-repository" at "http://mtkopone.github.com/scct/maven-repo"

2. Add this sbt plugin there as well.

addSbtPlugin("reaktor" % "sbt-scct" % "0.2-SNAPSHOT")

3 . Define a lazy val for SCCT settings in your Build.scala & include the settings as below :


  lazy val scct_settings = Defaults.defaultSettings ++ Seq(ScctPlugin.instrumentSettings: _*)
  ................
  ................

  val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA,settings = scct_settings).settings( 
  testOptions in Test := Nil
  )

   

4. We have a model object Hello.scala in app/models & its corresponding test HelloTest.scala in test/models

5. After adding these just do :

play clean compile eclipsify run

6. Now its time to have the coverage report for our tests. Run scct:test as shown below
SCCT Test Coverage

7. You’d find the test coverage report for you project in /target/scala-2.9.1/coverage-report/index.html .

Note : Open the index.html file with Firefox browser.

8. Here’s our test coverage report :
SCCT Test Coverage Report

Find the code here on Github

Integrating JaCoCo in your Play Scala project

Its always good to have a fine test coverage in any project. I am working on Play framework & this time i’ve tried to integrate the JaCoCo with my play scala project & it’s cool to have it in my project.

I am going to elaborate a few easy steps to integrate the JaCoCo in Play Scala project.

1. Add the following lines of code in your plugin.sbt file. You’ve to add the plugin dependency to your project’s plugins.sbt.

libraryDependencies ++= Seq(
 	"org.jacoco" % "org.jacoco.core" % "0.5.7.201204190339" artifacts(Artifact("org.jacoco.core", "jar", "jar")),
 	"org.jacoco" % "org.jacoco.report" % "0.5.7.201204190339" artifacts(Artifact("org.jacoco.report", "jar", "jar")))

 addSbtPlugin("de.johoop" % "jacoco4sbt" % "1.2.3")

2. Have this import in your Build.scala file.

import de.johoop.jacoco4sbt.JacocoPlugin._

3. Add the following line in your Build.scala file.

lazy val jacoco_settings = Defaults.defaultSettings ++ Seq(jacoco.settings: _*)

This line adds the jacoco settings to the variable jacoco_settings.

4. Add these settings in to your Play project in Build.scala file as

 val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA, settings = jacoco_settings).settings(
    parallelExecution in jacoco.Config := false)

parallelExecution in jacoco.Config := false makes sure that the ParallelExexution is false during testing.(Look at Point 7)

Note that we’ve a model class with name Test.scala & a test class DemoTest.scala for now.

5. That’s it. Lets run the JaCoCo with command jacoco:cover

6. You’ll find the html file with name index.html which would give you the full test report. You’ll find this file in this path /target/scala-2.9.1/jacoco/html

This is how your coverage report would look like :

null

7. You can check whether the parallel execution if false or not as

Get the CodeCoverage here