Thursday, 30 October 2014

How to Upload Images to DropBox In Java

This Tutorial explains how to upload images to drop box and get the public url of uploaded image .
First of all we have to create a DropBox API app using app console. Once you create the app , you can get App key and secret key in the app properties .

Now add following dependency in your pom file .
<dependency>
 <groupId>com.dropbox.core</groupId>
 <artifactId>dropbox-core-sdk</artifactId>
 <version>1.7.7</version>
</dependency>
Now this java program will do the rest . Replace your app ket and secret key in program . Run this java program from command line and it will ask for the code , you will get the code by following the url printed on the console.

For getting the public url , we just need to use createShareableUrl of the dropboxClient class.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Locale;

import com.dropbox.core.DbxAppInfo;
import com.dropbox.core.DbxAuthFinish;
import com.dropbox.core.DbxClient;
import com.dropbox.core.DbxEntry;
import com.dropbox.core.DbxException;
import com.dropbox.core.DbxRequestConfig;
import com.dropbox.core.DbxWebAuthNoRedirect;
import com.dropbox.core.DbxWriteMode;


public class UploadImages
{
 public static void main(String[] args) throws IOException, DbxException
 {
  final String DROP_BOX_APP_KEY = "APPKEY";
        final String DROP_BOX_APP_SECRET = "SECRETKEY";
        
        String rootDir = "C:\\Users\\Downloads\\";

        DbxAppInfo dbxAppInfo = new DbxAppInfo(DROP_BOX_APP_KEY, DROP_BOX_APP_SECRET);

        DbxRequestConfig reqConfig = new DbxRequestConfig("javarootsDropbox/1.0",
            Locale.getDefault().toString());
        DbxWebAuthNoRedirect webAuth = new DbxWebAuthNoRedirect(reqConfig, dbxAppInfo);

        
        String authorizeUrl = webAuth.start();
        System.out.println("1. Go to this URL : " + authorizeUrl);
        System.out.println("2. Click \"Allow\" (you might have to log in first)");
        System.out.println("3. Copy the authorization code and paste here ");
        String code = new BufferedReader(new InputStreamReader(System.in)).readLine().trim();

        
        
        DbxAuthFinish authFinish = webAuth.finish(code);
        String accessToken = authFinish.accessToken;

        DbxClient client = new DbxClient(reqConfig, accessToken);

        System.out.println("account name is : " + client.getAccountInfo().displayName);

        
        
        File inputFile = new File(rootDir +"images\\"+ "javaroots.jpg");
        FileInputStream inputStream = new FileInputStream(inputFile);
        try {
         
            DbxEntry.File uploadedFile = client.uploadFile("/javaroots.jpg",
                DbxWriteMode.add(), inputFile.length(), inputStream);
            String sharedUrl = client.createShareableUrl("/javaroots.jpg");
            System.out.println("Uploaded: " + uploadedFile.toString() + " URL " + sharedUrl);
        } finally {
            inputStream.close();
        }
 }
}
Take reference from the this official drop box link.

You can download the full project from this link . Post Comments and Suggestions !!


How To Configure SSL with NGINX IN RAILS

In our previous post,we have learnt how to use ssl in a rails application by modifiying application server and application configurations.

In this post we will be configuring/bypassing Proxy for using ssl in an web server.

We will be using Nginx for our configuration.

To configure an HTTPS server, the ssl parameter must be enabled on listening sockets in the server block, and the locations of the server certificate and private key files should be specified.

Generate your ssl keys using the previous post and copy over the files to nginx directory.








Download the nginx.conf file , take back up of your existing configuration and replace it .

Steps to follow:
1. Add the number of worker process you need by default it should be 1. e.g worker_processes 4;
2. Make sure that path of ssl_certificate & ssl_certificate_key are correct.
3. Create dir/entry for access_log & error_log.
4. In the upstream section you can configure your server address with port for https, like this
 
   upstream proxy_pass_server {
            server 127.0.0.1:3000 fail_timeout=0;
      }
Here I am pointing to localhost port 3000 and added server_name 127.0.0.1 in Server Section of configuration

Now , Start your rails server independent of application server in 3000 port and type https://localhost

Your application Now runs on HTTPS .

Thanks to Santosh for writing this post .

REFER NGINX For more Details

Monday, 13 October 2014

Social Media Authentication On Rails- Part 2

