Saturday, October 11, 2014

Grail's Create Or Change Database Connection Manually Or Run-time | Using multiple data-sources in a Grail's project | Grail's Multiple Data Sources | Grail's multi tenant data-sources

In src/groovy, create a groovy class named 'UserHolder' with following contents:


package a.b.c

/**
 * Created by pritom on 14/08/2014.
 */
class UserHolder {
    public static Integer DEFAULT = 1;
    private static final ThreadLocal contextHolder = new ThreadLocal();
    public static String DS_PREFIX = "dataSource_";
    public static String DS_POSTFIX = "User";

    static void setEnvironment(Map environment) {
        contextHolder.set(environment);
    }

    static getEnvironment() {
        return contextHolder.get();
    }

    static void clear() {
        contextHolder.remove();
    }
}

Also create a groovy class named 'SwitchableDataSource' in src/groovy with following contents:


package a.b.c

import grails.util.Holders
import org.springframework.context.ApplicationContext
import org.springframework.jdbc.datasource.DriverManagerDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource

import javax.sql.DataSource

/**
 * Created by pritom on 14/08/2014.
 */
class SwitchableDataSource extends AbstractRoutingDataSource {
    def applicationContext

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext
    }

    protected DataSource determineTargetDataSource() {
        def user = UserHolder.getEnvironment();
        try {
            DriverManagerDataSource ds = super.determineTargetDataSource();
            return ds;
        }
        catch (Exception ex) {
            println "--->Error:: ${ex.getMessage()}";
            try {
                def ga = Holders.getGrailsApplication();
                String beanFullName = UserHolder.DS_PREFIX + user.id + UserHolder.DS_POSTFIX;
                if(user && user.id && ga.mainContext.containsBean( beanFullName ) ) {
                    println "Using data source: '${beanFullName}'";
                    return ga.mainContext.getBean(beanFullName);
                }
            }
            catch (Exception ex2) {
                println "--->Error:: ${ex2.getMessage()}";
            }
        }
    }

    @Override
    protected Object determineCurrentLookupKey() {
        def user = UserHolder.getEnvironment();
        return user?.id ?: UserHolder.DEFAULT;
    }

    @Override
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        super.setTargetDataSources(targetDataSources);
    }
}

Edit resource.groovy file under grails-app/conf/spring folder:


import a.b.c.SwitchableDataSource
import a.b.c.UserHolder
import org.springframework.jdbc.datasource.DriverManagerDataSource

// Place your Spring DSL code here
beans = {
    parentDataSource(DriverManagerDataSource) { bean ->
        bean.'abstract' = true;
        driverClassName = 'com.mysql.jdbc.Driver'
        username = "root"
    }

    "rootDataSource"(DriverManagerDataSource) { bean ->
        bean.parent = parentDataSource;
        bean.scope = 'prototype';
        url = "jdbc:mysql://localhost/user${UserHolder.DEFAULT}?useUnicode=yes&characterEncoding=UTF-8";
        username = "root"
    }

    def dataSources = [:]
    dataSources[UserHolder.DEFAULT] = ref("rootDataSource");

    dataSource(SwitchableDataSource) {
        targetDataSources = dataSources
    }
}

Now create another groovy class named 'DataSourceService' to bind datasource to your project dynamically/runtime with following contents:


package a.b.c

import grails.spring.BeanBuilder
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.springframework.beans.BeansException
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.context.support.GenericApplicationContext

/**
 * Created by pritom on 14/08/2014.
 */
class DataSourceService implements ApplicationContextAware {
    ApplicationContext applicationContext;
    public GrailsApplication grailsApplication;

    @Override
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * Add new bean to system
     * @param beanName
     * @param dsurl
     * @param uid
     * @param pwd
     * @return
     */
    def registerBean( String beanName, String dsurl, String uid, String pwd ) {
        String beanFullName = UserHolder.DS_PREFIX + beanName + UserHolder.DS_POSTFIX;
        if( !applicationContext.containsBean( beanFullName ) ) {
            def bb = new BeanBuilder()
            bb.beans {
                "$beanFullName" { bean ->
                    bean.parent = ref('parentDataSource');
                    bean.scope = 'prototype';
                    url = dsurl;
                    username = uid
                    password = pwd
                }
            }
            bb.registerBeans( applicationContext );

            println "Added $beanFullName"
        }
        else {
            println "Already got a bean called $beanFullName"
        }
    }

