Heroku – Deploy Java App with Yeoman scaffold-ed client

I have a Java application configured with Maven. I have all my model and web services in this application (backend). In a Java app normally you would have your web client code in src/main/webapp (frontend). I scaffold-ed the client application with yeoman, so it uses grunt to build and bower to manage dependencies. Great! well, not so much, it runs perfectly in my local environment (I can run bower install, then grunt build and it would generate a «dist» folder with all my sources compiled and minified) but it doesn’t work on heroku’s platform.

The problem is heroku detects my app only as Java application so it doesn’t run bower install nor grunt build.

I tried to use heroku-buildpack-multi with some issues, I even created my own patched version that allows to specify a base path for each buildpack. With that I can push to heroku and it runs mvn package and then npm install for the node buildpack. I’ve added a postinstall script to run both bower install and grunt build, which in turn you need to add as dependencies in your package.json.

{
  "name": "webapp",
  "version": "0.0.0",
  "dependencies": {
    "grunt": "^0.4.1",
    "grunt-cli": "~0.1.13",
    "bower": "~1.3.9",
    "grunt-autoprefixer": "^0.7.3",
    "grunt-concurrent": "^0.5.0",
    "grunt-contrib-clean": "^0.5.0",
    "grunt-contrib-compass": "^0.7.2",
    "grunt-contrib-concat": "^0.4.0",
    "grunt-contrib-connect": "^0.7.1",
    "grunt-contrib-copy": "^0.5.0",
    "grunt-contrib-cssmin": "^0.9.0",
    "grunt-contrib-htmlmin": "^0.3.0",
    "grunt-contrib-imagemin": "^0.7.0",
    "grunt-contrib-jshint": "^0.10.0",
    "grunt-contrib-uglify": "^0.4.0",
    "grunt-contrib-watch": "^0.6.1",
    "grunt-filerev": "^0.2.1",
    "grunt-google-cdn": "^0.4.0",
    "grunt-karma": "^0.8.3",
    "grunt-newer": "^0.7.0",
    "grunt-ngmin": "^0.0.3",
    "grunt-svgmin": "^0.4.0",
    "grunt-usemin": "^2.1.1",
    "grunt-wiredep": "^1.7.0",
    "jshint-stylish": "^0.2.0",
    "karma": "^0.12.17",
    "karma-jasmine": "^0.1.5",
    "karma-phantomjs-launcher": "^0.1.4",
    "load-grunt-tasks": "^0.4.0",
    "time-grunt": "^0.3.1"
  },
  "engines": {
    "node": ">=0.10.0"
  },
  "scripts": {
    "test": "grunt test",
    "postinstall": "./node_modules/bower/bin/bower install && ./node_modules/grunt-cli/bin/grunt build"
  }
}

It effectively run bower install and then grunt build, but it failed because my scaffold-ed client uses compass which in turn requires ruby, arrrgh! This is where I stopped looking into this path, I’ve decided to build on my local computer and include the «dist» folder on source control (against all my principles), as suggested by various websites, for now.

Sources:
https://github.com/ddollar/heroku-buildpack-multi
https://discussion.heroku.com/t/grunt-task-after-deployment/253

Java – Ambiente de producción y desarrollo

Lo más común es desarrolllar nuestras aplicaciones en un ambiente de desarrollo, es decir, utilizar servidores de prueba para después implementarlo en un ambiente de produción. Si el código de tu proyecto se encuentra en un sistema de control de código (git, svn, etc.) es díficil, si no tedioso, cambiar entre un ambiente y otro. Tienes que modificar los archivos de configuración para que se conecte a la base de datos de producción cada vez que actualizas el sistema y debes tener cuidado de no incluir en el control de código las conexiones de prueba o visceversa.

Para resolver este problema podemos utilizar JNDI, pero se vuelve complicado el mantener un entorno replicado en nuestra máquina de desarrollador. Eixsten plataformas para desarrollar y ejecutar aplicaciones web de forma escalable -tales como- Heroku, Google App Engine o Microsoft Azure. Para resolver este problema de contextos, Heroku ha optado por utilizar variables de ambiente para cambiar entre el contexto de desarrollo y el de producción.

Esta solución me pareció adecuada y decidí implementarla en un proyecto Java. Realmente es muy sencillo, normalmente creamos una conexión a la base de datos de la siguiente forma:

DriverManager.getConnection(dbUrl, dbUser,dbPassword);

Necesitamos 3 cosas: url a la base de datos, usuario y contraseña.
Opcionalmente podemos incluir el usuario y contraseña en la URL de la base de datos si el controlador lo permite.En el caso de Oracle es de la siguiente manera:

jdbc:oracle:thin:[USER/PASSWORD]@[HOST][:PORT]:SID
jdbc:oracle:thin:[USER/PASSWORD]@//[HOST][:PORT]/SERVICE

Para leer la configuración de las variables de ambiente sería

DriverManager.getConnection(System.getenv(«DATABASE_URL»));

En nuestro caso utilizamos diferentes conexiones de acuerdo al usuario y la base de datos, por lo que seguimos una nomenclatura de la siguiente manera

USUARIO_AT_DATABASE

así por ejemplo, podríamos conectarnos a distintas bases de datos

   DriverManager.getConnection(System.getenv("RH_AT_QUERETARO"));
   DriverManager.getConnection(System.getenv("RH_AT_AMEALCO"));
   DriverManager.getConnection(System.getenv("USRCIVQRO_AT_QUERETARO"));

Por último necesitas configurar estas variables de ambiente en tu sistema operativo.

En Ubuntu lo puedes hacer de diferentes formas.
A mi me funcionó creando un archivo env.sh en la carpeta /etc/profile.d

   #!/usr/bin/bash
   export RH_AT_CENTRO_DE_JUSTICIA=jdbc:oracle:thin:rh/secret@127.0.0.1:1521:dbtest
   export COMPRAS_AT_AMEALCO=jdbc:oracle:thin:compras/secret@127.0.0.1:1521:dbtest

Fuentes:
https://devcenter.heroku.com/articles/heroku-postgresql#connecting-in-java
http://stackoverflow.com/questions/5547224/username-password-in-jdbc-connection-url
https://help.ubuntu.com/community/EnvironmentVariables
http://askubuntu.com/questions/307023/command-not-working-in-profile