Tuesday, January 30, 2007

java http proxy support

Heres a good post on getting java to use the host machines proxy settings

http://weblogs.java.net/blog/kohsuke/archive/2005/08/we_deserve_a_be.html

Upshot is to include the following in you java prog before making http requests

try {
System.setProperty("java.net.useSystemProxies","true");
} catch (SecurityException e) {
; // failing to set this property isn't fatal
}
Sweet!

Wednesday, December 20, 2006

Unlocking mobile phones

I recently got a second mobile phone, and wanted to swap sims between the two.

The phones I wanted to unlock were a Nokia 6021, and a Nokia 6070

My experience was
  • Get your IMEI code off your phone (type *#06# into the phone).
  • Figure out if you are DCT3 or DCT 4 and your phone type from this site http://www.mobyproject.com/link/dct3&4list.txt
  • Goto this site http://unlock.nokiafree.org. Enter the details and get the code
  • Take out your sim and start phone without it.
  • Type in the bottom (7th) code from the list following the instructions from http://unlock.nokiafree.org. (Press * multiple times to get letters *, P, W +)

Voila.

Of course there are risks.
This article gives a good synopsis of what to do and some exceptions that can occur
http://www.oreilly.com/pub/wlg/3935

Good luck

Monday, October 16, 2006

Misc unix commands

chmod only dirs, using find
find /dir/to/chmod/all/dirs -type d -exec chmod a+x {} \;

Move all files after a certain date (Yesterday) , using find
find /dir/ -mtime -1 -exec mv {} ./temp \;

List only directories
ls -l | grep ^d

Find last created entity (file or directory)
ls -t ${CIDIR}| head -n 1

Find last created directory (note must use long ls results, therefore we need to parse 8th elment)
ls -tl | grep ^d | head -n 1 | awk '{print $8}'

grep multiple log files in different locations. (Join multiple lines into one line)


grep EXCEPTION `ls -t /var/log/bea/logs/MWOSBDomain/servers/MWOSB1?/customaudit/LogFile1?.log.* | head -n 3 |  tr '\n' ' '`

e.g. this will grep log files in differnt locations from yesterday (based on naming convention LogFile12.log = current log file. LogFile12.log. is rolled over log file. Assuming log files roll over every night).
Top 3 files are taken from ls command (in this case I know there are 3 log directories, so top 3 files are all yesterdays file in each directory)
List output is then 'translated', converting each line break into a space, so feed into grep command.

Dirname

Discovers the dir where the current running script is running;

Useful if writing bash scripts and you want to know where the current file is (for example if loading other companion scripts)

DIR="$( cd "$( dirname "$0" )" && pwd )"

e.g

#!/bin/bash

export DIRNAME=$(cd `dirname $0` && pwd)

source ${DIRNAME}/common.sh

#echo $JAVA_HOME/bin/java -cp $CLASSPATH ie.bge.middleware.envstatus.app.SetSystemStatus $@

$JAVA_HOME/bin/java -cp $CLASSPATH ie.bge.middleware.envstatus.app.SetSystemStatus $@

N.B. script must be executable. Therefore chmod +x


Parse log file with awk
awk normally splits lines based on whitespace characters. This can be forced however using the -F switch and passing a regex.
e.g. the following splits on semi-colon, and prints the 3rd and 6th fields.
awk -F ";" '{print $3 " " $6 }'
this example splits on commas, within quotes e.g. "value1", "value2", ..
awk -F "\"*,\"*" '{print $3}' file.csv

Identify unix version
uname -r
cat /etc/*-release
cat /etc/issue
rpm -qa --queryformat "%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n"|grep release|sort

Misc Tips
Whitepace gothcas when writing bash scripts.

Bash IF statment requires whitespace.
DIRNAME=mydir
if [ -d $DIRNAME ]; then
echo $DIRNAME exists
else
echo $DIRNAME does not exist
fi

1/ There must be NO whitespace in the set command (DIRNAME=mydir, ..e.g. the following won't work DIRNAME = mydir). Otherwise bash misinterprets the set operation as a command (called DIRNAME here).
2/ The whitespace between the IF statement and the [..] is required. e.g. (if [-d $DIRNAME]; then will cause an error)

Script to copy latest build folder to other location
#!/bin/bash
# Exit on Error
set -e
DIR=/usr/local/apache2/htdocs/Repository
CIDIR=/opt/continuous_integration/build_archive/
echo $#
if [ $# -ne 1 ]; then
echo Usage: PublishBuild.sh VER. Must supply version number.
exit 1
fi
VER=$1
if [ ! -d ${DIR}/$VER ]; then
mkdir ${DIR}/$VER
fi
if [ ! -d ${DIR}/${VER}/osb ]; then
mkdir ${DIR}/$VER/osb
fi
CIB=`ls -t ${CIDIR}| head -n 1`
echo cp -R ${CIDIR}/${CIB}/* ${DIR}/${VER}/osb
cp -R ${CIDIR}/${CIB}/* ${DIR}/${VER}/osb
echo Copied ${CIB} to ${VER}
exit 0

Friday, October 13, 2006

Drupal built in Global

Heres the small prog to produce this list

foreach($GLOBALS as $g=>$v){
if(is_array($v)){
echo("$g = Array {");
foreach($v as $a2=> $b2){
echo("$a2=$b2,");
}
echo("}");
}else
echo("$g = $v");
}

Heres the list
  • HTTP_POST_VARS = Array {}
  • _POST = Array {}
  • HTTP_GET_VARS = Array {q=node/11,}
  • _GET = Array {q=node/11,}
  • HTTP_COOKIE_VARS = Array {MANTIS_PROJECT_COOKIE=5,PHPSESSID=b9fb481c4b12115c83761754702db5ae,MANTIS_STRING_COOKIE=b36c8ddd894abf6d551b90aed8552328be6ab68c73aafdf3d611d932e25c67da,userwdth=null,userfontsz=null,userbg=null,phpMyAdmin=8d176d85421e8ec646ce148c4893cbec,}
  • _COOKIE = Array {MANTIS_PROJECT_COOKIE=5,PHPSESSID=b9fb481c4b12115c83761754702db5ae,MANTIS_STRING_COOKIE=b36c8ddd894abf6d551b90aed8552328be6ab68c73aafdf3d611d932e25c67da,userwdth=null,userfontsz=null,userbg=null,phpMyAdmin=8d176d85421e8ec646ce148c4893cbec,}
  • HTTP_SERVER_VARS = Array {HTTP_HOST=localhost,HTTP_USER_AGENT=Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7,HTTP_ACCEPT=text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5,HTTP_ACCEPT_LANGUAGE=en-us,en;q=0.5,HTTP_ACCEPT_ENCODING=gzip,deflate,HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7,HTTP_KEEP_ALIVE=300,HTTP_CONNECTION=keep-alive,HTTP_REFERER=http://localhost/psoup/lia/?q=node/13,HTTP_COOKIE=MANTIS_PROJECT_COOKIE=5; PHPSESSID=b9fb481c4b12115c83761754702db5ae; MANTIS_STRING_COOKIE=b36c8ddd894abf6d551b90aed8552328be6ab68c73aafdf3d611d932e25c67da; userwdth=null; userfontsz=null; userbg=null; phpMyAdmin=8d176d85421e8ec646ce148c4893cbec,HTTP_CACHE_CONTROL=max-age=0,PATH=c:\\apps\\ruby\\ruby-184-17\\bin;c:\\apps;C:\\oracle\\product\\10.2.0\\db_2\\bin;c:\\beaSP2\\jdk141_05\\bin;c:\\apps\\ruby\\bin;c:\\apps\\sybase\\OCS-12_5\\lib3p;c:\\apps\\sybase\\OCS-12_5\\dll;c:\\apps\\sybase\\OCS-12_5\\bin;c:\\apps\\sybase\\SQLRemote\\dll;c:\\apps\\sybase\\RPL-12_5\\bin;c:\\apps\\sybase\\JS-12_5\\bin;c:\\apps\\sybase\\ASE-12_5\\dll;c:\\apps\\sybase\\ASE-12_5\\bin;C:\\Program Files\\ATI Technologies\\ATI Control Panel;c:\\apps\\imagemagick-6.1.5-q16;c:\\apps\\gpg\\bin;c:\\apps\\sybase\\OLEDB;c:\\apps\\cvs;c:\\apps\\sybase\\ODBC;c:\\apps\\sybase\\ASEP_Win32;c:\\apps\\sybase\\OCS-12_5\\dll;c:\\apps\\sybase\\OCS-12_5\\lib3p;c:\\apps\\sybase\\OCS-12_5\\bin;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\Program Files\\ATI Technologies\\ATI Control Panel;c:\\apps\\apache-ant-1.6.2\\bin;C:\\Program Files\\Subversion\\bin;c:\\apps\\php-4.3.9-Win32;C:\\Program Files\\Common Files\\GTK\\2.0\\bin;c:\\Program Files\\MySQL\\MySQL Server 4.1\\bin;C:\\Program Files\\cvsnt;C:\\apps\\php-4.3.9-Win32;C:\\Program Files\\QuickTime\\QTSystem\\,SystemRoot=C:\\WINDOWS,COMSPEC=C:\\WINDOWS\\system32\\cmd.exe,PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.RB;.RBW,WINDIR=C:\\WINDOWS,SERVER_SIGNATURE=
  • Apache/2.0.58 (Win32) PHP/4.3.9 Server at localhost Port 80
  • ,SERVER_SOFTWARE=Apache/2.0.58 (Win32) PHP/4.3.9,SERVER_NAME=localhost,SERVER_ADDR=127.0.0.1,SERVER_PORT=80,REMOTE_ADDR=127.0.0.1,DOCUMENT_ROOT=C:/Program Files/Apache Software Foundation/Apache2/htdocs,SERVER_ADMIN=admin@ad.aol.aoltw.net,SCRIPT_FILENAME=C:/dev/psoup/lia/index.php,REMOTE_PORT=2251,GATEWAY_INTERFACE=CGI/1.1,SERVER_PROTOCOL=HTTP/1.1,REQUEST_METHOD=GET,QUERY_STRING=q=node/11,REQUEST_URI=/psoup/lia/?q=node/11,SCRIPT_NAME=/psoup/lia/index.php,PHP_SELF=/psoup/lia/index.php,PATH_TRANSLATED=C:/dev/psoup/lia/index.php,}
  • _SERVER = Array {HTTP_HOST=localhost,HTTP_USER_AGENT=Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.7) Gecko/20060909 Firefox/1.5.0.7,HTTP_ACCEPT=text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5,HTTP_ACCEPT_LANGUAGE=en-us,en;q=0.5,HTTP_ACCEPT_ENCODING=gzip,deflate,HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7,HTTP_KEEP_ALIVE=300,HTTP_CONNECTION=keep-alive,HTTP_REFERER=http://localhost/psoup/lia/?q=node/13,HTTP_COOKIE=MANTIS_PROJECT_COOKIE=5; PHPSESSID=b9fb481c4b12115c83761754702db5ae; MANTIS_STRING_COOKIE=b36c8ddd894abf6d551b90aed8552328be6ab68c73aafdf3d611d932e25c67da; userwdth=null; userfontsz=null; userbg=null; phpMyAdmin=8d176d85421e8ec646ce148c4893cbec,HTTP_CACHE_CONTROL=max-age=0,PATH=c:\\apps\\ruby\\ruby-184-17\\bin;c:\\apps;C:\\oracle\\product\\10.2.0\\db_2\\bin;c:\\beaSP2\\jdk141_05\\bin;c:\\apps\\ruby\\bin;c:\\apps\\sybase\\OCS-12_5\\lib3p;c:\\apps\\sybase\\OCS-12_5\\dll;c:\\apps\\sybase\\OCS-12_5\\bin;c:\\apps\\sybase\\SQLRemote\\dll;c:\\apps\\sybase\\RPL-12_5\\bin;c:\\apps\\sybase\\JS-12_5\\bin;c:\\apps\\sybase\\ASE-12_5\\dll;c:\\apps\\sybase\\ASE-12_5\\bin;C:\\Program Files\\ATI Technologies\\ATI Control Panel;c:\\apps\\imagemagick-6.1.5-q16;c:\\apps\\gpg\\bin;c:\\apps\\sybase\\OLEDB;c:\\apps\\cvs;c:\\apps\\sybase\\ODBC;c:\\apps\\sybase\\ASEP_Win32;c:\\apps\\sybase\\OCS-12_5\\dll;c:\\apps\\sybase\\OCS-12_5\\lib3p;c:\\apps\\sybase\\OCS-12_5\\bin;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\Program Files\\ATI Technologies\\ATI Control Panel;c:\\apps\\apache-ant-1.6.2\\bin;C:\\Program Files\\Subversion\\bin;c:\\apps\\php-4.3.9-Win32;C:\\Program Files\\Common Files\\GTK\\2.0\\bin;c:\\Program Files\\MySQL\\MySQL Server 4.1\\bin;C:\\Program Files\\cvsnt;C:\\apps\\php-4.3.9-Win32;C:\\Program Files\\QuickTime\\QTSystem\\,SystemRoot=C:\\WINDOWS,COMSPEC=C:\\WINDOWS\\system32\\cmd.exe,PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.RB;.RBW,WINDIR=C:\\WINDOWS,SERVER_SIGNATURE=
  • Apache/2.0.58 (Win32) PHP/4.3.9 Server at localhost Port 80
  • ,SERVER_SOFTWARE=Apache/2.0.58 (Win32) PHP/4.3.9,SERVER_NAME=localhost,SERVER_ADDR=127.0.0.1,SERVER_PORT=80,REMOTE_ADDR=127.0.0.1,DOCUMENT_ROOT=C:/Program Files/Apache Software Foundation/Apache2/htdocs,SERVER_ADMIN=admin@ad.aol.aoltw.net,SCRIPT_FILENAME=C:/dev/psoup/lia/index.php,REMOTE_PORT=2251,GATEWAY_INTERFACE=CGI/1.1,SERVER_PROTOCOL=HTTP/1.1,REQUEST_METHOD=GET,QUERY_STRING=q=node/11,REQUEST_URI=/psoup/lia/?q=node/11,SCRIPT_NAME=/psoup/lia/index.php,PHP_SELF=/psoup/lia/index.php,PATH_TRANSLATED=C:/dev/psoup/lia/index.php,}
  • HTTP_ENV_VARS = Array {}
  • _ENV = Array {}
  • HTTP_POST_FILES = Array {}
  • _FILES = Array {}
  • _REQUEST = Array {q=node/11,MANTIS_PROJECT_COOKIE=5,PHPSESSID=b9fb481c4b12115c83761754702db5ae,MANTIS_STRING_COOKIE=b36c8ddd894abf6d551b90aed8552328be6ab68c73aafdf3d611d932e25c67da,userwdth=null,userfontsz=null,userbg=null,phpMyAdmin=8d176d85421e8ec646ce148c4893cbec,}
  • conf = Array {array_filter=1,comment_image=2,comment_page=0,comment_story=2,file_directory_temp=c:\windows\temp,filter_default_format=3,filter_html_1=1,image_help=,menu_primary_menu=2,menu_secondary_menu=2,minimum_image_size=0,minimum_page_size=0,minimum_story_size=0,nice_menus_menu_1=42,nice_menus_name_1=Nice Menu 1,nice_menus_number=1,nice_menus_type_1=down,node_options_forum=Array,node_options_image=Array,node_options_page=Array,node_options_story=Array,page_help=,story_help=,theme_default=bluemarine2,type=page,upload_image=1,upload_page=1,upload_story=1,}
  • db_url = mysql://root:@localhost/lia
  • db_prefix =
  • base_url = http://localhost/psoup/lia
  • base_path = /psoup/lia/
  • base_root = http://localhost
  • db_type = mysql
  • active_db = Resource id #6
  • HTTP_SESSION_VARS = Array {watchdog_overview_filter=all,node_overview_filter=Array,}
  • _SESSION = Array {watchdog_overview_filter=all,node_overview_filter=Array,}
  • user = Object
  • queries =
  • timers = Array {page=Array,}
  • locale = en
  • multibyte = 0
  • _menu = Array {path index=Array,items=Array,callbacks=Array,visible=Array,}
  • theme = bluemarine2
  • theme_engine = phptemplate
  • custom_theme =
  • theme_key = bluemarine2
  • sidebar_indicator =

Sunday, September 24, 2006

Wednesday, August 30, 2006

Drupal idiosyncracies

  • The always present "Create Content" menu item (even when users aren't logged in)
http://drupal.org/node/47212
In particular, simply "Reset" the menu item should fix it

  • Read More tag in postings
    http://drupal.org/node/64051
Menus
Should write module to allow new terms to be added to menu system. At moment must create terms. Then create content using those terms. As part of this you can select create menu item.

Nice Menus.
By default css only supplies styles for 1 sublevel. Thus higher sublevels autoexpand. Add the following to stop this
(see http://drupal.org/node/65482)

// Add extra layer to stop 2nd level submenus from autoexpanding
//level 2
ul.nice-menu ul,
ul.nice-menu li:hover ul ul, ul.nice-menu li.over ul ul,
ul.nice-menu li:hover li:hover ul ul, ul.nice-menu li.over li.over ul ul {
display:none;
}

ul.nice-menu li:hover ul, ul.nice-menu li.over ul,
ul.nice-menu li:hover li:hover ul, ul.nice-menu li.over li.over ul,
ul.nice-menu li:hover li:hover li:hover ul, ul.nice-menu li.over li.over li.over ul {
display:block;
}

//Level 3
ul.nice-menu ul,
ul.nice-menu li:hover ul ul, ul.nice-menu li.over ul ul,
ul.nice-menu li:hover li:hover ul ul, ul.nice-menu li.over li.over ul ul,
ul.nice-menu li:hover li:hover li:hover ul ul, ul.nice-menu li.over li.over li.over ul ul {
display:none;
}

ul.nice-menu li:hover ul, ul.nice-menu li.over ul,
ul.nice-menu li:hover li:hover ul, ul.nice-menu li.over li.over ul,
ul.nice-menu li:hover li:hover li:hover ul, ul.nice-menu li.over li.over li.over ul,
ul.nice-menu li:hover li:hover li:hover li:hover ul, ul.nice-menu li.over li.over li.over li.over ul {
display:block;

Wednesday, August 16, 2006

Java Spring and Locales

Related to my previous post. We were updating a web app and localizing it for some new countries.

The jsps used some Spring tag libs.

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" />


Spring comes with an inbuilt LocaleResolver. By default it uses the AcceptHeaderLocaleResolver which detects the clients Locale from the Http headers (which are sent with the bowsers request).

In our case we didn't want the client locale to get picket up. We wanted to set it based on the servername. (To do these we added some virtual hosts to our tomcat instance).

Then to update the Spring Locale we had to use the SessionLocaleResolver . This has to be instantiated via the Spring xml file (otherwise it will default to AceptHeaderLocaleResolver).



We then simply set the Locale froma filter.

String servername = httpRequest.getServerName();
Locale locale = null;
if(servername.indexOf(".co.uk")>0){
_log.info("Setting UK locale");
locale = Locale.UK;
}else if(servername.indexOf(".fr")>0){
_log.info("Setting FR locale");
locale = Locale.FRANCE;
}else if(servername.indexOf(".de")>0){
_log.info("Setting DE locale");
locale = Locale.GERMANY;
}else{
_log.info("Cannot ascertain originating server. Defaulting to UK locale");
locale = Locale.UK;
}


HttpServletRequest

I keep forgetting these value. So I'm writing it down here to remember

Within a servlet, or Filter (or jsp) you can access the following information about the request.

httpRequest.getContextPath(); // =/webapp
httpRequest.getRequestURI(); // =/webapp/webhome
httpRequest.getServletPath(); // = /webhome
httpRequest.getRequestURL(); // = http://mybox.my:11600/webapp/webhome?q=query&r=prevPage
httpRequest.getRequestURI(); // = http://mybox.my:11600/webapp/webhome

httpRequest.getServerName(); // = mybox.my (1)
httpRequest.getRemoteHost(); // = 10.149.93.49 (2)
httpRequest.getRemoteAddr(); // = 10.149.93.49
httpRequest.getRemoteUser(); // = null ... (3)

N.B.
If you perform a RequestDispatcher.forward() then all the above methods will reflect the new forwarded values. Personally I didn't think the javadocs made this clear.

As of Servlet spec 2.4 however you can still access the original client request data using the following attributes. (see http://www.javaworld.com/javaworld/jw-03-2003/jw-0328-servlet_p.html)

  • javax.servlet.forward.request_uri
  • javax.servlet.forward.context_path
  • javax.servlet.forward.servlet_path
  • javax.servlet.forward.path_info
  • javax.servlet.forward.query_string

Inside a forwarded servlet you'll see getRequestURI() return the path to the target servlet as always, but now if you want the original path, you can call request.getAttribute("javax.servlet.forward.request_uri"). One special caveat: if forward() happens through a getNamedDispatcher() call, these attributes aren't set because, in that case, the original path elements aren't changed.

Note from servlet spec 2.2 there already exists

  • javax.servlet.include.request_uri
  • javax.servlet.include.context_path
  • javax.servlet.include.servlet_path
  • javax.servlet.include.path_info
  • javax.servlet.include.query_string
However, these work just the opposite of the forward() attributes. In an include(), the path elements don't change, so the include attributes act as the backdoor to access the target servlet's path elements. Compare this with a forward() where the path elements change so the forward attributes represent the backdoor to the original path elements.

Should filters invoke for forwarded requests? Included requests? What about for URIs invoked via the mechanism? Before Servlet 2.4, these questions were left as open issues. Now Servlet 2.4 makes it a developer's choice. There's a new element in the deployment descriptor with possible values REQUEST, FORWARD, INCLUDE, and ERROR. You can add any number of entries to a like this:


<filter-mapping>
<filter-name>Logging Filter</filter-name>
<url-pattern>/products/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>

This indicates the filter should be applied to requests directly from the client as well as forward requests. Adding the INCLUDE and ERROR values also indicates that the filter should additionally be applied for include requests and requests. Mix and match for what you want. If you don't specify any elements, the default is REQUEST.

The last RequestDispatcher change is to allow, for the first time, relative paths in request.getRequestDispatcher() calls. The path will be interpreted relative to the current request's path. It's a minor change, but comes in handy when dispatching to a sibling servlet.




Notes:
No all these method are available on the basic ServletRequest. Normally I just cast the basic ServletRequest into a HttpServletRequest, since I am normally only writting web apps.

1/ This is the server name from the Request. You can set up your web server to be multi hosted using virtual hosts. (Heres an example for tomcat). Then you can use this variable to differentiate on which host they came in on. We are using this for setting the locale on one project. (In general it is better to choose the locale based on the request,but we have specific reasons for doing it this way).

2/ This is the clients IP address. Can be used for logging.

3/I'm guess this will show a value if the page is protected by HttpAuthentication.

For Php equivilents check out this page

http://www.php.net/reserved.variables

Thursday, July 06, 2006

Updating a Windows Service..

I needed to update mysql to use the old authentication mechanism...
http://dev.mysql.com/doc/refman/5.0/en/old-client.html

This involved adding some command line parameters to mysqld when it starts to use the old authentication mechanism. Unfortunately the Windows Services tool doesn't allow this.

Thanks to http://illiniguy.wordpress.com/2006/03/17/updating-a-windows-service/

regedit to

\\HKEY_LOCAL_MACHINE\SYSTEMCurrentControlSet\Services\___YOUR_SERVICE_NAME___

and edit away...

Saturday, April 08, 2006

Browser interoperability

I've had a lot of headaches with this. In general my approach is to use and libraries/ open source functions etc that are out there since they will almost certainly work better in a cross browser environemnt than what I throw together

This doesn't always work out however and I find myself writting css pages, javascript etc...

Anyway the problem. Looks like a bug in IE. It appears that the document.getElementById() function does not work... However on further examination it turns out that the ID attribute must be the first (or before most atribute) attribute in an html element.

For example

<img class="myimg" name="myimg" src="myimg.jpg" id="12"/>

If you then try to access this in javascript it doesn't work

docuemnt.getElementById("12") returns a null.

However if you re-jig the element so id is the first attribute then it works fine.. Bizarre.

<img id="12" class="myimg" name="myimg" src="myimg.jpg" />

[tested on IE 6.02]

Thursday, October 13, 2005

DB access in word VBA

I was working on little program to extract data from a word document, and insert it into a database. Pretty straightforward VBA for a VBA developper... Except I'm not a VBA developper.

Actually it proved quite simple up to the point where I need to make an ODBC connection to the database. Then all hell broke loose.

In time honoured VBA programming practise, when you hit upon a problem, record a macro, and do the step you want to, then view and edit the code.. .

This I did and discovered the nice looking InsertDatabase [Link to msdn]
. Worked a treat.. Read data from the odbc, and displayed in it the doc. Wonderful!

Except for the teeny weeny problem thatI wanted to display the data in a userForm. Reading the docs in that link above, the InsertDatabase method can only be called on a Range object. Try as I might I couldn't find a Range object in the UserForm.

Long story short.. I found the ADO object which solved my problems.. Gives you a full API for talking to DB's. You will need to install the reference libraries Microsoft AxtiveX Data Object library (you will need your office install media for this), and include them in your references first.

I did briefly run into the infamous Error 80004005 "Data Source Name Not Found"

But with a bit of tinkering around I got this to work.

First step, create a systemDSN (userDSN should also work) of the name for the ODBC connection you want (vba in this instance)

Then the following code calls a table there and inserts the data into my UserForm (called UserInput)


Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim sql As String

Const ConnectString = "DATABASE=vba;DESCRIPTION=Vba Test;DSN=vba;OPTION=0;PORT=0;SERVER=localhost"


cn.ConnectionString = ConnectString
'cn.CursorLocation = adUseClient
cn.Open

' Find out if the attempt to connect worked.
If cn.State = adStateOpen Then
Set rs = cn.Execute("Select * From test")
If rs.EOF Then
UserInput.namesList.AddItem "No Entries returned from Database."
Else
While Not rs.EOF
UserInput.namesList.AddItem rs("data") & ":" & rs("date")
rs.MoveNext
Wend
End If
'MsgBox (rs("data") & ":" & rs("date"))
rs.Close
Else
MsgBox "Sorry there was a problem connecting to the database."
End If

cn.Close


Wonderful..

Any questions, drop me a comment,

Thursday, August 25, 2005

more xml schema validation

I thought I had Xml validation sorted after the following entries (java and xml, and schema validation).

So today when I went to validate some xml's against a Xsd I was a bit surprised when it didn't work

What was more surprising was that it was working, and when I changed something small, it stopped.

As part of a Unit Test I was validating an xml file against a schema, and it was working fine. However I was loading the Xsd via a webserver into the parser. This wouldn't do since other developpers would want to run the unit tests and would not want the hassle of starting up a webserver and dropping the xsd file in place initally before running the tests.

So I changed the URL to load the Xsd via the file:// protocal. See below

xsd="file://"+path+"wishlist.xsd";


Running that however gave the following exception



org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'wishList'.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
....


But I knew the XSD was correct because it had been working before when I retrieved it via http:// on my webserver....

Do you see the problem? Well I didn't initially. After some poking around I found the solution.

xsd="file:///"+path+"wishlist.xsd";

See the difference. Subtle isn't it. Basically xerces insists that file needs 3 forward slashes in it url definition (file:///wishlist.xsd). That was the problem. Surely a better error message could have been generated there. (Maybe XSD not found or something)

Anyway I then started gettign the following error



org.xml.sax.SAXParseException: Invalid byte 1 of 1-byte UTF-8 sequence.
at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
...


Short answer to this problem was my file character encoding. I had saved my xsd using a free editor (crimson). By default it saves files in Ascii encoding. However my Xsd expected to be in UTF-8. Changing the character encoding and re-saving solved the problem.

Amazing how a simple little task can tie you down for hours..

Monday, August 15, 2005

Regular expressions tutorial

I can never remember Regular Expressions (regex).

So heres a good tutorial on the subject I found. http://www.silverstones.com/thebat/Regex.html

once you've read that, then pick one of the following results as a quick reference card.
http://www.google.ie/search?q=regex+quick+reference


---Added Jul 13 ----
Just found this great site for validating your regex's online.. Brilliant.

http://www.koralsoft.com/regextester/

Regexs
Strip html from strings
//javascript Makes <b>Hello</b> World => Hello World
tag = tag.replace(/(<([^>]+)>)/ig,"");

Split CamelCase word (Note performance might not be great for many iterations)
s.replaceAll("([A-Z])", ' $1'); // taken from here

Slight modification (don't split if more than one capital after another)
s.replaceAll("([A-Z]{1,})", ' $1');

Thursday, August 04, 2005

Remote Debugging Java with eclipse

This is a powerful feature which allows you to debug a remote server from an IDE, and step through the code to see what is happening. For example a remote web server like tomcat, or an app server like WebLogic or Websphere can be debugged.

Firstly the basis of this is a feature in the Java JVM. This means that any java executable can be debugged this way.

To start debugging on a java instance you need to include the following when you run the JVM

java -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=n,suspend=n,address=8000 -Djava.compiler=NONE

For running Weblogic Server in debug mode subtle difference
java -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 -Djava.compiler=NONE

This sets the debugger listening on a socket on port 8000.

Debugging can also be set up using shared memory, but eclipse can't use the shared memory feature so I won't deal with it here (BTW, Netbeans can use the shared memory mechanism for debugging so this can be pursued if you are using Netbeans)

Simply then within eclipse you need to select Run/Debug.... From there select Remote Debugging, select the project where you have the source code for the project, and specify the server name where the service is running and the port (8000 in our case), and you're laughing.

Easy peasy.

If you are running tomcat (well version 5.5 anyway), the startup scripts already have the debugging information included, see this link
http://jakarta.apache.org/tomcat/faq/development.html

What I've done then is simply changed the startup.bat file.

At the start (line 9) I added the following, which specifies socket based debugging (shared memory is the default), and sets the listen port to 8000
rem ++++++++++++++++++++++++++++++++++++++
rem Enable Remote Debugging
set JPDA_ADDRESS=8000
set JPDA_TRANSPORT=dt_socket
rem ++++++++++++++++++++++++++++++++++++++

Careful of any extra spaces of tabs on these line. An extra space caused me some problems for a while.

Then change the 2nd last line where it calls the catalina.bat file from
call "%EXECUTABLE%" %CMD_LINE_ARGS% start

to

call "%EXECUTABLE%" start %CMD_LINE_ARGS%

Now when you call the startup.bat you can simply call startup jpda to start the debugger listening on port 8000. Then you can attach your IDE to port 8000 and debug the server.

Alternatively you can simply call the catalina.bat file directly using the command

catalina.bat jpda start

But you must declare JPDA_ADDRESS=8000 and JPDA_TRANSPORT=dt_socket as environment variable (or put them in the catalina.bat)

Weblogic

Remote debugging with eclipse

To enable remote debugging for weblogic the following must be done

In the setDomainEnv.cmd or setDomainEnv.sh you must assign the variable debugFlag to true. (Note no need for quotes etc as I discovered after some time debugging)

setDomnainEnv.cmd

set debugFlag=true

setDomainEnv.sh

local debugFlag=true

Wednesday, July 13, 2005

Website notice

Just want to publicise www.billyeccles.com. This is a website I developed for, Billy Eccles (surprise surprise). Billy is a potter based in Dublin. He also happens to be my girlfriends father. So no pressure there... Anyway have a look and let me know what you think, and like in restaurants/ shops etc.

"If you don't like something on the site tell me.... If you like something, tell everyone" (and me as well).

Technical aside
You may notice that the site is a PHP site, and yet all my postings before now, have been Java related. That's correct. For this site I realised that if I was to develop anything worthwhile I needed to leverage as much free code as possible. So I'm using an open source CMS called Mambo. It saved me a lot of time.

Tuesday, July 12, 2005

Autostart Vnc

Took me a while to find this so I thought I'd write it down. Of course its easy when you know how.

Edit /etc/sysconfig/vncservers

Add the following

VNCSERVERS="1:username"

Where 1 is the display to start the vncserver on, and username is the name of the user you want to start vnc as (Not root). Simple as that. You should also run vncpasswd first and set the vnc password on the system.

Now a quick explanation

The /etc/sysconfig dir contains information on user services to be started up (unlike the /etc/rx.d dir that starts up system services). Information on these can be found in

RedHat docs


or on

/usr/share/doc/initscripts-/sysconfig.txt

Cross platform Jsp issues

I find this hard to believe, yet it seems to be true


Take a simple html tag with a jsp tag


<input name="text" value="<%=new String("Hello")%>"/%>


That works fine on tomcat. No problems...

On weblogic however, no go...

The problem is the nested quotes """

To get it to work, obviously a few solutions

<input name="text" value="<%=new String(\"Hello\")%>"/%>

or

<input name="text" value='<%=new String("Hello")%>'/%>

Both easy solutions once you know the problem. Of course it took me a while to find out that this problem. In my defence, I wasn't doing something so simple as the above example. I was having problems with a tiles definition.
After a bit of effort I now have some basic JSF pages working.

One error that stumped me for a good while was the following

javax.faces.el.PropertyNotFoundException:
Can't instantiate class ....

This came about from a backing bean I was tryign to configure from my face-config.xml


<managed-bean-name> Menubar </managed-bean-name>
<managed-bean-class> com.aol.beans.jsf.Menubar </managed-bean-class>
<managed-bean-scope> application </managed-bean-scope>
<managed-property>
<description>List of items to appear in the MenuBar and privilages, these get localised to menu.</description>
<property-name>itemsAndPrivilegeLevel</property-name>
<property-class>java.lang.String[]</property-class>
<list-entries>
<value>home,1</value>
<value>profile,1</value>
<value>performance,1</value>
<value>transaction,1</value>
<value>reference,1</value>
<value>sysAdmin,3</value>
<value>production,2</value>
<value>logout,1</value>
</list-entries>
</managed-property>
</managed-bean>


Basically I was trying to set the itemsAndPrivilegeLevel parameter in the bean.

The problem was I hadn't created a getItemsAndPrivilegeLevel method in the bean. I dodn't think I needed one (I don't), but apparently either JSF or the beans specification think different, so I have to have that method there.

The perils of globalisation

... from a programmers persepctive...

Call it globalisation or internationalisation, either way it not as straightforward as I'd like to believe.

As a java programmer it all seems easy. Use a ResourceBundle and store all your text in handy resource files. These can easily be translated as needs require. However once you've externalised all of your user displayed text to property files, thats when the fun really begins. Especially if you're dealing with a non Western script.


Funny how Japanese text looks like fractions, symbols and punctuation marks you may find yourself saying....
.....
Once you get past that stage though, then its onto the world of character encodings.

Character encoding. It's something most Western language users blissfully ignore. Its only when you try and export your freshly translated text to say Japan that things come tumbling down.

The best links I found on this are here and here.

Ah ha, maybe that 3/4 symbol isn't in fact the japanese for Hello.

In fact its garbled character encoding. Looks like its time to instruct your webserver to serve up different character sets.

I started out setting up Tomcat to send UTF-8. There are a few distinct steps involved.


1.
The JVM must be initiated using the correct charset. This sets the format of the files that java will use (includes, properties file, jsp pages etc.)

This is done with the following switch

-D=file.encoding=UTF-8

so for Tomcat, I added the following to the cataline.bat file

set CATALINA_OPTS=-D=file.encoding=UTF-8


2.
Its important to realise the standard encoding used by the OS that you are running. My version of windows is using a Western Latin-1 script. This is unable to display japanese characters. In order to get japanese characters displayed I had to install japanese character supprt.

This also means that files (for example properties files) may be stored in a different character set than you may be expecting.

In my case, I was using Crimson as an editor. Crimson saves all charcters as Ascii, thus cannot display japanese character, or even Western scripts such as é or ß characters. I had to find a unicode enabled editor. Unipad is a good one that I found.

Java properties files do not by default support unicode. They must be encoded.

Once your files are stored in a unicode mapping, you have to run it through the nativeToAscii program which escapes out any strange foreign characters and puts in the exact unicode code point instead. (Theres an ant task which can be used for this).

<native2ascii encoding="UTF-8" src="$%7Bsrc.dir%7D" dest="${build.dir}" includes="**/*.properties">.

Once your basic java environment is set, you need to be able to set the character encoding for the page. This can be set with a page directive

<%@ page contentType="text/html;charset=UTF-8" />

or in xml syntax

<jsp:directive.page contenttype="text/html;charset=UTF-8">

4.
Finally (I think) set the encoding for the HttpResponse (So you can understand any text that gets sent back)

Using jstl

<fmt:requestencoding value="UTF-8">



Now in the above example I have used UTF-8 as the encoding, this encoding maps to a variable number of bytes (from 1 to 6). Western mappings e.g. ascii will normally be covered by 1 byte, but those foreign type scripts may take up to 6 bytes to be encoded.

If you are mainly directing pages to Japanese clients then UTF-8 will be quite wasteful. A fairer encoding might be UTF-16 (doesn't seem to be supported by IE, or Mozilla browsers), or even (I going out on a bit of a limb here) Shift-JIS.



Its all very nice, if it all works well , but if it doesn't..... Can be bit nasty.

What I'm looking at now is changing the encoding deplending on the locale. The serlvet 2.4 spec has a nice mapping

<local-encoding-mapping-list>
<locale>jp</locale>
<encoding>Shift_JIS</encoding>
</local-encoding-mapping-list>

which hopefully will sort things out.

If theres no more entires on this subject then it all worked out swimmingly

Location independent loading of properties

Heres another little douzie that been slapping me across the face all day.

When writing and deploying code you don't want to have absolute paths listed for config files, resources etc, as these will invariably lead to problems when moving the application to another server.

Normally with java this entails creating a deployment directory, and including within it all classes and resources that you may need. You then load all files and properties using the deployment directory as the root.

The question then arises how do you access these properties.

For example with properties files the initial way one thinks of to load properties is as follows


FileInputStream inputStream = new FileInputStream("");
Properties prop = new Properties();
prop.load(inputStream);


The problem with this is that the is an absolute value, which knows nothing of the deployment directory that you may be running from.

The solution is to use one of the following


Class.getResourceAsStream() or
ClassLoader.getResourceAsStream()


The funny thing is that for me sometimes the first method works (e.g. when run from within Eclipse), and the 2nd one fails. Sometimes (from with tomcat) the first one fails and the 2nd one works.

In fact initially I had posted to use the 2nd method after spending a few hours tracking down why my program worked in Eclipse but failed in tomcat. It was only a day later that I discovered that the 2nd method (which works in tomcat) doesn't work in eclipse.

So now I have this slightly ugly construct to try and get around the problems

/**
* The name of the properties files. N.B. the "/" at the start means it is an absolute
* package, not a relative path from this package.
* Default propertuies location /resources/rsi.properties in the classpath may be
* overridden by setting the System property rsiserver.property.file,
* as in the test ant target, or with java -Drsiserver.property.file=myNewPropertiesFile
*/
static String propLoc="/resources/rsi.properties";
static{
// First check system property to see if specific properties file is set
propLoc = System.getProperty("rsiserver.property.file", propLoc);
prop=new Properties();
InputStream is = Utils.class.getResourceAsStream(propLoc);
if(is==null){
log.debug("Failed to load Resource ["+propLoc+"] from Utils.class.getResourcesAsStream() trying classloader.");
ClassLoader cl=Utils.class.getClassLoader();
if(log.isDebugEnabled())
log.debug("ClassLoader = "+cl);
is=cl.getResourceAsStream(propLoc);
}

try {
//Throws IOException
prop.load(is);
} catch (Exception e) {
log.fatal("Exception loading Properties file.",e);
}
}




I'm at a loss to explain it, but I suspect (hope) that its some configuration problem.