    /**
     * Remove bean from system
     * @param beanName
     * @return
     */
    def deRegisterBean( String beanName ) {
        if( applicationContext.containsBean( beanName ) ) {
            (applicationContext as GenericApplicationContext).removeBeanDefinition( beanName )
            println "Removed $beanName"
        }
        else {
            println "Trying to deRegister a bean $beanName that I don't know about"
        }
    }
}

Now create a filter in grails-app/filters named 'SecurityFilters' with following contents:


package filters

import a.b.c.UserHolder

class SecurityFilters {

    def filters = {
        all(controller: '*', action: '*') {
            before = {
     /* This line is for specify which user request to handle */
                if (params.int('user')) {
                    UserHolder.setEnvironment([id: params.int('user')]);
                }
            }
            after = { Map model ->

            }
            afterView = { Exception e ->

            }
        }
    }
}

Example of adding a new datasource to system:


DataSourceService dataSourceService = new DataSourceService();
dataSourceService.setApplicationContext(grailsApplication.mainContext);
dataSourceService.grailsApplication = grailsApplication;
dataSourceService.registerBean(params.user, "jdbc:mysql://localhost/user${params.user}?useUnicode=yes&characterEncoding=UTF-8", "root", "");

Suppose params.user = 3 here.

That's it Download code

Friday, October 10, 2014

Using Java Send Email Using Smtp Server(Html, Attachment, Embedded Image)

First download java mail api jar from: https://java.net/projects/javamail/pages/Home or here.
And add this to your project classpath.


package com.pritom;

import java.util.*;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;

/**
 * Created by pritom on 30/11/2016.
 */
public class SendEmailUsingSmtp {
    private static final String toAddress = "pritom@xxxxx.com";

    public static void main(String[] args) {
        google();
        //office();
        //bleep();
    }

    private static void google() {
        String host = "smtp.gmail.com";
        String port = "587";
        String userName = "xxxxx@gmail.com";
        String password = "xxxxx";
        send(host, port, userName, password);
    }

    private static void office() {
        String host = "smtp.office365.com";
        String port = "587";
        String userName = "xxxxx@office.com";
        String password = "xxxxx";
        send(host, port, userName, password);
    }

    private static void bleep() {
        String host = "bleep.xxxxx.com";
        String port = "587";
        String userName = "pritom@xxxxx.com";
        String password = "xxxxx";
        send(host, port, userName, password);
    }

    private static void send(String host, String port, String userName, String password) {
        String attachments = "attachments/Attachment_1.gif;"
                + "attachments/Attachment_2.pdf;"
                + "attachments/Attachment_3.txt;"
                + "attachments/Attachment_4.docx;"
                + "attachments/Attachment_5.jpg";


        Properties props = new Properties();
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.host", host);
        props.put("mail.smtp.port", port);
        props.put("mail.smtp.auth", "true");
        props.put("https.protocols", "TLSv1,SSLv3,SSLv2Hello");
        props.put("com.sun.net.ssl.enableECC", "false");
        props.put("jsse.enableSNIExtension", "false");

        String subject = "Java send mail example - TLS Authentication";

        Session mailSession = Session.getInstance(props, new javax.mail.Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(userName, password);
            }
        });

        MimeMessage message = new MimeMessage(mailSession) {
            protected void updateMessageID() throws MessagingException {
                if (getHeader("Message-ID") == null)
                    super.updateMessageID();
            }
        };

        try {

            /* If failed to send email then fail report delivered to following email address */
            /* But remember not all smtp server allow use different email address */
            //props.put("mail.smtp.from", "pritomkucse@gmail.com");

            message.setFrom(new InternetAddress(userName, "Pritom Kumar", "UTF-8"));
            message.setReplyTo(InternetAddress.parse(userName, false));
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(toAddress, toAddress, "UTF-8"));

            message.setSentDate(new Date());
            message.setSubject(subject, "UTF-8");
            Multipart multipart = new MimeMultipart();

            BodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setContent("This is <b>message</b> body, pls see "
                    + "<i style='color: blue; font-size: 40px;'>attachments</i>", "text/html");
            multipart.addBodyPart(messageBodyPart);

            for( int i = 0; i < attachments.split(";").length; i++) {
                String fileName = attachments.split(";")[i];
                messageBodyPart = new MimeBodyPart();
                DataSource source = new FileDataSource(fileName);
                messageBodyPart.setDataHandler(new DataHandler(source));
                messageBodyPart.setFileName(source.getName());
                messageBodyPart.setHeader("Content-ID", "<CONTENT_" + i + ">");
                multipart.addBodyPart(messageBodyPart);
            }

            /* Some custom headers added to email */
            message.addHeader("header-1", "header-1-value");
            message.addHeader("header-2", "header-2-value");

            messageBodyPart = new MimeBodyPart();
            messageBodyPart.setContent("<h1>Attachments are added.</h1>Attached image as embedded:<br/>"
                    + "<img style='width: 50px;' src='cid:CONTENT_4'/>", "text/html");
            multipart.addBodyPart(messageBodyPart);

            message.setContent(multipart );
            println("Start sending email...");
            Transport.send(message);
            println("Mail sent with message ID=" + message.getMessageID());
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static void println(Object o) {
        System.out.println(o);
    }
}

