WildGigs Beta

This was a long and hard week for me. Yesterday we launched the beta version of WildGigs.

WildGigs is based on the PLOIN Portal what I sold to the Reutax AG. We transfered all User Accounts, Projects, Jobs and everything else from ploin.de to wildgigs.com. We got a lot of Feedback. We have to fix a lot of small things but in general the users are liking it.

Installing MongoDB on YDL

MongoDB is a pretty good Document Database. It is NOT a Object Database. Anyway. If you want learn more about MongoDB check out this site: http://www.mongodb.org

As far as I know MongoDB is not available over the yum package manager from Yellow Dog Linux (YDL). But it is pretty easy to install. Just download the linux binaries and unpack it.

cd /opt/
sudo wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-1.8.1.tgz
sudo tar -xzf mongodb-linux-x86_64-1.8.1.tgz

For convenient reasons you can create a short symlink

sudo ln -s mongodb-linux-x86_64-1.8.1 mongodb

Now you can start all mongo binaries under “/opt/mongodb/bin”. For convenient reasons you can create more symlinks.

cd /usr/bin
sudo ln -s /opt/mongodb/bin/mongod
sudo ln -s /opt/mongodb/bin/mongo

MongoDB will save all the database stuff in the directory “/data/db”. If this directory does not exist you will get an error. Just create the directory.

sudo mkdir /data
sudo mkdir /data/db

Now you can start the MongoDB server

sudo mongod

Your MongoDB Server is up and running. In a diffrent shell you can use the mongo client to connect to the server.

mongo

Now you are in the Mongo Shell. By default the mongo client connects to the database “test”. Try this:

db.foo.save({"b":"2"})
db.foo.find()

Now you should see something like this:

{ "_id" : ObjectId("4dd975e60994b04312264239"), "b" : "2" }

Congratulation! You can exit the shell with this command:

exit

Installing Nginx 1.0.2 on Yellow Dog Linux

I just got an Yellow Dog Linux (YDL) up and running on Amazon EC2. YDL is based on Red Hat. The installation tool is called “yum”. It is similar to debians “apt-get” tool, but it is based on RPMs.

Anyway. You can install nginx via yum with this command:

sudo yum install nginx

But this is not the newest version. If you want the newest version you should install it from the source code. But at first you need to install some additional tools.

sudo yum install gcc
sudo yum install pcre
sudo yum install pcre-devel
sudo yum install zlib
sudo yum install zlib-devel
sudo yum install make

Now you can download the newest version with weget from the nginx page: http://wiki.nginx.org/Install

After the download you should unpack the *tar.gz file und navigate into the directory. Now you can install it with this 3 commands:

sudo ./configure
sudo make
sudo make install

If everything works fine it is installed here:

/usr/local/nginx/

Now you can add “/usr/local/nginx/sbin” to your PATH or you just create a symlink in “/usr/bin”

cd /usr/bin
ln -s /usr/local/nginx/sbin/nginx

For security reason you should create a nginx group.

sudo useradd -s /sbin/nologin -r nginx
sudo usermod -a -G nginx <USERNMAE>

And you should have a place where you deploy your webapps.

sudo mkdir /var/www
sudo chgrp -R nginx /var/www
sudo chmod -R 755 /var/www

Now you can start nginx with this command:

sudo nginx

And stop it with this command:

sudo nginx -s stop

Amazon EC2 API Tools

To deal with instances on Amazon EC2 you need the Amazon EC2 API Tools. You can download it here:

http://aws.amazon.com/developertools/351?_encoding=UTF8&jiveRedirect=1

This command line tools are used to access the EC2 instances. To use this tools you need Java 1.5 or higher and you need to setup the System Variable “JAVA_HOME”.  How to set up the tools with the certificates you can read in the User Guide.

http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html

Add a project to github

github.com is a pretty good git repository server for open source projects. If you have an account you can add easily a project to your github repo. At first generate the git project by executing this line in your project root:

git init

than add all files from your project to your local git repo:

git add .

Than commit everything to your local git repo:

git commit -m "init"

OK. Now you can connect your local git repo with your remote git repo by github.com

git remote add origin git@github.com:<username>/<projectname>.git

Just replace “username” with your github username and “projectname” with your projectname on github. Now you can push your changes to the github repo.

git push

.gitignore

If you want that git is ignoring some files for you you just have to create the “.gitignore” file in your project root. Here you can add all the files you don’t want have in your git repository. For example some meta files from IntelliJ IDEA.

*.iml
*.ipr
*.iws
.idea/

SqlServer 2008 with Hibernate 3.6.4

The current stable version if Hibernate is 3.6.4.FINAL. In this version the Dialect for the SqlServer 2008 from Microsoft looks like this:

