Fork me on GitHub

6/01/2013

Deploy Jersey in the Openfire plugin

Let's say, the original method to access the openfire service by http is by HttpServlet (ex. presence plugin). So, how to replace it with Jersey for convenient development? In this post, I will detail the steps and the problems I met during achieving this.

The main reference is here. Assuming that you have successfully run a self-made plugin.


Step1. Modify the web-custom.xml

The web-custom.xml tells the container where to search for resource class. From that reference. There is some tricks in the web-custom.xml processing in openfire. So we need a wrapper, and finding the true resource class package there. As below. The class in the <servlet-class> tag is your wrapper class, the path in <url-pattern> is the base url you want.

<!-- Servlets -->
<servlet>
    <servlet-name>BrownyServlet</servlet-name>
    <servlet-class>com.brownylin.openfire.plugin.browny.BrownyServletWrapper</servlet-class>
</servlet>

<!-- Servlet mappings -->
<servlet-mapping>
    <servlet-name>BrownyServlet</servlet-name>
    <url-pattern>/test</url-pattern>
</servlet-mapping>

Step2. Tell Wrapper where to find resource class

The trick in the wrapper class is to find resouce class by PackagesResourceConfig. Below sample is referenced from that link.

The resouce class should be under the same package (or inner) as the wrapper class.

AuthCheckFilter.addExclude(SERVLET_URL); is used for avoiding the need of login to access the api.

    
public class BrownyServletWrapper extends ServletContainer {

    private static final long serialVersionUID = 1L;
    private static final String SERVLET_URL = "browny/test/*";
    private static final String SCAN_PACKAGE_KEY = "com.sun.jersey.config.property.packages";
    private static final String SCAN_PACKAGE_DEFAULT = BrownyServletWrapper.class
        .getPackage().getName();

    private static final String RESOURCE_CONFIG_CLASS_KEY = "com.sun.jersey.config.property.resourceConfigClass";
    private static final String RESOURCE_CONFIG_CLASS = "com.sun.jersey.api.core.PackagesResourceConfig";

    private static Map<String, Object> config;
    private static PackagesResourceConfig prc;

    static {
        config = new HashMap<String, Object>();
        config.put(RESOURCE_CONFIG_CLASS_KEY, RESOURCE_CONFIG_CLASS);
        config.put(SCAN_PACKAGE_KEY, SCAN_PACKAGE_DEFAULT);
        prc = new PackagesResourceConfig(SCAN_PACKAGE_DEFAULT);
        prc.setPropertiesAndFeatures(config);
        prc.getClasses().add(BrownyResources.class);
    }

    public BrownyServletWrapper() {
        super(prc);
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);

        // Exclude this servlet from requering the user to login
        AuthCheckFilter.addExclude(SERVLET_URL);
    }

    @Override
    public void destroy() {
        super.destroy();
        // Release the excluded URL
        AuthCheckFilter.removeExclude(SERVLET_URL);
    }
}

Step3. The Jersey dependent jar library

They are asm-3.3.1.jar, jersey-bundle-1.10-b01.jar, jersey-servlet-1.17.1.jar, jsr311-api-1.1.1.jar. If wrong dependency, the ClassNotFoundException, ClassNotDefException will happen (you could find the error from openfire_src/target/openfire/logs/error.log)


Step4. The Resource class

The trick here is the @Path() should starts from plugin name, later servlet url-pattern and at the end - path of the your resouce. So that is @Path("browny/test/hello")

    
package com.brownylin.openfire.plugin.browny;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

@Path("browny/test/hello")
public class BrownyResources {

    @GET
    @Path("/")
    public Response getMsg() {

        String output = "Jersey say Hello";
        return Response.status(200).entity(output).build();

    }
}

Step5. Don't want result shown in openfire admin console

As this thread said. The default configuration is to capture all text/html content from the server and force it into the admin page.

You could add the url pattern you want to exclude in openfire_src/src/web/WEB-INF/decorators.xml as below