Console output would be like following

Start sending email...
Mail sent with message ID=<2059904228.1.1477967571904.JavaMail.pritom@PRITOM-PC>

In my gmail inbox email would be render as follows:



Use following code block if you want to use SSL Authentication


props.put("mail.smtp.host", HOST);
props.put("mail.smtp.socketFactory.port", PORT);
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.port", PORT);

GRAILS Database Data To XML File


import grails.converters.XML

grailsApplication.domainClasses.each { def domainClass ->
    dataMap[domainClass.clazz.simpleName] = domainClass.clazz.findAll();
}
String xmlString = new XML(dataMap).toString()

Read & Construct CSV File Using Java Code




package com.pritom.kumar;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by pritom on 10/10/2014.
 */
public class ReadCsvFile {
    final static Charset ENCODING = StandardCharsets.UTF_8;
    private Integer maxRowSize = 0;
    List dataList = new ArrayList();
    public String DELIMITER = ",";

    public static void main(String[] args) throws Exception {
        ReadCsvFile readCsvFile = new ReadCsvFile();
        Long started = System.currentTimeMillis();
        readCsvFile.run();
        Long finished = System.currentTimeMillis();
        Long timeTaken = finished - started;
        readCsvFile.prettyPrint();
        readCsvFile.println("Time Taken: " + timeTaken + " Milli Seconds.");
        readCsvFile.println(readCsvFile.toHtml("csv-output.html"));
        readCsvFile.println(readCsvFile.toCsv("csv-output.csv"));
        System.exit(200);
    }

    public String toCsv(String fileName) throws Exception {
        File file = new File(fileName);
        List fileLines = new ArrayList();
        for (Object object : dataList) {
            fileLines.add(listToBuffer((List) object).toString());
        }
        writeStringList(fileLines, file.getAbsolutePath());
        return file.getAbsolutePath();
    }

    private StringBuffer listToBuffer(List data) {
        StringBuffer stringBuffer = new StringBuffer();
        Boolean firstValue = true;
        for (Object value : data) {
            String line = value.toString();
            if (!firstValue) {
                stringBuffer.append(DELIMITER);
            }
            stringBuffer.append("\"");
            for (Integer index = 0; index < line.length(); index++) {
                char chars = line.charAt(index);
                if (chars == '\"') {
                    stringBuffer.append("\"");
                }
                stringBuffer.append(chars);
            }
            stringBuffer.append("\"");
            firstValue = false;
        }
        return stringBuffer;
    }

    public String toHtml(String fileName) throws Exception {
        File file = new File(fileName);
        List fileLines = new ArrayList();
        for (Integer dataIndex = 0; dataIndex < dataList.size(); dataIndex++) {
            List columnData = (ArrayList) dataList.get(dataIndex);
            maxRowSize = columnData.size() > maxRowSize ? columnData.size() : maxRowSize;
        }
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("<table>");
        for (Integer dataIndex = 0; dataIndex < dataList.size(); dataIndex++) {
            List columnData = (ArrayList) dataList.get(dataIndex);
            stringBuffer.append("<tr><td>" + (dataIndex + 1) + "</td>");
            for (Integer headerIndex = 0; headerIndex < maxRowSize; headerIndex++) {
                stringBuffer.append("<td style='border: 1px solid black;'>" +(columnData.size() > headerIndex ? columnData.get(headerIndex) : "") + "&nbsp;</td>");
            }
            stringBuffer.append("</tr>\n");
            if (dataIndex % 10 == 0) {
                fileLines.add(stringBuffer.toString());
                stringBuffer = new StringBuffer();
            }
        }
        stringBuffer.append("</table>");
        fileLines.add(stringBuffer.toString());
        writeStringList(fileLines, file.getAbsolutePath());
        return file.getAbsolutePath();
    }