public class SQLServer2008Dialect extends SQLServerDialect {
  public SQLServer2008Dialect(){
    registerColumnType( Types.DATE, "date" );
    registerColumnType( Types.TIME, "time" );
    registerColumnType( Types.TIMESTAMP, "datetime2" );

    registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP,false) );
  }
}

A litle bit short. If you have some problems with this Dialect you should write your own Dialect. This class here is a customized SqlServerDialect from the Hibernate 4 Project. For me it works fine together with SqlServer 2008 R2.

import org.hibernate.Hibernate;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.SQLServer2005Dialect;
import org.hibernate.dialect.function.*;
import org.hibernate.type.StandardBasicTypes;

import java.sql.Types;

public class SqlServer2008Dialect extends SQLServer2005Dialect {

 public SqlServer2008Dialect(){
 super();

 registerColumnType( Types.DATE, "date" );
 registerColumnType( Types.TIME, "time" );
 registerColumnType( Types.TIMESTAMP, "datetime2" );

 registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", Hibernate.TIMESTAMP,false) );

 registerColumnType( Types.BIT, "tinyint" ); //Sybase BIT type does not support null values
 registerColumnType( Types.BIGINT, "bigint" );     //changed
 registerColumnType( Types.SMALLINT, "smallint" );
 registerColumnType( Types.TINYINT, "tinyint" );
 registerColumnType( Types.INTEGER, "int" );
 registerColumnType( Types.CHAR, "char(1)" );
 registerColumnType( Types.VARCHAR, "varchar($l)" );
 registerColumnType( Types.FLOAT, "float" );
 registerColumnType( Types.DOUBLE, "double precision" );

 registerColumnType( Types.VARBINARY, "varbinary($l)" );
 registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
 registerColumnType( Types.BLOB, "image" );
 registerColumnType( Types.CLOB, "text" );
 registerColumnType( Types.ROWID, "bigint");

 registerFunction( "ascii", new StandardSQLFunction("ascii", StandardBasicTypes.INTEGER) );
 registerFunction( "char", new StandardSQLFunction("char", StandardBasicTypes.CHARACTER) );
 registerFunction( "len", new StandardSQLFunction("len", StandardBasicTypes.LONG) );
 registerFunction( "lower", new StandardSQLFunction("lower") );
 registerFunction( "upper", new StandardSQLFunction("upper") );
 registerFunction( "str", new StandardSQLFunction("str", StandardBasicTypes.STRING) );
 registerFunction( "ltrim", new StandardSQLFunction("ltrim") );
 registerFunction( "rtrim", new StandardSQLFunction("rtrim") );
 registerFunction( "reverse", new StandardSQLFunction("reverse") );
 registerFunction( "space", new StandardSQLFunction("space", StandardBasicTypes.STRING) );

 registerFunction( "user", new NoArgSQLFunction("user", StandardBasicTypes.STRING) );

 registerFunction( "current_timestamp", new NoArgSQLFunction("getdate", StandardBasicTypes.TIMESTAMP) );
 registerFunction( "current_time", new NoArgSQLFunction("getdate", StandardBasicTypes.TIME) );
 registerFunction( "current_date", new NoArgSQLFunction("getdate", StandardBasicTypes.DATE) );

 registerFunction( "getdate", new NoArgSQLFunction("getdate", StandardBasicTypes.TIMESTAMP) );
 registerFunction( "getutcdate", new NoArgSQLFunction("getutcdate", StandardBasicTypes.TIMESTAMP) );
 registerFunction( "day", new StandardSQLFunction("day", StandardBasicTypes.INTEGER) );
 registerFunction( "month", new StandardSQLFunction("month", StandardBasicTypes.INTEGER) );
 registerFunction( "year", new StandardSQLFunction("year", StandardBasicTypes.INTEGER) );
 registerFunction( "datename", new StandardSQLFunction("datename", StandardBasicTypes.STRING) );

 registerFunction( "abs", new StandardSQLFunction("abs") );
 registerFunction( "sign", new StandardSQLFunction("sign", StandardBasicTypes.INTEGER) );

 registerFunction( "acos", new StandardSQLFunction("acos", StandardBasicTypes.DOUBLE) );
 registerFunction( "asin", new StandardSQLFunction("asin", StandardBasicTypes.DOUBLE) );
 registerFunction( "atan", new StandardSQLFunction("atan", StandardBasicTypes.DOUBLE) );
 registerFunction( "cos", new StandardSQLFunction("cos", StandardBasicTypes.DOUBLE) );
 registerFunction( "cot", new StandardSQLFunction("cot", StandardBasicTypes.DOUBLE) );
 registerFunction( "exp", new StandardSQLFunction("exp", StandardBasicTypes.DOUBLE) );
 registerFunction( "log", new StandardSQLFunction( "log", StandardBasicTypes.DOUBLE) );
 registerFunction( "log10", new StandardSQLFunction("log10", StandardBasicTypes.DOUBLE) );
 registerFunction( "sin", new StandardSQLFunction("sin", StandardBasicTypes.DOUBLE) );
 registerFunction( "sqrt", new StandardSQLFunction("sqrt", StandardBasicTypes.DOUBLE) );
 registerFunction( "tan", new StandardSQLFunction("tan", StandardBasicTypes.DOUBLE) );
 registerFunction( "pi", new NoArgSQLFunction("pi", StandardBasicTypes.DOUBLE) );
 registerFunction( "square", new StandardSQLFunction("square") );
 registerFunction( "rand", new StandardSQLFunction("rand", StandardBasicTypes.FLOAT) );

 registerFunction("radians", new StandardSQLFunction("radians", StandardBasicTypes.DOUBLE) );
 registerFunction("degrees", new StandardSQLFunction("degrees", StandardBasicTypes.DOUBLE) );

 registerFunction( "round", new StandardSQLFunction("round") );
 registerFunction( "ceiling", new StandardSQLFunction("ceiling") );
 registerFunction( "floor", new StandardSQLFunction("floor") );

 registerFunction( "isnull", new StandardSQLFunction("isnull") );

 registerFunction( "concat", new VarArgsSQLFunction( StandardBasicTypes.STRING, "(","+",")" ) );

 registerFunction( "length", new StandardSQLFunction( "len", StandardBasicTypes.INTEGER ) );
 registerFunction( "trim", new SQLFunctionTemplate( StandardBasicTypes.STRING, "ltrim(rtrim(?1))") );
 registerFunction( "locate", new CharIndexFunction() );

 getDefaultProperties().setProperty(Environment.STATEMENT_BATCH_SIZE, NO_BATCH);
 }

}
 