In the last post , we have discussed how to get api keys and access for multiple social media platform .In this post we will to setup rails to integrate these applications .

Code SetUp:

Now its Time to Set Up Rails Application with MongoDB , Rails & Omniauth Gem(s).
we will be using “ruby 2.1.1p76” with “Rails 4.1.0” for our application.

Step 1:
In Gem file add the following Gems:
gem 'rails', '4.1.0'
gem 'mongoid', git: 'https://github.com/mongoid/mongoid.git'
gem 'devise'
gem 'bson_ext'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-linkedin' 
gem 'omniauth-twitter' 
gem "omniauth-google-oauth2"
gem 'twitter'
gem "linkedin"
gem 'oauth2'
Step 2:
Follow the link and install devise gem to your application.
For Omniauth with devise follow the link which will be usefull for development and debugging your application.
Step 3:
Include required Gems in your initializers/devise.rb file and add your API KEYS with API Secret.
require 'devise/orm/mongoid'
require 'omniauth-twitter'
require 'omniauth-google-oauth2'
require 'omniauth-linkedin'
require 'omniauth-facebook'
require 'omniauth-github'

Configuring API Keys:
config.omniauth :twitter, "API KEY", "API SECRET"
config.omniauth :linkedin, "API KEY", "API SECRET", :scope => 'r_basicprofile r_emailaddress rw_nus'
config.omniauth :facebook, 'API KEY', 'API SECRET'
config.omniauth :google_oauth2, 'API KEY', 'API SECRET'

Add the following links to devise registrations/new or shared/_links.html.erb









Open Up Your User Model and Configure it as described below , fields for mongo db can be configured as per your requirement :
class User
  include Mongoid::Document
  devise :omniauthable, :omniauth_providers => [:facebook,:twitter,:linkedin,:google_oauth2]
  embeds_one :user_linkedin_connection, :class_name => 'User::LinkedinConnection'
  embeds_one :user_twitter_connection, :class_name => 'User::TwitterConnection'
  # Configured for Getting mongo key from Session in rails 4 (Mongoid)
  class << self
    def serialize_from_session(key, salt)
      record = to_adapter.get(key.first["$oid"]) if key.present? # to_adapter.get(key.to_s)
      record if record && record.authenticatable_salt == salt
    end
  end
  def self.connect_to_linkedin(auth)
    self.provider = auth.provider
    self.uid = auth.uid
    self.user_linkedin_connection = User::LinkedinConnection.new(:token => auth["extra"]["access_token"].token, :secret => auth["extra"]["access_token"].secret)
    unless self.save
      return false
    end
    true
  end
  def self.disconnect_from_linkedin!
    self.provider = nil
    self.uid = nil
    self.user_linkedin_connection = nil
    self.save!
  end
  def self.find_for_linkedin_oauth(auth, signed_in_resource=nil)
    @user = User.where(:provider => auth.provider, :uid => auth.uid).first
    if @user
      @user.connect_to_linkedin(request.env["omniauth.auth"])
      sign_in_and_redirect @user, :event => :authentication
      set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
    else
      flash[:notice] = "Couldn't find a user connected to your LinkedIn account. Please sign in and then connect your account to LinkedIn."
      redirect_to new_user_session_url
    end
  end
  def self.find_for_facebook_oauth(auth)
   where(auth.slice(:provider, :uid)).first_or_create do |user|
     user.provider = auth.provider
     user.uid = auth.uid
     user.email = auth.info.email
     user.password = Devise.friendly_token[0,20]
     user.name = auth.info.name   # assuming the user model has a name
   end
  end
  def self.find_for_google_oauth2(access_token, signed_in_resource=nil)
    data = access_token.info
    user = User.where(:email => data["email"],:provider => "Google").first
    unless user
      user = User.create( name: data["name"],email: data["email"],provider: "Google", password: Devise.friendly_token[0,20]  )
    end
    user
  end
  def self.find_for_github_oauth(auth)
    record = where(provider: auth.provider, uid: auth.uid.to_s).first
    record || create(provider: auth.provider, uid: auth.uid, email: auth.info.email, password: Devise.friendly_token[0,20], name: auth.info.name )
  end
end
Create two More files named linkedin_connection.rb and twitter_connection.rb inside app/models/user/ which will contain the token and secret provided from provider.