    public Boolean writeStringList(List<String> aLines, String aFileName) throws IOException {
        try {
            Path path = Paths.get(aFileName);
            Files.write(path, aLines, ENCODING);
            return true;
        }
        catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    public void prettyPrint() {
        for (Integer dataIndex = 0; dataIndex < dataList.size(); dataIndex++) {
            List columnData = (ArrayList) dataList.get(dataIndex);
            print((dataIndex + 1) + ": ");
            for (Integer headerIndex = 0; headerIndex < columnData.size(); headerIndex++) {
                print("<" + columnData.get(headerIndex) + ">");
                if (headerIndex + 1 < columnData.size()) {
                    print(", ");
                }
            }
            println("");
        }
    }

    public void run() throws Exception {
        String csvFile = "input.csv";
        BufferedReader br = null;
        FileReader fileReader = new FileReader(csvFile);
        String line = "";
        try {
            br = new BufferedReader(fileReader);
            while ((line = br.readLine()) != null) {
                if (line.trim().length() > 0) {
                    List tempDataList = parseLine(line.trim());
                    maxRowSize = tempDataList.size() > maxRowSize ? tempDataList.size() : maxRowSize;
                    dataList.add(tempDataList);
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private List parseLine(String string) throws Exception{
        InputStream stream = new ByteArrayInputStream(string.getBytes("UTF-8"));
        Reader fr = new InputStreamReader(stream, "UTF-8");
        int chars = fr.read();
        while (chars == '\r') {
            chars = fr.read();
        }
        if (chars < 0) {
            return new ArrayList();
        }
        List dataList = new ArrayList();
        StringBuffer stringBuffer = new StringBuffer();
        Boolean inQuotes = false, lineStarted = false;
        while (chars > 0) {
            if (inQuotes) {
                lineStarted = true;
                if (chars == '\"') {
                    inQuotes = false;
                }
                else {
                    stringBuffer.append((char) chars);
                }
            }
            else {
                if (chars == '\"') {
                    inQuotes = true;
                    if (lineStarted) {
                        stringBuffer.append('\"');
                    }
                }
                else if (chars == DELIMITER.charAt(0)) {
                    dataList.add(stringBuffer.toString());
                    stringBuffer = new StringBuffer();
                    lineStarted = false;
                }
                else if (chars == '\r') {

                }
                else if (chars == '\n') {
                    break;
                }
                else {
                    stringBuffer.append((char) chars);
                }
            }
            chars = fr.read();
        }
        dataList.add(stringBuffer.toString());
        return dataList;
    }

    private void print(Object object) {
        System.out.print(object);
    }

    private void println(Object object) {
        System.out.println(object);
    }
}

Output would be like this:


1: <permalink>, <company>, <numEmps>, <category>, <city>, <state>, <fundedDate>, <raisedAmt>, <raisedCurrency>, <round>
2: <lifelock>, <LifeLock Limited,Company">, <>, <web>, <Tempe>, <AZ>, <1-May-07>, <6850000>, <USD>, <b>
....................
1459: <myrio>, <Myrio>, <75>, <software>, <Bothell>, <WA>, <1-Jan-01>, <20500000>, <USD>, <unattributed>
1460: <grid-networks>, <Grid Networks>, <>, <web>, <Seattle>, <WA>, <30-Oct-07>, <9500000>, <USD>, <a>
1461: <grid-networks>, <Grid Networks>, <>, <web>, <Seattle>, <WA>, <20-May-08>, <10500000>, <USD>, <b>
Time Taken: 96 Milli Seconds.
C:\codes\javap\csv-output.html
C:\codes\javap\csv-output.csv