You can just copy & pate it to your own project. If you want to use it, just add the dialect to your hibernate.properties.

hibernate.dialect=org.<your_package_name>.SqlServer2008Dialect

Customized MySql5Dialect for Hibernate

By default the MySqlDialect who is coming with Hibernate does MySQL not force to UTF. And by default all binary columns are mapped to “tinyblob”. That’s why I wrote my own Dialect. It is very easy to do. Just a fiew lines of code. Here is my own MySql5Dialect.

import org.hibernate.dialect.MySQL5InnoDBDialect;

import java.sql.Types;

public class MySql5Dialect extends MySQL5InnoDBDialect {

  public String getTableTypeString() {
    return " ENGINE=InnoDB DEFAULT CHARSET=utf8";
  }

  public MySql5Dialect() {
    super();
    registerColumnType( Types.BINARY, "MEDIUMBLOB" );
  }

}

You can use by adding this to your hibernate.properties files:

hibernate.dialect=org.<your_package_name>.MySql5Dialect

Could not initialize class JavaReflection

By migrating to Hibernate 3.6.4.FINAL and Spring 3.0.5.RELEASE I got this Exception:

Could not initialize class org.hibernate.annotations.common.reflection.java.JavaReflection

I could solve the problem by adding this to my pom.

       <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.6.1</version>
            <scope>compile</scope>
        </dependency>

Single Sign-On with Facebook & Ruby on Rails

There are over 400 Million people on earth with a Facebook Account. From this point of view it makes absolute sense to offer a Single Sign-On with Facebook.

Facebook offers a Login via OAuth 2.0. The Facebook documentation for the Authentication process you can find here: http://developers.facebook.com/docs/authentication/.

Before you are using the API from Facebook you have to set up an “Facebook App”. Every Facebook App has a client_id and a client_secret. You need both to communicate with the Facebook API. Here you can create a Facebook App: http://www.facebook.com/developers/

If your set up is done you can start with the implementation. Maybe you want to offer a “Login with Facebook” button like this:

Login with Facebook

Login with Facebook

To achieve this you can embed this code in your HTML Page:

<pre><a href='javascript:var popupWindow = window.open(link, "popupWindow", "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, menubar=1, resizable=1, width="+winWidth+",height="+winHeigh+"top="+top+", left="+left);'
           style="margin-right: 5px;" >
    <img src="/images/fb_login_icon.gif"  style="border: 0px solid white; padding: 0;" />
</a></pre>

This will open a JavaScript popup window with the Facebook Login mask, if you are not already logged in by Facebook via Cookie.

To make this work you need a little bit JavaScript:

var winWidth = 950;
var winHeigh = 550;
var left = (screen.width/2)-(winWidth/2);
var top = (screen.height/2)-(winHeigh/2);

var domainlink = "https://graph.facebook.com/oauth/authorize?";
var req_perms = "req_perms=email&";
var clientid = "client_id=111111111111&";
var scope = "scope=email,offline_access&";
var redirect = "redirect_uri=http://yourdomain.com/facebook/start";
var link = domainlink + req_perms + clientid + scope + redirect;

