Simple Java BBCode Implementation

I have made a simple Java BBCode Implementation, and it is open source and free to use. Feel free to take it into your project.

Below is the Java static method to convert the bbcode-based text into HTML form to be displayed in browser.

public static String bbcode(String text) {

String temp = nl2br(text);

Map<string , String> bbMap = new HashMap</string><string , String>();</string>

bbMap.put(“\\[b\\](.+?)\\[/b\\]”, “<strong>$1</strong>”);

bbMap.put(“\\[i\\](.+?)\\[/i\\]”, “<span style=’font-style:italic;’>$1</span>”);

bbMap.put(“\\[u\\](.+?)\\[/u\\]”, “<span style=’text-decoration:underline;’>$1</span>”);

bbMap.put(“\\[h1\\](.+?)\\[/h1\\]”, “<h1>$1</h1>”);

bbMap.put(“\\[h2\\](.+?)\\[/h2\\]”, “<h2>$1</h2>”);

bbMap.put(“\\[h3\\](.+?)\\[/h3\\]”, “<h3>$1</h3>”);

bbMap.put(“\\[h4\\](.+?)\\[/h4\\]”, “<h4>$1</h4>”);

bbMap.put(“\\[h5\\](.+?)\\[/h5\\]”, “<h5>$1</h5>”);

bbMap.put(“\\[h6\\](.+?)\\[/h6\\]”, “<h6>$1</h6>”);

bbMap.put(“\\[quote\\](.+?)\\[/quote\\]”, “<blockquote>$1</blockquote>”);

bbMap.put(“\\[p\\](.+?)\\[/p\\]”, “<p>$1</p>”);

bbMap.put(“\\[p=(.+?),(.+?)\\](.+?)\\[/p\\]”, “<p style=’text-indent:$1px;line-height:$2%;’>$3</p>”);

bbMap.put(“\\[center\\](.+?)\\[/center\\]”, “<div align=’center’>$1”);

bbMap.put(“\\[align=(.+?)\\](.+?)\\[/align\\]”, “<div align=’$1′>$2”);

bbMap.put(“\\[color=(.+?)\\](.+?)\\[/color\\]”, “<span style=’color:$1;’>$2</span>”);

bbMap.put(“\\[size=(.+?)\\](.+?)\\[/size\\]”, “<span style=’font-size:$1;’>$2</span>”);

bbMap.put(“\\[img\\](.+?)\\[/img\\]”, “<img src=’$1′ />”);

bbMap.put(“\\[img=(.+?),(.+?)\\](.+?)\\[/img\\]”, “<img width=’$1′ height=’$2′ src=’$3′ />”);

bbMap.put(“\\[email\\](.+?)\\[/email\\]”, “<a href=’mailto:$1′>$1</a>”);

bbMap.put(“\\[email=(.+?)\\](.+?)\\[/email\\]”, “<a href=’mailto:$1′>$2</a>”);

bbMap.put(“\\[url\\](.+?)\\[/url\\]”, “<a href=’$1′>$1</a>”);

bbMap.put(“\\[url=(.+?)\\](.+?)\\[/url\\]”, “<a href=’$1′>$2</a>”);

bbMap.put(“\\[video\\](.+?)\\[/video\\]”, “<video src=’$1′ />”);

for (Map.Entry entry: bbMap.entrySet()) {

temp = temp.replaceAll(entry.getKey().toString(), entry.getValue().toString());

}

return temp;

}


6 June 2011
Refer to stackoverflow, there is one topic that is related to Java BBCode I discovered just now.

SmokeScreen Convert Flash into HTML5+JavaScript

SmokeScreen, a project utilize JavaScript and HTML5, to convert Flash into pure HTML5 + JavaScript, therefore user can browser the Flash animation without Flash Plugin.

Chris Smoak, a programmer, recently started a project called SmokeScreen, to convert Flash into pure HTML5 + JavaScript, therefore user can browser the Flash animation without Flash Plugin. Here have some fantastic demo.