linkedin_connection.rb:
class User::LinkedinConnection
  include Mongoid::Document
  include Mongoid::Timestamps
  embedded_in :user
  field :token
  field :secret
end 
twitter_connection.rb:
class User::TwitterConnection
  include Mongoid::Document           field :token
  include Mongoid::Timestamps         field :secret
  embedded_in :user
   end
Once we get a Success request from Provider , response moves on to omniauth call_back controller where we need to store the response and maintain the session.

Create a omniauth_callback controller and paste the code as provided below:

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  before_filter :authenticate_user!
  # Linkedin authentication
  def linkedin
    @user = User.where(:provider => request.env["omniauth.auth"].provider, :uid => request.env["omniauth.auth"].uid).first
    if @user.present?
      sign_in_and_redirect @user, :event => :authentication
      set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
    else
      auth = request.env["omniauth.auth"]
      @user = User.new #create new user to save in the database
      @user.email=  auth.info.email #save user email
      @user.provider = auth.provider
      @user.uid = auth.uid
      @user.user_linkedin_connection = User::LinkedinConnection.new(:token => auth["extra"]["access_token"].token, :secret => auth["extra"]["access_token"].secret)
      @user.save(:validate => false) #password for the linkdin to be stored
      sign_in_and_redirect @user, :event => :authentication
      set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
    end
  end

# Facebook authentication
def facebook
    # You need to implement the method below in your model (e.g. app/models/user.rb)
    @user = User.find_for_facebook_oauth(request.env["omniauth.auth"])
    if @user.persisted?
      sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

# Twitter authentication
def twitter
    @user = User.where(:provider => request.env["omniauth.auth"].provider, :uid => request.env["omniauth.auth"].uid).first
    if @user.present?
      sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
    else
      auth = request.env["omniauth.auth"] # contains all the information about the user login profile.
      @user = User.create(name: auth.extra.raw_info.name,
                  provider: auth.provider,
                  uid: auth.uid,
                  email: auth.uid+"@twitter.com", #create user email
                  password: Devise.friendly_token[0,20],
                  user_twitter_connection: User::TwitterConnection.new(:token => auth.credentials.token, :secret => auth.credentials.secret )
      )
      sign_in_and_redirect @user, :event => :authentication
      set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
    end
  end

 # Google authentication
  def google_oauth2
    # You need to implement the method below in your model (e.g. app/models/user.rb)
    @user = User.find_for_google_oauth2(request.env["omniauth.auth"])
    if @user.persisted?
      sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, :kind => "Google") if is_navigational_format?
      # flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
      # sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
    else
      session["devise.google_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end
end
Now we are Good to Go ahead and start authenticating with social websites in our Rails app.

Note:
• Application status in Provider Settings should be live
• Call back URL should match your application routes
• It is Good to go with Storing session in DB as sometimes cookie_store fails when a logged in user fetches request from provider.


Thanks to Santosh for wroting this post .


Social Media Authentication On Rails- Part 1

This Post is intended to provide an overview of the installation of social authentication plugins like Twitter/Github/Facebook & Google using Rails version 4 with devise(authentication plugin),omniauth(API Plugin for Social websites) & Mongo DB as underlying Database.


Before Proceeding towards installation/building a rails application that allows authentication with social websites we need to get API/Client Keys & API/Client Secret.


Here are the urls from where you can create an App and get the keys:


Facebook:

URL: Facebook Link











Twitter:>

URL: Twitter































Settings: Enter call back url as : http://127.0.0.1:3000/auth/twitter/callback/ under settings tab once you create an application














Google:

URL: Google URL










Settings: Go to API Access and enter redirect url as http://localhost:3000/users/auth/google_oauth2/callback



LinkedIn:>

URL: LinkedIn URL

Linked In Api Doesnot require any call back URI. Application URL is Enough for Linked in api as Omniauth-linked Has its method defined in Gem.













In the next post , the ROR code will be explained to integrate these social applications .



Monday, 15 September 2014

MULE FTP : Create Directory If Not Exist

FTP and SFTP endpoints of mule , does not create directory on the fly , if the directory does not exist at ftp location .
It throws error like this :
ERROR 2007-11-05 15:24:29,192 [connector.ftp.0.receiver.1] org.mule.impl.DefaultExceptionStrategy: Caught exception in Exception Strategy: Failed to change working directory to /IN. Ftp error: 550
java.io.IOException: Failed to change working directory to /IN. Ftp error: 550
        at org.mule.providers.ftp.FtpMessageReceiver.listFiles(FtpMessageReceiver.java:103)
        at org.mule.providers.ftp.FtpMessageReceiver.poll(FtpMessageReceiver.java:72)
        at org.mule.providers.PollingReceiverWorker.run(PollingReceiverWorker.java:47)
        at org.mule.impl.work.WorkerContext.run(WorkerContext.java:310)
        at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:987)
        at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:528)
        at java.lang.Thread.run(Thread.java:619) 