Just replace  ”111111111111” with your client_id and “yourdomain” with your domain. The link contains a redirect_uri on your server. After the Facebook Authentication is done, Facebook will redirect the user to your “redirect_uri”.

OK. And here is the corresponding Controller with Ruby on Rails.

class FacebookController < ApplicationController

  layout "plain"

  def start
    code = params['code']

    domain = 'https://graph.facebook.com'
    uri = '/oauth/access_token'
    query = 'client_id=111111111111&'
    query += 'redirect_uri=http://yourdomain.com/facebook/start&'
    query += 'client_secret=2222222222222222222&'
    query += 'code=' + code
    link = domain + uri + '?' + query

    response = HTTParty.get(URI.encode(link))

    data = response.body
    access_token = data.split("=")[1]

    user = get_user_for_token access_token
    if !user.nil?
      sign_in user
    end
  end

  private

    def get_user_for_token(token)
      json_user = JSON.parse HTTParty.get('https://graph.facebook.com/me?access_token=' + URI.escape(token)).response.body
      user = User.find_by_fb_id json_user['id']
      if user.nil?
        user = User.new
        user.update_from_fb_json json_user
      end
      user.fb_token = token
      user.save
      user
    end

end

I am using here the “HTTParty” gem. You should have this line in your Gemfile:

gem 'httparty', '0.7.4'

And you have to map the controller action in your routes.rb file:

match '/facebook/start',    :to => 'facebook#start'

The “def start” action will be called from Facebook after the User Auth.  Facebook will send you with this request a “code”. You can fetch the code like this:

code = params['code']

Together with the given token, your client_id and your client_secret you can fetch an access_token from facebooks GRAPH API.

    domain = 'https://graph.facebook.com'
    uri = '/oauth/access_token'
    query = 'client_id=111111111111&'
    query += 'redirect_uri=http://yourdomain.com/facebook/start&'
    query += 'client_secret=2222222222222222222&'
    query += 'code=' + code
    link = domain + uri + '?' + query

    response = HTTParty.get(URI.encode(link))

    data = response.body
    access_token = data.split("=")[1]

With the access_token you can fetch a user as JSON object.

json_user = JSON.parse HTTParty.get('https://graph.facebook.com/me?access_token=' + URI.escape(token)).response.body

That’s it.

HTML Upload to Amazon S3 with Ruby on Rails

This Blog Post will demonstrate how to build a HTML file upload for images with Ruby on Rails and store the images on Amazon S3 Cloud Storage. I assume that you are familiar with Ruby on Rails and RubyGems.

For the connection to Amazons S3 Storage System we will use the gem “aws-s3″. To use this you have to add this line to your Gemfile:

gem 'aws-s3', '0.6.2', :require => 'aws/s3'

After you added the line to your Gemfile, execute:

bundle

to load the gem. To use aws-s3 is pretty easy. Just add this lines to your “application.rb” file:

AWS::S3::Base.establish_connection!(
      :access_key_id     => 'your_access_key_id',
      :secret_access_key => 'your_secret_access_key'
    )

Just customize the above lines with your access_key_id and your secret_access_key from your S3 Account. Everytime then you are starting your Ruby App AWS will establish a connection to your S3 storage.

OK. Let’s start with the HTML upload form. Here it is:

 <%= form_for @image, :html => {:multipart => true, :accept => "image/gif,image/png,image/jpg"} do |f| %>

   <div>
     <label>Image</label>
   </div>
   <div style="width: 400px;" >
     <%= file_field 'upload', 'datafile'  %>
   </div>

 <div>
   <%= f.submit "Upload image", :class => "button" %>
 </div>

<% end  %>

And the corresponding Ruby Controller looks like this:

class ImagesController < ApplicationController

@@BUCKET = "my_image_bucket"

def create
  fileUp = params[:upload]
  orig_filename =  fileUp['datafile'].original_filename
  filename = sanitize_filename(orig_filename)
  AWS::S3::S3Object.store(filename, fileUp['datafile'].read, @@BUCKET, :access => :public_read)
  url = AWS::S3::S3Object.url_for(filename, @@BUCKET, :authenticated => false)
  @image = Image.new(params[:image])
  @image.user = current_user
  @image.filename = filename
  @image.url = url;
  if @image.save
    flash[:success] = "Image saved! "
    render '/home'
  else
    render '/users/new_image'
  end
end

def destroy
  AWS::S3::S3Object.find(@image.filename, @@BUCKET).delete
  @image.destroy
  render '/home'
end

private 
  
    def sanitize_filename(file_name)
      just_filename = File.basename(file_name)
      just_filename.sub(/[^\w\.\-]/,'_')
    end

end

That’s it. Just cusotmezice the “@@BUCKET” with your Amazon Bucket name.