SmokeScreen totally run inside the browser, it reads SWF binary file, decrypt it using local JavaScript Online!!!, it retrieves the images and sound data from the SWF, convert them into Base64-encoded data. Then, it converts its vector graphic into SVG animation. We can use Google Chrome to open Web Inspector. During the time the demo running, you can see SVG is running in the real time. SmokeScreen also designed his own ActionScript compiler.

Most importantly, this converted animation can be viewed inside iPad and iPhone as well.

JSF 2 f:ajax why execute onevent three times?

Recently when I doing <f:ajax> inside JSF 2.0, I specify onevent javascript callback function, when f:ajax execute to the server and return to the client, it will call the javascript callback function. But I discovered that it will call the function three times. Afterwards when I checked the Javascript Console Log in Google, I discovered onevent will have three different status when it called the function.

The status are: begin, complete, success.

Therefore, the problem has known. We just have to define an onevent callback function as below.

function onevent(e) {
    if(e.status == ‘success’) {
        // TODO: your business
    }
}

Variable access using JavaScript OO

Based on Java coding:

public Class Dog {
    int a = 1;;
    int b = this.a;
    public int c() {
        return a+b;
    }
}

Corresponding with JavaScript, we have:

function Dog() {
    d = new Object();
    d.a = 1;
    d.b = d.a;
    d.c = function() {
        return this.a+this.b;
    }
    return d;
}

Remember in JavaScript, if variable b want to get variable a, should use d.a but not this.a, however inside method, want to get variable a, should use this.a instead of d.a.

This is a kind of JavaScript Object-oriented reliazation method.

Simple Web Form Showcase

As I am in the journey of learning web page design, now I am in the stage of designing web form layout. There is a long run of research on the web form layout such as the place where the label to be put, the font size or font weight of the text should be put, and etc.

By referring to the Luke W Research and UxMatters Blog, I have found some useful information that can help me to design a web form.

I have created a sample web form layout and I am now going to show the design for the reader. But please be noted that what I show here is not the final decision and will be changed later. Try give me any comments after you have tested it.

Screenshots

First, let us see the screenshots of the web form layout:

Sample Web Form Layout from fyhao.com 

HTML / CSS

Second, let us see the HTML / CSS coding that make the above web form layout real life.

HTML

<!– form –>
            <div class="form">
                <h2>Sample Form</h2>
                <p>
                    <label>Name: </label><span class="required">(Required)</span>
                    <br /><span class="error">Error Message Here. Error Message Here. Error Message Here. Error Message Here.Error Message Here. Error Message Here.  </span>
                    <input class="text" type="text" value="Default" />
                    <br />
                    <div class="fieldinfo">You cannot put illegal name here</div>
                </p>
                <p>
                    <label>Name: </label><span class="required">(Required)</span>
                    <br /><span class="error">test </span>
                    <textarea class="text">Default</textarea>
                    <br />
                    <div class="fieldinfo">You cannot put illegal name here</div>
                </p>
                <p>
                    <label>Name: </label><span class="required">(Required)</span>
                    <br /><span class="error">Error Message Here. Error Message Here. Error Message Here. Error Message Here.Error Message Here. Error Message Here. Error Message Here. Error Message Here. Error Message Here. Error Message Here. Error Message Here.  </span>
                    <input class="text" type="text" value="Default" />
                    <br />
                    <div class="fieldinfo">You cannot put illegal name here</div>
                </p>
                <p>
                    <label>Hobby: </label><span class="required">(Required)</span>
                    <br /><span class="error">Error Message Here. Error Message Here. Error Message Here. Error Message Here.Error Message Here. Error Message Here.  </span>
                    <span class="group">
                        <span class="pair"><input type="radio" /> One </span>
                        <span class="pair"><input type="radio" /> One </span>
                        <span class="pair"><input type="radio" /> One </span>
                        <span class="pair"><input type="radio" /> One </span>
                        <span class="pair"><input type="radio" /> One </span>
                        <span class="pair"><input type="radio" /> One </span>
                    </span>
                    <br />
                    <div class="fieldinfo">You cannot put illegal name here</div>
                </p>
                <p>
                    <label>Like: </label><span class="required"></span>
                    <span class="error"></span>
                    <span class="group">
                        <span class="pair"><input type="checkbox" /> One </span>
                        <span class="pair"><input type="checkbox" /> One </span>
                        <span class="pair"><input type="checkbox" /> One DDSFSF </span>
                        <span class="pair"><input type="checkbox" /> One  sfsdfsfsf</span>
                        <span class="pair"><input type="checkbox" /> One </span>
                        <span class="pair"><input type="checkbox" /> One </span>
                    </span>
                    <br />
                    <div class="fieldinfo">Just choose what you like</div>
                </p>
                <p>
                    <input class="button" type="button" value="Submit" />
                </p>
            </div>
            <!– form –>

 