There is an Open Issue for this functionality .

To implement this functionality for FTP , we have to create a custom FTPDispatcher and integrate it in the mule ftp connector .


So first change mule ftp connector to have CustomFTPMessageDispatcher like this:
<ftp:connector name="ftp_con">
  <service-overrides dispatcherFactory="CustomFtpMessageDispatcherFactory"></service-overrides>
 </ftp:connector>
    <flow name="sftpExampleFlow1" doc:name="sftpExampleFlow1">
     
        <file:inbound-endpoint path="E:/ftp" responseTimeout="10000" doc:name="File"/>
        <ftp:outbound-endpoint host="localhost" port="21" responseTimeout="10000" doc:name="FTP" connector-ref="ftp_con"
        outputPattern="custom/path/myFile.txt" path="/home/ftp" 
        />
    </flow>
And here's the DispatcherFactory class .

import org.mule.api.MuleException;
import org.mule.api.endpoint.OutboundEndpoint;
import org.mule.api.transport.MessageDispatcher;
import org.mule.transport.ftp.FtpMessageDispatcherFactory;

public class CustomFtpMessageDispatcherFactory extends FtpMessageDispatcherFactory
{
 /** {@inheritDoc} */
    public MessageDispatcher create(OutboundEndpoint endpoint) throws MuleException
    {
        return new CustomFtpMessageDispatcher(endpoint);
    }
}


And here's the FTPMessageDispacther , which will first create a directory if the outputPattern has it .

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.mule.api.MuleEvent;
import org.mule.api.endpoint.OutboundEndpoint;
import org.mule.api.transport.DispatchException;
import org.mule.config.i18n.CoreMessages;
import org.mule.model.streaming.CallbackOutputStream;
import org.mule.transport.ConnectException;
import org.mule.transport.ftp.FtpConnector;
import org.mule.transport.ftp.FtpMessageDispatcher;

public class CustomFtpMessageDispatcher extends FtpMessageDispatcher
{

 Log logger = LogFactory.getLog(CustomFtpMessageDispatcher.class);

 public CustomFtpMessageDispatcher(OutboundEndpoint endpoint)
 {
  super(endpoint);

 }

 protected void doDispatch(MuleEvent event) throws Exception
 {
  Object data = event.getMessage().getPayload();
  String outputPattern = (String) endpoint.getProperty(FtpConnector.PROPERTY_OUTPUT_PATTERN);
  String basePath = endpoint.getEndpointURI().getPath();
  OutputStream out = null;
  if (basePath.endsWith("/"))
   basePath = basePath.substring(0, basePath.length() - 1);

  if (outputPattern != null && outputPattern.contains("/"))
  {
   try
   {
    if (outputPattern.startsWith("/"))
     outputPattern = outputPattern.substring(1, outputPattern.length());
    
    String dirs[] = outputPattern.split("/", -1);
    final FtpConnector connector = (FtpConnector) endpoint.getConnector();
    final FTPClient client = connector.getFtp(endpoint.getEndpointURI());
    for (int i = 0; i < dirs.length - 1; i++)
    {
     try
     {
      if (!dirs[i].isEmpty())
      {
       basePath = basePath + "/" + dirs[i];
       if (!client.changeWorkingDirectory(basePath))
        client.makeDirectory(basePath);
      }

     } catch (Exception e)
     {
      logger.error("Error Creating dir on ftp" + e.getMessage());
     }
    }
    
    String filename = dirs[dirs.length - 1];
    out = client.storeFileStream(filename);
    if (out == null)
    {
     throw new IOException("FTP operation failed: " + client.getReplyString());
    }

    out = new CallbackOutputStream(out, new CallbackOutputStream.Callback()
    {
     public void onClose() throws Exception
     {
      try
      {
       if (!client.completePendingCommand())
       {
        client.logout();
        client.disconnect();
        throw new IOException("FTP Stream failed to complete pending request");
       }
      } finally
      {
       connector.releaseFtp(endpoint.getEndpointURI(), client);
      }
     }
    });
   }
   catch (ConnectException ce)
         {
             // Don't wrap a ConnectException, otherwise the retry policy will not go into effect.
             throw ce;
         }
         catch (Exception e)
         {
             throw new DispatchException(CoreMessages.streamingFailedNoStream(), event, (OutboundEndpoint)endpoint, e);
         }

  } 
  else
  {
   out = connector.getOutputStream(getEndpoint(), event);
  }

  try
  {
   if (data instanceof InputStream)
   {
    InputStream is = ((InputStream) data);
    IOUtils.copy(is, out);
    is.close();
   } else
   {
    byte[] dataBytes;
    if (data instanceof byte[])
    {
     dataBytes = (byte[]) data;
    } else
    {
     dataBytes = data.toString().getBytes(event.getEncoding());
    }
    IOUtils.write(dataBytes, out);
   }
  } finally
  {
   out.close();
  }
 }

}


