Thursday, February 7, 2013

[Github / Maven] Maven repository using GitHub

This simple post is a reminder on how to create a Maven2 repository and use it with Maven in a "pom.xml" file or in Java Play!.

The first step is to create a GitHub Repository (it will be named "maven2").

Then reproduce the folder structure of a Maven Repository, as I did in my "Maven2" repo (https://github.com/enreeco/maven2).

For instance, given this artifact (jar):

<groupId>com.rubenlaguna</groupId>
  <artifactId>evernote-api</artifactId>
  <name>Official Evernote API</name>
  <version>1.22</version>

Create these folders:

./com
     ./com/rubenlaguna
     ./com/rubenlaguna/evernote-api
     ./com/rubenlaguna/evernote-api/1.22
     ./com/rubenlaguna/evernote-api/1.22/evernote-api-1.22.jar
     ./com/rubenlaguna/evernote-api/1.22/evernote-api-1.22.pom

Now you have a pubblicly accessible Maven2 repository at https://github.com/[username]/[repoName]/raw/master/ (in my case https://github.com/enreeco/maven2/raw/master/).

To consume it in your projects, just add this lines in the "pom.xml" file of your project:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.echoservice</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>echoservlet</artifactId>
    <repositories>
    <repository>
      <id>myRepository</id>
      <url>https://github.com/enreeco/maven2/raw/master/</url>
    </repository>
    </repositories>
    <dependencies>
 . . .
 </depencencies>
 . . .
</project>

To integrate the maven repo in a Java Play! project (necessary if you're messing with Heroku), take the "/prject/Build.scala" file and add those lines:

import sbt._
import Keys._
import PlayProject._

object ApplicationBuild extends Build {

    val appName         = "evernote-integration"
    val appVersion      = "0.1"

    val appDependencies = Seq(
      "com.rubenlaguna" % "evernote-api" % "1.22", //Evernote Thrift Library
      "com.rubenlaguna" % "libthrift" % "1.0-SNAPSHOT",//Thrift core library
      "postgresql" % "postgresql" % "9.1-901.jdbc4", //Postgres
      "org.apache.httpcomponents" % "fluent-hc" % "4.2.1" //Apache HTTP client
    )

    val main = PlayProject(appName, appVersion, appDependencies, mainLang = JAVA).settings(
     resolvers+= "personal maven repo" at "https://github.com/enreeco/maven2/raw/master/"
    )

}

Maven will search for the selected jars in the default locations, but when it's not finding anything it will search for your personal resolvers.

Tuesday, February 5, 2013

[Visualforce / Tip] Always add a <apex:pagemessages/> tag

Always add <apex:pagemessages/> at the beginning of your VF page to see if there are errors in loading/submitting VF page.
If something underneath the Visuarlfoce is wrong, you don't see anything (no clear log at least)!

I was using the automatic SOQL generation of the "Object__c" standard controller, and to do this I usually use (well, I used to do it in the past, now I only use a series of "{!field}" in a hidden <apex:outputPannel>):

     <apex:inputHidden value="{!Object__c.CreatedDate}" />
     <apex:commandButton value="Do something" action="{!doSomething}"/>

This is clearly a blasphemy,because you cannot set with input hidden a "created date" field, but as I hadn't wrote this piece of code myself, I didn't see it immediatly.

Result was that commandLink/ButtonLink was not working, no log provided (exception made for the page load's initialization debug log), everithing I did made the button simply reloading the page without a real postback.

Using a simple <apex:pagemessages/> I saw the error and manage to know what was the problem.

Wednesday, January 30, 2013

[Apex / JavaScript] What is @RemoteAction? Baby don't hurt me, don't hurt me, no more!

2 hours to find out why @RemoteAction was hurting me.
This is related to Cloudspoke's challenge POC - Bootstrap Visualforce Pages (which I haven't submitted neither).

This is the controller:

@RemoteAction
    public static List queryContacts(List filters, String orderBy) {
    ...
    }

And this is the piece of javascript:

  var orderBy;
  var filters = [];
  function searchContacts()
  {
   var ob = orderBy;
   Visualforce.remoting.Manager.invokeAction(
              '{!$RemoteAction.MyPageController.queryContacts}',filters,ob,
              function(result, event){
               
                  if (event.status) {
                   
                   //result has the List of contacts
                   var contacts = result;
                   console.log(contacts);
                  } else if (event.type === 'exception') {
                       alert(event.message);
                  } else {
                    alert(result+ ' '+event.message);
                  }
              }, 
              {escape: true});
  }
It keeps sayng:
Visualforce Remoting Exception: Method 'queryContacts' not found on controller CSChallenge.MyPageController. Check spelling, method exists, and/or method is RemoteAction annotated.

The problem is the javascript variable "orderBy" that is "undefined"!!

By initializing it with:

     var orderBy = '';

@RemoteAction go smoothly.



Courtesy of Doombringer

Friday, January 25, 2013

[Salesforce / Canvas] Set up a minimum Canvas App (Java style)

This new post is about setting up a Force.com Canvas App and doing beautiful things with it. It comes from an old challenge I won (see Cloudspokes.com blog post), evenif in that case I used Javascript to get the session infos.

What is a Canvas App? In simple words it is a way to integrate external custom web application into Force.com platform, with simplified authorization process.
There are two ways of authentication:
  • OAuth 2.0 (GET)
  • Signed Request (POST)
I'm going to use the last method.

The first thing you have to do is creating a new "Connected App" in Setup->App Setup->Create->Apps->Connected Apps and press the "New" button.

Now set the mandatory fields:
  • Name: yuor application name
  • Contact email: your email
  • Callback URL: this is the callback URL used in the OAuth process. Simply set with the app URL
  • Selected OAuth Scopes: permissions associated to the injected session informations
  • Force.com Canvas: yes it is
  • Canvas App URL: endpoint of your app
  • Access method: Signed Request (POST)

For the sake of testing, you can set "http://localhost[:port]" as the endpoint.

Here is my configuration:



If you click in the "Chatter" tab you now see the new app:


The second step is to host a local web app.
To simplify your play here is a simple Java Play! Application that integrates with Force.com Canvas:

https://github.com/enreeco/CanvasApp-Base

To run the app simply follow my previous post [Java Play! / Heroku] Setup Java Play! + Heroku + Eclipse, for the Play part (if you want you can also use Heroku and configure the whole thing to use Heroku, but it can be a bit frustrating when developing, due to the loss of time in deploying).

How it works?

Salesforce call your app making a POST request, sending a "signed_request" parameter that is a big base64 encoded String in which all session infos are stored. This is an example:

jCblE7oIsZanRIeshRkJxtx2Dk1tS2tP3GWL0Yf1o+s=.eyJjb250ZXh0Ijp7InVzZXIiOn QiOmZhbHNlLCJjdXJyZW5jeUlzb0NvZGUiOiJFVVIifSwibGlua3MiOnsiZW50ZXJwcmlzZVVybCI6Ii 9zZXJ2aWNlcy9Tb2FwL2MvMjYuMC8wMERpMDAwMDAwMEg0bXUiLCJtZXRhZGF0YVVybCI6Ii9zZXJ2aW Nlcy9Tb2FwL20vMjYuMC8wMERpMDAwMDAwMEg0bXUiLCJwYXJ0bmVyVXJsIjoiL3NlcnZpY2VzL1NvYX IsImZ1bGxOYW1lIjoiQWRt ..... wiY2xpZW50SWQiOiIzTVZHOUEya04zQm4xN2h2Vn Uuc2FsZXNmb3JjZS5jb20ifQ==

Using the App Consumer Secret (red circle in the first pic) the Java Salesforce Framework SDK decodes this response and verify that it isn't tamped with.
The SDK can be found here, but it has been included in the CanvasApp-Base github under the "com.salesforce.canvas" package.

N.B. I've made some modification to the SignedRequest class (it appears that my own libraries have a new version and the org.apache.commons.codec.binary.Base64 class has different constructors than the one used in the SDK...so if you have problems just replace this class with the one provided by Salesforce).
The Consumer Secret is stored in the "application.conf" file, in the first lines:
     # Force.com User Secret
     canvas.consumer.secret = XXXXXXXX
This value is accessed through the AppProperties class.

This is the result:

The app uses sessions to store Canvas session info, so if you reload the page:

The application now has a valid Session Id that can be used, accordingly to the App Access Level, to work with Salesforce (from queries to metadata describes).

The core of this web app is the "Application.index()" method that stores the logic of the Signed Request handling:
package controllers;

import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;

import com.salesforce.canvas.CanvasRequest;
import com.salesforce.canvas.SignedRequest;

public class Application extends Controller {

 public static Result index() {

  String message = "";
  CanvasRequest canvasInfo = AppProperties.getSessionCanvasRequest(Controller.session());
  if(canvasInfo != null)
  {
   message += "Hi <b>"+canvasInfo.getContext().getUserContext().getUserName()+"</b>! Canvas Session Info has already been given. Enjoy Canvas App!";
  }
  else
  {
   message += "Canvas App Session info not already set.";
   if(request().method()== "POST")
   {
    message += "Incoming POST request...";
    
    //this is the post info got from Force.com POST request
    String[] signedRequest = request().body().asFormUrlEncoded().get("signed_request");
    
    if(signedRequest!=null)
    {
     System.out.println("Request: "+signedRequest[0]);
     try
     {
      canvasInfo = SignedRequest.verifyAndDecode(signedRequest[0], AppProperties.CANVAS_CONSUMER_SECRET);
      AppProperties.setSessionCanvasRequest(canvasInfo,Controller.session());
      message += "Hi <b>"+canvasInfo.getContext().getUserContext().getUserName()+"</b>! Canvas Session Info has just been correctly given. Enjoy Canvas App!";
     }
     catch(Exception e)
     {
      e.printStackTrace();
      message += "Error occurred (see log): "+e.getLocalizedMessage();
     }
    }
    else
    {
     message += "No session info provided.";
    }
   }
  }
  return ok(index.render(message));
 }

}
And this is the "routes" file:
  GET      /                   controllers.Application.index()
  POST     /                   controllers.Application.index()
The "Application.index()" method serves both GET/POST requests.
Finally this is what happens if you access the page using a simple GET request outside Canvas:

That's all.

Tuesday, January 22, 2013

[APEX] Strange automatic casting error from String to ID

Developing some APEX for a customer, I saw this error:
System.StringException: Invalid id: -1

I checked the code and it was something like this:
     if(aString == anSObject.Id){
          ...
     }
So a String object cannot be compared to an ID type if the first is not an ID?
I switched the members:
     if(anSObject.Id == aString ){
          ...
     }
And no error is thrown.

In my experience it is a strange behavior, because I would have expected that the ID field whould have been casted to String (being the second operand) rather then the String object been casted to ID type...but maybe my whole life is a lie!!

Monday, January 21, 2013

[Java Play! / Heroku] Setup Java Play! + Heroku + Eclipse

I'm not a very good developer, I have to admit it.
I always forget, if I don't "play HTML" for a while, how to define a CSS style class, so you can imagine what kind of memory I have (the worst kind), and what kind of problems I have to set an environment to make a new project, if that implies that I have to follow more than 3 steps!.
This post is dedicated to myself of the next month, and I want to show me how to set up a Java Play! Proejct using Heroku and Eclipse, and some other little things.

First, create a new Play! project:
 $ play new my-new-app
              _            _
  _ __ | | __ _ _  _| |
 | '_ \| |/ _' | || |_|
 |  __/|_|\____|\__ (_)
 |_|            |__/

 play! 2.0.3, http://www.playframework.org

 The new application will be created in \playTest\my-new-app

 What is the application name?
 > my-new-app

 Which template do you want to use for this new application?

   1 - Create a simple Scala application
   2 - Create a simple Java application
   3 - Create an empty project

 > 2

 OK, application my-new-app is created.

 Have fun!

Now you have a simple Java Play! project (with a simple controller that says that your new application is ready.
The next step is to tell Heroku that your application is a Play application, by creating the /conf/dependencies.yml

 # Application dependencies

 require:
  - play 2.0.3

And that this application will be a web application (that needs the "play run" script) with the file Procfile ( in the root of the app, and without extension):

 web:    play run --http.port=$PORT $PLAY_OPTS

Now it's time to create a new GIT local repository (that will be pushed to Heroku):
   $ cd my-new-app
   $ git init
   $ git add .
   $ git commit -m "init"

Now it's time of Heroku.
You have to install the Heroku toolbelt (go here for instructions): if you have troubles with SSH keys follow this article).
Create a new Heroku application (it will be available on "http://my-new-app.herokuapp.com"):
   $ heroku create my-new-app

And push your local repository to git:
   $ git push heroku master
   

To open the app directly from the command line (via the browser)
       $ heroku open

If you don't like the name of your Heroku application, simply login to Heroku and change it in the preference panel.

Now install the Eclipse Heroku plugin (see details here).

If you need to set a specific GIT directory (the place where GIT, and Heroku, projects are stored in your local filesystem):
Import your Heroku project using the plugin just installed (Import... -> Heroku application): the project is not properly a Java project (packages are not highligthed with the usual icon, for example). To do this digit:
       $ play ecplipsify
Refresh the project on Eclipse and you see that now the project is correctly "divided" into packages.

To run the project locally, just use play run (http://localhost:9000)).

I haven't found a way to automatically compile the Play project in eclipse, so if I add a new Scala HTML template, I "eclipsify" one more time, to have a reference to the new view classes on Eclipse (the view.html.* classes created from the HTML files). This is also helpfull if you add new referenced libraries (I'll explain how to do this using GitHub in the next article).


Now that you are ready, it's the final countdown for your new killer app!

Thursday, January 17, 2013

[VisualForce] Block Auto Focus on DatePicker

This little post is born to remember how to avoid auto focus on Visualforce page of a DatePicker field, in case it is the first "focusable" field in the page:
 
     //avoid autofocus on date pickers
     function setFocusOnLoad() {}

This is something I have found online some weeks ago, but I can't remember the original post. So if you claim the paternity of this fix, I'll be glad to add a reference link.