Friday, October 17, 2008

Redirect from a JSP page (to another server)

Keywords:
best practice tips JSP redirect XML

Problem:
<jsp:forward> is not for redirecting to an external server (and the address you forward to will have access the request attributes and parameters, which may be desirable, see discussion here: when to use response redirect and jsp forward.

Is using response.sendRedirect(...) ok/best-practice?
Solution:
The short answer, is it's fine. In summary, there are four approaches I can think of:

Approach #1: Scriptlet to sendRedirect

<%
    response.sendRedirect("http://www.example.com");
%>

This has worked since the introduction of JSPs (see: Implementing a Redirect in a JSP Page) ... sometimes you need the servlet API in your JSP page either because there's other content (eg HTML) that makes it reasonable not to be a pure servlet. Other times it's just convenient to have a text file compiled on the fly.

Though there are many that would disagree (Sciptlet snobs? see How to redirect a page in JSP - I don't see why you'd get wound up about scriptlets. Why would you write a servlet when one line of code in a text file gives you the same result?).

Approach #2: Use Apache JSTL and the c:redirect tag

<c:redirect url="http://www.example.com"/>

or scriptlets again:
<c:redirect url="<%=scriptlet logic%>"/>

Sure, it's 'pure' XML but you'll need the taglib definition in the JSP file and include the JSTL jars in your web application - as discussed in the notes for a previous post.

Approach #3: Refresh meta tag


You could get the JSP to produce a HTML page that contains the Refresh meta tag.
<html>
<head>
  <meta http-equiv="Refresh" content="0; url=http://www.example.com/">
</head>
<body></body>
</html>

Where 0 is the delay in seconds. If more than zero, you'd probably want to put some text on the page to explain what's happening.

Approach #4: Javascript


As above, you could get the JSP to produce a HTML page that contains javascript to perform the redirect.
<html>
<head>
<script type="text/javascript">
window.location = "http://www.example.com/";
</script>
</head>
<body></body>
</html>

You could use setTimeout to get the redirect to happen after a period of milliseconds.


Notes:
Out of curiosity I checked TCP monitor for what the browser is actually receiving when you use Approach #1 or #2 (sendRedirect or c:redirect)
HTTP/1.1 302 Moved Temporarily
Location: http://www.example.com

So it saves you from 2 lines of servlet (or scriptlet) code:
response.setStatus(302);
response.setHeader("Location", "http://www.example.com");

So the difference to Approaches #3 & #4 isn't great or much more inefficient really, in all cases it's up to the browser to go to the specified address.

Friday, October 10, 2008

Comments in JSON

Keywords:
comments JSON javascript

Problem:
Can you have comments in JSON?

Solution:
A discussion leading to the answer is on the Bytes IT forum.

Basically, though it's not defined in the JSON Grammar - on json.org - you can use slash-star /* ... */ comments to get most(?) javascript engines to ignore the comment text.

For example:
<script type="text/javascript">
    var nested_arrays = {
        cities: [
            ["Sydney", "Melbourne", "Canberra"]  /* Australia */
          , ["London", "Birmingham"]             /* UK */
          , ["Los Angeles", "New York"]          /* US */
        ]
    };
</script>

Friday, August 15, 2008

How do you remove a windows service?

Keywords:
manually remove windows service registry sc

Problem:
OK, I've uninstalled some software but it's left a service definition. It can't do much harm as most (but not all) of the resources it needs have been removed ... but I can't ignore it - how do you get rid of it?

Note to self: before uninstalling software with services it may help to stop them all and possibly disable them all too? I think this is why this particular thing could not be removed.

Note to developers: stop and remove services as part of uninstall programs.

Solution:
Some solutions talk about using regedit and modifying:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services


A better approach is to use sc ".. a command line program used for communicating with the Service Control Manager and services".

It should be as simple as:
sc delete [service name]


But the tricky thing is getting the name of the service right. What you see in the Service window is the display name not the service name. Use:
sc query state= all


To get a listing like
...
SERVICE_NAME: ExampleService
DISPLAY_NAME: Example Service That I Want To Delete
        TYPE               : 10  WIN32_OWN_PROCESS
        STATE              : 1  STOPPED
                                (NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN))
        WIN32_EXIT_CODE    : 1077  (0x435)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

...

SERVICE_NAME: helpsvc
DISPLAY_NAME: Help and Support
        TYPE               : 20  WIN32_SHARE_PROCESS
        STATE              : 4  RUNNING
                                (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN))
        WIN32_EXIT_CODE    : 0  (0x0)
        SERVICE_EXIT_CODE  : 0  (0x0)
        CHECKPOINT         : 0x0
        WAIT_HINT          : 0x0

...


So the above example listing:
sc delete ExampleService


Notes:
Just type sc at the command prompt for usage and more example commands (hit y to get help for the sc query commands).

Wednesday, June 18, 2008

HTTP Status 405 - HTTP method POST is not supported by this URL

Keywords:
HTTP Status 405 - HTTP method POST is not supported by this URL form login tomcat

Problem:
What does this error mean when reported by tomcat?
HTTP Status 405 - HTTP method POST is not supported by this URL
Status report

HTTP method POST is not supported by this URL

The specified HTTP method is not allowed for the requested resource (HTTP method POST is not supported by this URL).