CSS

/* form */
.form {border:#CCC solid 1px;padding:0.5em;}
.form h2 {text-align:center;font-size:1.3em;}
.form p {margin:0.8em auto 0.8em auto;clear:both;}
.form label {font-weight:bold;}
.form .required {color:#666;font-weight:bold;}
.form .fieldinfo {color:#666;font-size:0.85em;clear:left;margin-top:1em;}
.form .error {color:red;font-size:0.8em;float:right;width:20em;margin:1em auto auto auto;text-align:justify;}
.form .text {margin:1em 1em auto auto;width:20em;}
.form .button {width:auto;}
.form .group {margin-bottom:2em;width:20em;display:block;margin-top:0.5em;}
.form .group .pair {display:block;float:left;}

Hello World to Direct Web Remoting

This is a simple article that how to hello world to DWR (Direct Web Remoting).

First, go http://directwebremoting.org/dwr/download.html download dwr.jar, for me I download 2.0.6 version in order it can be supported in Google Appengine. Put dwr.jar in WEB-INF/lib

Second, download commons-logging-1.1.1.jar, put this jar in WEB-INF/lib also.

Third, modify web.xml to add this content of

    <servlet>
  <servlet-name>dwr-invoker</servlet-name>
  <display-name>DWR Servlet</display-name>
  <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
  <init-param>
     <param-name>debug</param-name>
     <param-value>true</param-value>
  </init-param>
</servlet>

<servlet-mapping>
  <servlet-name>dwr-invoker</servlet-name>
  <url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

Fourth, create dwr.xml and with the content of

<!DOCTYPE dwr PUBLIC
    "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
    "
http://getahead.org/dwr/dwr20.dtd">

<dwr>
  <allow>
    <create creator="new" javascript="DWRStuff">
      <param name="class" value="com.fyhao.secs.DWRStuff"/>
    </create>
  </allow>
</dwr>

Then you have to create DWRStuff.java file with the content of

package com.fyhao.secs;

public class DWRStuff {

    public String shownum(int a) {
        return "" + (a * 3);
    }
}

Create a JSP file, called ajax.jsp with the content of

<%@ page contentType="text/html; charset=utf-8" language="java" import="java.sql.*" errorPage="" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script src=’dwr/interface/DWRStuff.js’></script>
<script src=’dwr/engine.js’></script>
<script type="text/javascript">
function update() {
    DWRStuff.shownum(5, function(data) {
                                 alert(data);
                                 });
}
</script>
</head>

<body>
<div id="num"></div>
<script>update();
</script>
</body>
</html>

Remember the DWRStuff.js shown in the script source there.

Now, you can try to see if it is success.

Appengine JPA persist data problem

There is sometime coding JPA persist data problem may occured.

For example, I have a code that is about:

public class MemberBean {

    public void registerMember(Members member) {
        EntityManager em = EMF.get().createEntityManager();
        try {
            em.persist(member);
            //em.refresh(member);
        } finally {
            em.close();
        }
    }

As you can see that, if you run this code, sometimes you will got:

Problem accessing /fyhaosecs. Reason:

    Illegal argument
Caused by:
javax.persistence.PersistenceException: Illegal argument
	at org.datanucleus.jpa.NucleusJPAHelper.getJPAExceptionForJDOException(NucleusJPAHelper.java:214)
	at org.datanucleus.jpa.EntityManagerImpl.close(EntityManagerImpl.java:157)
	at org.datanucleus.store.appengine.jpa.DatastoreEntityManager.close(DatastoreEntityManager.java:54)
	at com.fyhao.secs.MemberBean.registerMember(MemberBean.java:18)
	at com.fyhao.secs.FyhaosecsServlet.doGet(FyhaosecsServlet.java:24)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:693)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)

Solution:

The solution is: just add em.refresh(member); after you persist.

You can also refer to this link: http://www.datanucleus.org/products/accessplatform_1_1/jpa/em.html

Web Design Learning Journey 1

As I now try to research some web design blog and article, to learn something about web design. What I learnt I will put in this blog content.

1. Resize Text in Typography

The research from “How To Size Text in CSS” tells us that, not every browser supports pixel in text size, however we can use em to specify the text size. It had gone through six iterations, such as “text size in pixels”, “text size in ems”, “body sized as percentage”, “setting line height in pixels”, “setting line height in ems” and “the Safari monospace problem”. By doing this, we can get something like this:

<style type="text/css">
body {
    font-size:100%; /* retain all font sizes first */
    line-height:1.125em; /* 1.125 x 16 = 18px */
}

.bodytext p {
    font-size:0.875em;
}

.sidenote {
    font-size:0.75em;
}
</style>

<!--[if !IE]>-->

<style type="text/css">
body {
    font-size:16px;
}
</style>

<!--<[endif]-->

Here we have Complex Example (A List Apart, n.d.) that showed us the way in sizing text. Refer to its CSS file, we can see that font-size, line-height, margin, both of them are using em to resize. We can refer to this in doing typography.

I have found another articles Line Spacing (Typographyforlawyers, 2008) tells us the optimal line spacing is usually between 125% and 140% of the font size. It is meant that for 12 px font, the font size must be somewhere between 15px to 17px.

I recently found that “Type is the backbone of good web design” (TheDesignCubicle, 2009), it gives web designer some hints on designing the typography. I have summarized the important point that is found from there.

Line Height

.bodytext p {
font-size:1em; /* 1em=16px */
line-height: 1.5em; /*1.5em of a 1em (or 16px font) = 24px
}

What he recommended is the line height we can just set to 1.5em, however, I have learnt this technique before, but here is the good explanation why we should put this. 1.5 em is the good and readable line height for body copy, it said.

Letter Spacing between All Caps and small caps

It said that we should introduce one px letter spacing for all caps and small caps because it bring a long nice balance of the web.

.bodytext p {
font-size:1em; /* 1em=16px */
letter-spacing: 1px;
}

Comfortable reading measures (45-75 characters)

The Elements of Typographic Style Applied to the Web” (Webtypography.net, n.d.) tells us the comportable measure for the text, for single column that is 45-75 characters for one line, 40-50 characters for multiple columns. The CSS we can put is something like this:

DIV#col1 {
  width:400px }

DIV#col2 {
  width:50% }