Post Comments And Suggestions !!!


Friday, 12 September 2014

COLOURIZED LOGGING IN RUBY(IRB) PROMPT

Wirble is a set of enhancements for ruby(irb). Wirble enables several items mentioned on the RubyGarden "Irb Tips and Tricks" page, including tab-completion, history, and a built-in ri command, as well as colorized results and a couple other goodies.

Wirble even works with rvm , lets hack the trick to do so:

Step 1:
When we start irb prompt it first checks for .irbrc file in home folder. ~/.irbrc.

Step 2 :
To enable wirble in irb prompt, Open the ~/.irbrc file (Create a new one if Not present.), and Paste the contents of the below code.
require 'irb/completion'
 require 'irb/ext/save-history'
 require 'rubygems'
 unless Gem::Specification.find_all_by_name('wirble').any?
   puts "Installing Wirble"
   %x{gem install 'wirble' --no-ri --no-rdoc}
 end
 Gem.refresh 
 require 'wirble'
# Initializing Wirble
Wirble.init
Wirble.colorize
# Customize according to your will.
colors = Wirble::Colorize.colors.merge({
  :object_class => :purple,
  :symbol => :purple,
  :symbol_prefix => :purple
})
Wirble::Colorize.colors = colors

Step 3:
Move out of the blog for a colourfull irb prompt and Njoy Coding in Ruby. Thanks to Santosh for writing this post .



Tuesday, 2 September 2014

Mule SFTP : Verify false Error

The following error might occur while using SFTP inbound or outbound endpoint in mule :
Error during login to x@192.168.2.18: verify: false
java.io.IOException: Error during login to x@192.168.2.18: verify: false
 at org.mule.transport.sftp.SftpClient.logAndThrowLoginError(SftpClient.java:200)
 at org.mule.transport.sftp.SftpClient.login(SftpClient.java:146)
 at org.mule.transport.sftp.SftpConnectionFactory.createClient(SftpConnectionFactory.java:98)
 at org.mule.transport.sftp.SftpConnector.createSftpClient(SftpConnector.java:191)
 at org.mule.transport.sftp.SftpConnector.createSftpClient(SftpConnector.java:174)
 at org.mule.transport.sftp.SftpReceiverRequesterUtil.getAvailableFiles(SftpReceiverRequesterUtil.java:75)
 at org.mule.transport.sftp.SftpMessageReceiver.poll(SftpMessageReceiver.java:62)
 at org.mule.transport.AbstractPollingMessageReceiver.performPoll(AbstractPollingMessageReceiver.java:219)
 at org.mule.transport.PollingReceiverWorker.poll(PollingReceiverWorker.java:84)
 at org.mule.transport.PollingReceiverWorker.run(PollingReceiverWorker.java:53)
 at org.mule.work.WorkerContext.run(WorkerContext.java:311)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at java.lang.Thread.run(Thread.java:722)
Mule SFTP uses JSch to connect to SFTP location . This error occurs with particular Java JDK updates . You might get this error If you are using following versions of jdk :
java7u6
java7u7
java7u15
This error does not occur if we use JDK version < java7u6 .

For more information please read this link.

Post Comments And Suggestions !!