Solution:
Simple answer: your servlet needs to implement doPost(HttpServletRequest, HttpServletResponse). Your servlet probably already implements doGet() so if you don't care about implementing different logic for POST, then just get it to call doGet():
public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
        // same logic
        this.doGet(request, response);
}


Notes:
It's a bit confusing if the servlet is a login form. GET should be returning the login form, POST from this form is handled by j_security_check. But if the client's initial request was a POST then the login servlet just needs to implement doPost() to keep the servlet container happy (calling doGet() as mentioned above is fine).

It seems that the servlet container (tomcat at least) makes sure the data from the original POST is not lost once the user gets past the j_security_check: Tomcat - User - [is] post data lost when redirecting

Tuesday, May 13, 2008

get/decode/unescape parameters from URL using Javascript

Keywords:
GET decode unescape request parameter param URL javascript

Problem:
You need to get at the (GET) parameters in the URL of the window with some client-slide javascript. There's no built in mechanism to access these by name in an unencoded way so it would seem you have to parse the window location ... this must have been done by some one before.

Solution:
Found two good blogs that discuss this:

  1. Get URL Parameters Using Javascript - uses regular expressions

  2. Get parameters from URL with JavaScript - uses substrings from the location.search (ie the query portion of the URL)


I found the second approach easier to read, but both miss unescaping the parameter value once obtained ... there's a built in function for that. So here's what I've used:
<script type="text/javascript">
/*
 * Retrieves the query parameter with the given parameter name or empty 
 * string if not defined
 * 
 * @param parameter name of the parameter to retrieve
 */
function queryParam(parameter) {
    var searchString = top.location.search;
    searchString = searchString.substring(1);// ommit the leading '?'

    var paramValue = '';
    var params = searchString.split('&');
    for (i=0; i<params.length;i++) {
        var paramPair = params[i];
        var eqlIndex = paramPair.indexOf('=');
        var paramName = paramPair.substring(0,eqlIndex);
        
        if (paramName == parameter) {
            paramValue = unescape(paramPair.substring(eqlIndex+1));
            return paramValue;
        }
    }
    return paramValue;
}
</script>


So from a URL http://www.example.com/formprocess?name=Fred%20Bloggs&date=01%2f01%2f2008
You can get the unescaped parameter values via:
var name = queryParam('name'); // 'Fred Bloggs'
var date = queryParam('date'); // '01/01/2008' 


Notes:
This doesn't handle multi-valued parameters ... the first (regex) blog post has some comments on how to handle this.

Wednesday, April 09, 2008

Call a stored procedure from a JSP with JSTL

Keywords:
Call execute SQL stored procedure JSP JSTL tag library

Problem:
The JSTL SQL tag library is a useful way of getting a rapid prototype going - it's all in a plain text file and will get compile on the fly. Examples I've seen show SELECT, UPDATE, INSERT and DELETE(s) ... can a stored procedure be run?

Solution:
The short answer is yes, the key thing is to know if the stored procedure is returning a result set or not as you have two tags available:

  • <sql:query> expects a ResultSet

  • <sql:update> does not expect a ResultSet - will throw an error if gets one. You do have access to an Integer result - eg rows updated.

For example, calling a stored procedure that returns a result set:
<sql:setDataSource var="myDataSource" dataSource="jdbc/myjndiref"/>
<sql:query var="examples" dataSource="${myDataSource}">
    exec ExampleProcLoadExample ?
    <sql:param value="${exampleId}"/>
</sql:query>
<c:choose>
    <c:when test="${fn:length(examples.rows) == 0}">
        <%-- no rows returned ! --%>
    </c:when>
    <c:otherwise>
        <c:set var="example" value="${examples.rows[0]}"/>
        <%-- got your object, can access columns with '.' notation --%>
    </c:otherwise>
</c:choose>


For example, calling a stored procedure that performs an 'update' (or insert/delete) returning number of rows updated:
<sql:setDataSource var="myDataSource" dataSource="jdbc/myjndiref"/>
<sql:update var="updateCount" dataSource="${myDataSource}">
    exec ExampleProcRemoveExample ?
    <sql:param value="${exampleId}"/>
</sql:update>
<c:choose>
    <c:when test="${updateCount le 0}">
        <%-- no rows updated ! --%>
    </c:when>
    <c:otherwise>
        <%-- some row(s) has been updated --%>
        <c:out value="${updateCount} row(s) have been updated"/>
    </c:otherwise>
</c:choose>


Notes:
When calling stored procedures you're getting into RDBMS vendor specific territory. Using the recommended JDBC drivers from the DB vendor for the DB version in use may make some of this work more smoothly.

Wednesday, February 27, 2008

Why can you not use a Wildcard as the first character in a Lucene search?

Keywords:
apache lucene wildcard search index "why not" leading first

Problem:
Reading the Lucene query parser syntax documentation for their latest release, there's a line that says "Note: You cannot use a * or ? symbol as the first character of a search.".

Why not? Sure it may be inefficient, but what if you're willing to wear that. Is it something that is technically not possible, is it something that's up to users of the library to work around or will it eventually be implemented in Lucene?

Solution:
Out of curiosity for why this is a limitation I found notes in the Lucene Wiki that indicate that you can do it and it is possible.

Seems the Query Syntax guide in the Lucene release simply needs updating(?).

queryParser.setAllowLeadingWildcard(true);


Notes:
Note the Wiki says this feature is available as of 2.1. But it seems there was a bug in this release. I've tested this with lucene 2.3.1 and it works fine.