DIV#col3 {
  width:33em }

But it tells us no matter how reader increases the text size, the width of the box that set in em will always introduce 66 characters per line. Therefore it is recommended we set em in width of the box.

Hierarchy and Contrast

Other than that, it also told us hierarchy and contrast is important in the web page. We should give readers to digest information in chunks, to allow them to retain more information and stay longer on our site.

On Web Typography (Jason, S. M., 2009) told us that contrast is important, even the font face we use. We can try to write down our general description of the message and find one suitable font face that can give qualities to that message. It is recommended using Sans and Serif to give cohesive look. However, there are also other typefaces pairing for example Perpetua and Gill Sans or Meta Sans and Meta Serif. Finding two divergence typefaces can create new meaning or an interesting juxtaposition, as long as the contrast is strong.

Layout

960 Grid System used by TheDesignCubide.com where it employs 960px for the width of the web page. It is a good system that enhance good layout. Looking into, we can find Custom CSS generator, HTML Layout generator inside. There also have some good examples on how to set 12 col and 16 col in grid system. Better we get reference inside.

1KB CSS Grid System is another recommendation from me that, we can choose number of columns, column width and gutter width, then we can download the resulted CSS files without tricky code. Good Recommendation when we need structuring a website.

Do’s and Don’ts of Effective Web Typography