<decorators defaultdir="/decorators">
    <decorator name="setup" page="setup.jsp">
        <pattern>/setup/*.jsp</pattern>
    </decorator>
    <decorator name="main" page="main.jsp">
          <pattern>/*.jsp</pattern>
          <pattern>/plugins</pattern>
    </decorator>
    <decorator name="none"/>
    <excludes>
        <pattern>/setup/setup-completed.jsp*</pattern>
        <pattern>/setup/setup-ldap-server_test.jsp*</pattern>
        <pattern>/setup/setup-ldap-user_test.jsp*</pattern>
        <pattern>/setup/setup-ldap-group_test.jsp*</pattern>
        <pattern>/setup/setup-clearspace-integration_test.jsp*</pattern>
        <pattern>/setup/setup-admin-settings_test.jsp*</pattern>
        <pattern>/login.jsp*</pattern>
        <pattern>/plugin-icon.jsp*</pattern>
        <pattern>/js/jscalendar/i18n.jsp*</pattern>
        <pattern>/plugins/browny/test/*</pattern>
    </excludes>
</decorators>

Step6. Test the resource url

Last, test the url localhost:9090/plugins/browny/test/hello. It's done. Hope this will be useful to someone :)

-- EOF --

5/13/2013

Git alias problem

Recently, don't know why, I found the git aliasing does not work. When I use git st aliasing command, I got below error:

fatal: cannot exec 'git-st': Not a directory
Problem is /usr/bin/python is not directed to directory

After search for a while, I found it should be caused by my environment variable PATH.

Use the command echo $PATH |tr ':' '\n' |xargs ls -ld, I found there is a symbolic link in the list /usr/bin/python -> python2.7 If it is removed, the git aliasing problem is gone.

I think it should be noticed that the environment path should points to directories not to files.

[~]$ echo $PATH |tr ':' '\n' |xargs ls -ld

drwxr-xr-x 2 root      root         4096 Apr 17 09:52 /bin
drwxrwxr-x 2 brownylin brownylin    4096 Apr 25 09:41 /home/brownylin/Java/maven3/bin
drwxr-xr-x 2 root      root        40960 May  9 13:07 /usr/bin
lrwxrwxrwx 1 root      root            9 Apr 15 15:54 /usr/bin/python -> python2.7
drwxr-xr-x 2 root      root         4096 Apr 24 11:34 /usr/local/bin


References

Git alias problem
http://stackoverflow.com/questions/4019501/git-alias-problem

5/06/2013

Personal wiki based on vimwiki

Recently, I am looking for a simple solution for personal wiki. My basic requirement is no need of database, easy deploy and lightweight.

Finally, I found the vimwiki is a perfect solution with some other services.

vimwiki: Simple syntax, perfectly integrated with vim. Export each single wiki to separate html file.
google-code-prettyfy: Used to make code snippets well formated.
Github pages: Used to host/publish the wiki.
Bootswatch: There are many beautiful and basic templates to beautify your wiki

Below is a brief description about how to setup the personal wiki which utilize above tools. Enjoy them :)


1. Vimwiki installation

https://code.google.com/p/vimwiki/wiki/Installation

  1. Download and unpack vimwiki_N_N.zip. (N_N is version number ie 0_8)
  2. Place unpacked files into (create directory if it isn't exists):
    Linux: ~/.vim/
    Windows: ~/vimfiles/, where ~ is a home directory, usually C:\Documents and Settings\USERNAME\
  3. To install help, open Vim and run :helptags ~/vimfiles/doc command.
  4. Modify vimrc as below, <F4> is mapped to generate html
" // --- vimwiki --- //
let g:vimwiki_list = [{'path': '~/Dropbox/vimwiki/',
			\'template_path': '~/Dropbox/vimwiki/template/',
			\'template_default': 'default',
			\'template_ext': '.html',
			\'path_html': '~/Dropbox/github/vimwiki/'}]

map <F4> :VimwikiAll2HTML<cr>


2. Use google-code-prettify for code highlight

https://code.google.com/p/google-code-prettify/

1. Download code-prettify (ex: prettify-small-4-Mar-2013.tar.bz2)
https://code.google.com/p/google-code-prettify/downloads/list

2. Modify the default vimwiki template
Add below code block before </head> and change <body> to <body onload='prettyPrint()'>

Use your prettify.js and prettify.css instead of http://XXX/prettify.css and ttp://XXX/prettify.js

<link href='http://XXX/prettify.css' rel='stylesheet' type='text/css'/>
<script language='javascript' src='http://XXX/prettify.js' type='text/javascript'/>
<script type='text/javascript'>
document.addEventListener(&#39;DOMContentLoaded&#39;,function() { prettyPrint();});
</script>

The result default.html of vimwiki should looks like as below

<html>
<head>
<link rel="Stylesheet" type="text/css" href="%root_path%%css%">
<title>%title%</title>
<meta http-equiv="Content-Type" content="text/html; charset=%encoding%">
<!-- Bootstrap: Bootswatch template goes here -->
<link href="http://XXX/bootstrap.min.css" rel="stylesheet"
media="screen" type='text/css'>

<!-- google-code-prettify -->
<link href='http://XXX/prettify.css' rel='stylesheet' type='text/css'/>
<script language='javascript' src='http://XXX/prettify.js' type='text/javascript'/>
<script type='text/javascript'>
document.addEventListener(&#39;DOMContentLoaded&#39;,function() { prettyPrint();});
</script>

</head>
<body onload='prettyPrint()'>
%content%
</body>
</html>


3. Use Github pages to host/publish you wiki

http://pages.github.com/

  1. Build a project page for the vimwiki
    https://help.github.com/articles/creating-project-pages-manually

4/22/2013

First week java web development - WD-041913

Last week, I start my journey on back-end web development. Below are some references from internet for getting some basic understanding on java web development.

Resources


Introduction into Java Web development

This tutorial introduces some basic concept about web development and java part: JSP and servlet.

REST with Java (JAX-RS) using Jersey - Tutorial

This helps me to build a simple JAX-RS web app and deploy it to Tomcat servlet container.

MySQL and Java JDBC - Tutorial & Connect To MySQL With JDBC Driver

These help me understand how to use JDBC to access MySQL database.

Definition


What is Java Servlet

A servlet is a Java programming language class used to extend the capabilities of a server. Technically speaking, a "servlet" is a Java class in Java EE that conforms to the Java Servlet API.

Servlets are most often used to

  • Process or store data that was submitted from an HTML form
  • Provide dynamic content such as the results of a database query
  • Manage state information that does not exist in the stateless HTTP protocol, such as filling the articles into the shopping cart of the appropriate customer

Problems


Below are some solution for the problem I met

INSTALLING Oracle Java JDK 7 On Ubuntu 12.04 Step By Step

How do I import the javax.servlet API in my Eclipse project?

Right click on project ---> Properties ---> Java Build Path ---> Add Library... ---> Server Runtime ---> Apache Tomcat ----> Finish.

Apache2, MySQL, php, phpmyadmin installation on ubuntu12.04

注意,要把 phpadmin conf 加到 apache 裡面

Ref: 1, 2

sudo vim /etc/apache2/apache2.conf  
Include /etc/phpmyadmin/apache.conf //Add the phpmyadmin config to the file    
sudo service apache2 restart //then restart apache

Java Naming and Directory Interface

-- EOF --

4/03/2013

[Bash] Annoying directory green highlight in terminal

Recently, I found some directory become green highlighted in the background when I issue ls command as below picture.

After google that, it is due to the write permission of the others (as the red mark in the picture). There are 2 ways to fix this annoying coloring.

  1. Change the bash color setting: refer to the Reference 2
  2. Use the chmod to recover the directory permission to default 755, or use below command to recursively set all directory to default 755

    $ find . -type d -print0 | xargs -0 chmod 755 
    

Ref

  1. Gnome-terminal syntax highlighting - green highlight?
  2. NTFS directory coloring in terminal
  3. Wikipedia: File system permissions
  4. Wikipedia: Sticky_bit
  5. How to chmod 755 all directories but no file (recursively)

--EOF--

3/31/2013

[Algorithm] Money Change Problem (dynamic programming)

Question

Given a list of N coins, their values being in an array A[], return the minimum number of coins required to sum to S (you can use as many coins you want). If it's not possible to sum to S, return -1

Below are the solutions by "greedy" and "dynamic programming"
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

// greedy
int minCoins_greedy(vector<int> a, int sum) {

    sort(a.begin(), a.end(), greater<int>()); // sorted in descending order
    a.erase(unique(a.begin(), a.end()), a.end()); // remove duplicates

    int ret;
    for (int i = 0; i < a.size(); i  ) {
        int remains = sum - a[i];
        //cout << sum << " - " << a[i] << " = " << remains << endl;
        if (remains > 0) {
            ret = minCoins_greedy(a, remains);
            //cout << "ret: " << ret << endl;
            if (ret > 0) {
                cout << a[i] << "   ";
                return   ret;
            }
        } else if (remains == 0) {
            cout << a[i] << "   ";
            return 1;
        }
    }
    return -1;
}

// dynamic programming
#define MIN(a, b) ((a) == -1) ? (b) : min((a),(b));
int minCoins(vector<int> S, int sum) {

    int setSize = S.size();
    int count[setSize 1][sum 1];

    // For sum = 0, do not need any coins
    for (int i = 0; i < setSize 1; i  )
        count[i][0] = 0;

    // For empty set, it is impossible to sum to >0
    // use -1 represents fail
    for (int j = 1; j < sum 1; j  )
        count[0][j] = -1;

    /*
     * cost func:
     * c(n, m) = min( c(n-1, m) , c(n, m-M[n])   1 )
     *                ^^^^^^^^^   ^^^^^^^^^^^^^^^^
     *                don't take     take M[n]
     */
    for (int i = 1; i < setSize 1; i  ) {
        for (int j = 1; j < sum 1; j  ) {
            if ((j - S[i-1]) >= 0) {
                count[i][j] = MIN(count[i-1][j], count[i][j-S[i-1]]   1);
            }
            else
                count[i][j] = count[i-1][j];
        }
    }

    // uncomment this code to print table
    /*
    for (int i = 0; i <= setSize; i  )
    {
        for (int j = 0; j <= sum; j  )
            printf ("%4d", count[i][j]);
        printf("\n");
    }
    */

    return count[setSize][sum];
}


int main() {

    // Input to a sorted vector
    int size, sum;
    cout << "input 'size' and 'sum'" << endl;
    cout << "ex: 4 63" << endl;
    cin >> size >> sum;

    cout << "input coins" << endl;
    cout << "ex: 1 10 30 40" << endl;

    int* arr;
    arr = new int[size];
    for (int i = 0; i < size; i  ) {
        int c;
        cin >> c;
        arr[i] = c;
    }
    vector<int> vecArr(arr, arr size);

    // Output
    int out = minCoins(vecArr, sum);
    //int out = minCoins_greedy(vecArr, sum);

    cout << endl;
    if (out > 0)
        cout << "Minimum " << out << " coins needed" << endl;
    else
        cout << "Impossible" << endl;

    delete[] arr;

    return 0;
}

Ref

  1. Wikipedia: Dynamic programming
  2. Lecture 12: More about debugging, knapsack problem, introduction to dynamic programming
  3. The 0/1 Knapsack Problem - Dynamic Programming Method
  4. Dynamic Programming | Set 25 (Subset Sum Problem)
  5. Money Changing Problem 之一