Other than this, Mike Smith had written good posts “20 Do’s and Don’ts of Effective Web Typography“, something had repeated as above, that meant it is agreed by most of the professional web designers. In summary:

  1. we should not use too many different font faces on the page
  2. we should planning for font size increase by the viewer
  3. we should not use Sans Serif for large bodies of text
  4. we should not over emphasis (make bold) in our text
  5. we should remember to use font stacks (in case some face is not owned by some users)
  6. we should use CSS text transform uppercase instead of typing UPPERCASE directly in our text
  7. we should use line height in our text
  8. we should have proper text colors on the page background, it is recommended we using off-white (#F8F8F8) font on a black background or a dark gray (#252525) font on a white background.
  9. we should use proper hierarchy for our web pages, such A List Apart.
  10. we should make use of baseline grid, consistent vertical grid will help readability and increase visual appeal of the overall design
  11. we should use shade variation to make some areas stand out more, such that our body text is black in color, sidebar gray in color, it is able to increase the speed of text reading.
  12. we should have proper letter spacing and make use of typographic scales in our CSS codes.

Other than typography, another “20 Do’s and Don’ts of Effective Web Design” by Mike Smith, we can also reference to there.

ColourLovers contains generated palettes, patterns and colors for web designer to use.

Lastly, this blog article is not still finalized and maybe refined later.

Java Version of Discuz! authcode()

Discuz! is a forum software developed by Comsenz. authcode is a function that able to encrypt the string into human unreadable form and also can decrypt it. The beauty inside is how many times you make encryption, the encrypted string is not same at all, but when you make decryption it is able to change back to original string. Comsenz had made great contribution to the PHP world by authcode function, whereas nowadays many of the PHP developers are using authcode function in their project, even me.

Now, I would like to find some way using Java to manipulate authcode function. However my skill is not talentable from getting authcode function works. Therefore, I searched online and found that the post rain.xie posted on Javaeye Forum. I changed a little bit from there to be hosted on Google Appengine along with my project. Notice that the implementation of Base64 Decoder I am using Google Appengine Library API.

Here is the code:

AuthCode.java

package com.fyhao.gift.helper;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Random;
import com.google.appengine.repackaged.com.google.common.util.Base64;

public class AuthCode {

    public enum DiscuzAuthcodeMode {
        Encode, Decode
    };

    public static String CutString(String str, int startIndex, int length) {
        if (startIndex >= 0) {
            if (length < 0) {
                length = length * -1;
                if (startIndex – length < 0) {
                    length = startIndex;
                    startIndex = 0;
                } else {
                    startIndex = startIndex – length;
                }
            }

            if (startIndex > str.length()) {
                return "";
            }

        } else {
            if (length < 0) {
                return "";
            } else {
                if (length + startIndex > 0) {
                    length = length + startIndex;
                    startIndex = 0;
                } else {
                    return "";
                }
            }
        }

        if (str.length() – startIndex < length) {

            length = str.length() – startIndex;
        }

        return str.substring(startIndex, startIndex + length);
    }

    public static String CutString(String str, int startIndex) {
        return CutString(str, startIndex, str.length());
    }

    public static String MD5(String pass) {
        byte[] defaultBytes = pass.getBytes();
        try{
             MessageDigest algorithm = MessageDigest.getInstance("MD5");
             algorithm.reset();
             algorithm.update(defaultBytes);
             byte messageDigest[] = algorithm.digest();

             StringBuffer hexString = new StringBuffer();
             for (int i=0;i<messageDigest.length;i++) {
            String hex = Integer.toHexString(0xFF & messageDigest[i]);
            if(hex.length()==1)
            hexString.append(‘0’);

            hexString.append(hex);
             }
             return hexString.toString();
        }
        catch(NoSuchAlgorithmException nsae){
        }

        return "";
    }

    public static boolean StrIsNullOrEmpty(String str) {
        //#if NET1
        if (str == null || str.trim().equals("")) {
            return true;
        }

        return false;
    }

    static private byte[] GetKey(byte[] pass, int kLen) {
        byte[] mBox = new byte[kLen];

        for (int i = 0; i < kLen; i++) {
            mBox[i] = (byte) i;
        }

        int j = 0;
        for (int i = 0; i < kLen; i++) {

            j = (j + (int) ((mBox[i] + 256) % 256) + pass[i % pass.length])
                    % kLen;

            byte temp = mBox[i];
            mBox[i] = mBox[j];
            mBox[j] = temp;
        }

        return mBox;
    }

    public static String RandomString(int lens) {
        char[] CharArray = { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘j’, ‘k’,
                ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, ‘w’,
                ‘x’, ‘y’, ‘z’, ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ };
        int clens = CharArray.length;
        String sCode = "";
        Random random = new Random();
        for (int i = 0; i < lens; i++) {
            sCode += CharArray[Math.abs(random.nextInt(clens))];
        }
        return sCode;
    }

    public static String authcodeEncode(String source, String key, int expiry) {
        return authcode(source, key, DiscuzAuthcodeMode.Encode, expiry);

    }

    public static String authcodeEncode(String source, String key) {
        return authcode(source, key, DiscuzAuthcodeMode.Encode, 0);

    }

    public static String authcodeDecode(String source, String key) {
        return authcode(source, key, DiscuzAuthcodeMode.Decode, 0);

    }

    private static String authcode(String source, String key,
            DiscuzAuthcodeMode operation, int expiry) {
        try {
            if (source == null || key == null) {
                return "";
            }

            int ckey_length = 4;
            String keya, keyb, keyc, cryptkey, result;

            key = MD5(key);

            keya = MD5(CutString(key, 0, 16));

            keyb = MD5(CutString(key, 16, 16));

            keyc = ckey_length > 0 ? (operation == DiscuzAuthcodeMode.Decode ? CutString(
                    source, 0, ckey_length)
                    : RandomString(ckey_length))
                    : "";

            cryptkey = keya + MD5(keya + keyc);

            if (operation == DiscuzAuthcodeMode.Decode) {
                byte[] temp;
                temp = Base64.decode(CutString(source, ckey_length));
                result = new String(RC4(temp, cryptkey));
                if (CutString(result, 10, 16).equals(CutString(MD5(CutString(result, 26) + keyb), 0, 16))) {
                    return CutString(result, 26);
                } else {
                    temp = Base64.decode(CutString(source+"=", ckey_length));
                    result = new String(RC4(temp, cryptkey));
                    if (CutString(result, 10, 16).equals(CutString(MD5(CutString(result, 26) + keyb), 0, 16))) {
                        return CutString(result, 26);
                    } else {
                        temp = Base64.decode(CutString(source+"==", ckey_length));
                        result = new String(RC4(temp, cryptkey));
                        if (CutString(result, 10, 16).equals(CutString(MD5(CutString(result, 26) + keyb), 0, 16))) {
                            return CutString(result, 26);
                        }else{
                            return "2";
                        }
                    }
                }
            } else {
                source = "0000000000" + CutString(MD5(source + keyb), 0, 16)
                        + source;

                byte[] temp = RC4(source.getBytes("GBK"), cryptkey);

                return keyc + Base64.encode(temp);

            }
        } catch (Exception e) {
            return "";
        }

    }

    private static byte[] RC4(byte[] input, String pass) {
        if (input == null || pass == null)
            return null;

        byte[] output = new byte[input.length];
        byte[] mBox = GetKey(pass.getBytes(), 256);

        int i = 0;
        int j = 0;

        for (int offset = 0; offset < input.length; offset++) {
            i = (i + 1) % mBox.length;
            j = (j + (int) ((mBox[i] + 256) % 256)) % mBox.length;

            byte temp = mBox[i];
            mBox[i] = mBox[j];
            mBox[j] = temp;
            byte a = input[offset];

            byte b = mBox[(toInt(mBox[i]) + toInt(mBox[j])) % mBox.length];

            output[offset] = (byte) ((int) a ^ (int) toInt(b));
        }

        return output;
    }

    public static int toInt(byte b) {
        return (int) ((b + 256) % 256);
    }

    public long getUnixTimestamp() {
        Calendar cal = Calendar.getInstance();
        return cal.getTimeInMillis() / 1000;
    }

}

Simple URL routing in Servlet

I have made a simple URL routing using servlet in Java. Using MainServlet as the front controller, then decide which service to call.

I have defined MainServlet.java as the Front controller, Service.java as the parent base of service, then GiftService.java for the actual service that will be carried out for action. MainServlet.java will be able to examine the URL, for example by the form of /Gift/send , it will call GiftService class and send method in the GiftService.java. Before that it calls the init method inside Service.java to transfer some instance that maybe used by the Services classes, such as HttpServletRequest, HttpServletResponse, and etc.

MainServlet.java

package com.fyhao.test;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MainServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = request.getPathInfo();
        try {
            String[] parts = path.split("/");
            if(parts.length >= 2) {
                try {
                    Class iClass = Class.forName("com.fyhao.test." + parts[1] + "Service");
                    Method init;
                    Constructor con;
                    Object myClass;
                    try {
                        init = iClass.getMethod("init", new Class[] {HttpServlet.class, HttpServletRequest.class, HttpServletResponse.class, String[].class});
                        con = iClass.getConstructor(new Class[] {});
                        myClass = con.newInstance(new Object[] {});
                        init.invoke(myClass, new Object[]{this, request, response, parts});
                    } catch (NoSuchMethodException ex) {
                        System.err.println("Please define init method on " + parts[1] + "Service");
                        return;
                    } catch (Exception ex) {
                        System.err.println("init exception");
                        return;
                    }
                    Method m;
                    if(parts.length >= 3) {
                        try {
                            m = iClass.getMethod(parts[2], null);
                            m.invoke(myClass);
                        } catch (NoSuchMethodException ex) {
                            try {
                                m = iClass.getMethod("main", null);
                                m.invoke(myClass);
                            } catch (Exception exc) {
                                System.err.println("Please define a main service method on " + parts[1] + "Service");
                                return;
                            }
                        } catch (Exception ex) {
                            System.err.println("service method exception");
                            return;
                        }
                    } else {
                        try {
                            m = iClass.getMethod("main", null);
                            m.invoke(myClass);
                        } catch (Exception exc) {
                            System.err.println("Please define a main service method on " + parts[1] + "Service");
                            return;
                        }
                    }
                } catch (ClassNotFoundException ex) {
                    defaultAction(request, response);
                }
            } else {
                defaultAction(request, response);
            }
        } catch (NullPointerException ex) {
            defaultAction(request, response);
            return;
        }
        //serviceclass("Gift", "send");
    }
    public void defaultAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("default action here: " + request.getPathInfo());
    }
    // leave for reference
    public void serviceclass(String c, String service) {
        try {
            Class iClass = Class.forName("com.fyhao.test." + c + "Service");
            Method init = iClass.getMethod("init", null);
            Method m = iClass.getMethod(service, null);
            Constructor con = iClass.getConstructor(new Class[] {});
            Object myClass = con.newInstance(new Object[] {});
            m.invoke(myClass);
        } catch( Exception ex) {}
    }
}

 

Service.java

package com.fyhao.test;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Service {

    HttpServlet servlet;
    HttpServletRequest request;
    HttpServletResponse response;
    String[] parts;
    public void init(HttpServlet servlet, HttpServletRequest request, HttpServletResponse response, String[] parts) {
        this.servlet = servlet;
        this.request = request;
        this.response = response;
        this.parts = parts;
    }
}

GiftService.java

package com.fyhao.test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GiftService extends Service {

    public void main() {
        System.out.println("default main methods: ");
    }
    public void send() {
        System.out.println("sending");
    }
}

 

All right, this is the coding done by me during first learning of using java reflection API, which is the great API to directly find the class by the full name, and dynamically initializes and calling its methods. However, I think it would have other better ways of doing this. Please tell me if you know. Thanks.