Tuesday, October 13, 2009

java.lang.NoSuchMethodError: org.mockito.Mockito

In a Mockito test case, I have the line:

when(searchService.processSearch(isA(SearchQuery.class)))
   .thenReturn(new StringBuilder(searchResults));

This was giving me the following error when I ran the test case:

java.lang.NoSuchMethodError: org.mockito.Mockito.when(Ljava/lang/Object;)Lorg/mockito/stubbing/OngoingStubbing;
 at au.gov.australia.agosp.web.portlet.search.SearchControllerTest.setUp(SearchControllerTest.java:42)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:122)
 at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:86)
 at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
 at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
 at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
 at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
 at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
 at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
 at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
 at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
 at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46)
 at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

This test works on our continuous build server though. The issue was solved after I read Issue 106 reported on Mockito's google code site. Maven updated the mockito jar from 1.7 to 1.8.0, but left both jars in my local repository. Once I removed the 1.7 jar, the test case worked.

Friday, October 02, 2009

JUnit breakpoints skipping in Eclipse debug mode

Sometimes when running a JUnit test case in Eclipse, my breakpoints are all being skipped. Most annoying.

I am using Eclipse Galileo 3.5.0 with JDK 1.6.0_14.

Workaround is to use the following VM argument: -XX:+UseParallelGC. The fix is to upgrade to a later JDK, currently JDK 1.6.0_14. Both methods fixed this issue for me.

Here is the Eclipse bug report for this error and the Stack Overflow report on this issue.

Thursday, October 01, 2009

Url Rewrite Filter duplicates query string parameters

Sun's Webspace portal uses tuckey.org's Url Rewrite Filter, in which you place a bunch of URL rewrite rules in urlrewrite.xml. This is a great way to implement friendly URLs. For example, you can have an easy to type URL that the public will use such as http://www.example.com/search which the Url Rewrite Filter will route to the real portlet/servlet: http://www.example.com/real/path/to/search.

I was debugging a search service when I noticed that the request parameters values were being duplicated by the time it hit my controller. I.e. I was expecting single value parameters in my request:

querywinter sport
advancedSearchfalse

But found this instead (multi valued parameters):

querywinter sportwinter sport
advancedSearchfalsefalse

It turns out that the Url Rewrite Filter was was configured to propagate query parameters when it didn't need to. I.e. I had the following rule in place:

<rule>
   <from>^/search(.*)$</from>
   <to type="forward">/real/path/to/search$1</to>
</rule>

The $1 at the end of the TO element means: put the query parameters (the (.*) grouping in the FORM element) back on the end of the URL. This isn't needed because the Url Rewrite Filter is invoked after the query string has already been processed: the query string parameters have already been parsed and put in the Request object. Thus, the Url Rewrite Filter caused the parameters to be processed a second time.

The fix was simple, once I understood the reason. Just drop $1 from the end of the TO element.

<rule>
   <from>^/search(.*)$</from>
   <to type="forward">/real/path/to/search</to>
</rule>

Wednesday, August 26, 2009

Eclipse DTP vs Oracle PL/SQL - DESC is not SQL!

I have tripped up on this a few times. The Data Tools Project in Eclipse is excellent for SQL work, but against an Oracle database it runs SQL only, not PL/SQL.

A couple of times now I have tried to run "DESCRIBE SOME_TABLE" in an SQL file within Eclipse and gotten ORA-00900: invalid SQL statement (0 rows affected). This is because under Oracle, DESC[RIBE] is PL/SQL, not SQL.

Here is the SQL equivalent.

SELECT column_name "Name", nullable "Null?",
   concat(concat(concat(data_type,'('),data_length),')') "Type"
FROM user_tab_columns
WHERE table_name = 'SOME_TABLE';

Sunday, August 02, 2009

Open Total Commander from Cygwin command line

A script to open the file explorer Total Commander from the Cygwin command line. Allows user to:

  • Open paths in currently running instance.
  • Open paths in existing or new tabs.
  • Specify paths for left and/or right panels.

Purpose. To provide a flexible way to open paths in Total Commander from Cygwin. Now I can use this or Windows Explorer from the Cygwin command line.

Input. Paths to open. Options to open new tabs.

Output. Total Commander opened to given paths.

Dependencies. Total Commander must be installed! Paths must exist.

<>Examples. See usage section in script.

Here is the script.

#!/bin/bash
#===============================================================================
#
#          FILE:  totalCommander.sh
#
#         USAGE:  see usage
#
#   DESCRIPTION:  Open Total Commander to whatever path.
#
#       OPTIONS:  - see usage
#  REQUIREMENTS:  - Total Commander be installed http://www.ghisler.com/
#                 - Paths requested to be opened exist
#          BUGS:  ---
#         NOTES:  ---
#        AUTHOR:  Robert Mark Bram (RMB), robertmarkbram@gmail.com
#       COMPANY:  http://robertmarkbramprogrammer.blogspot.com/
#       VERSION:  1.0
#       CREATED:  07/31/09 16:54:46 AUSEST
#      REVISION:  ---
#===============================================================================

set -o nounset                              # Treat unset variables as an error


#-------------------------------------------------------------------------------
#  Variables for this script.
#-------------------------------------------------------------------------------
# Open new tabs? Blank for no, '/T' for yes.
newTab=
# Path to open on left.
tcpathLeft=
# Path to open on right.
tcpathRight=
# Total Commander command.
totalCommander=/apps/totalcmd/TOTALCMD.EXE
# Should we be verbose?
verbose=no


#-------------------------------------------------------------------------------
#  Common functions for this script.
#-------------------------------------------------------------------------------


#===  FUNCTION  ================================================================
#          NAME:  checkVars
#   DESCRIPTION:  Check initial state of vars in this script.
#    PARAMETERS:
#       RETURNS:
#===============================================================================
function checkVars() {
   if [ -z "$tcpathLeft" -a -z "$tcpathRight" ] ; then
      tcpathLeft=.
   elif [ ! -z "$tcpathLeft" -a ! -e "${tcpathLeft}" ] ; then
      usage "Left location [${tcpathLeft}] does not exist."
      exit 2;
   elif [ ! -z "$tcpathRight" -a ! -e "${tcpathRight}" ] ; then
      usage "Right location [${tcpathRight}] does not exist."
      exit 2;
   fi
   type $totalCommander &> /dev/null
   if [ ! -e "$totalCommander" ]; then
      echo "There is no spoon. Or total commander @ '$totalCommander'."
      exit 2;
   fi
}


#===  FUNCTION  ================================================================
#          NAME:  message
#   DESCRIPTION:  Output message if verbose is on
#    PARAMETERS:  message to be printed
#       RETURNS:  -
#===============================================================================
message ()
{
   if [ "$verbose" == "yes" ] ; then
      echo -e "${1}"
   fi
}    # ----------  end of function message  ----------


#===  FUNCTION  ================================================================
#          NAME:  processArgs
#   DESCRIPTION:  Check command line arguments.
#    PARAMETERS:  $@ from this script invocation
#       RETURNS:  Exit or take other action with error messages
#===============================================================================
processArgs ()
{
   # Process all the opening arguments.
   while [ "$#" -gt 0 ]
   do # until we have no more args to process.
      case "${1}" in
         "-h"     )  usage; exit 0;;
         "--help" )  usage; exit 0;;
         "-l"     )  tcpathLeft="${2}"; shift; shift;;
         "-r"     )  tcpathRight="${2}"; shift; shift;;
         "-t"     )  newTab="/T"; shift;;
         "-v"     )  verbose=yes; shift;;
         *        )  usage "Unknown option: $1" ; exit 2;;
      esac
   done
}    # ----------  end of function processArgs  ----------


#===  FUNCTION  ================================================================
#          NAME:  help
#   DESCRIPTION:  Output usage statement and exit.
#    PARAMETERS:  Error message.
#       RETURNS:
#===============================================================================
function usage() {
# Here document for help.. less or cat
errMessage=
if [ "$#" -gt 0 ] ; then
   errMessage=$1
else
   errMessage=HELP
fi
# Here document for help.. less or cat
cat << STOP_HELP
$errMessage
usage: $0 [-t] [-l leftPath] [-r rightPath]
Open Total Commander to paths, if specified, or current directory otherwise.
Always uses currently running instance. Opens new instance if none are running.
   -l    - Path to open in left tab.
            If neither -l or -r are given, default value is "-l .".
   -r    - Path to open in right tab.
            If neither -l or -r are given, default value is "-l .".
   -t    - Open paths in new tabs.
   -v    - verbose
Examples
1) Open current directory in left panel, current tab.
      $0
2) Open current directory in left panel, parent directory in right panel in new
   tabs.
      $0 -l . -r .. -t
STOP_HELP
}


#-------------------------------------------------------------------------------
#  Script Logic
#-------------------------------------------------------------------------------


processArgs "$@"
checkVars

if [ ! -z "$tcpathLeft" ] ; then
   tcpathLeft=/L=`cygpath -d -a "${tcpathLeft}"`
fi
if [ ! -z "$tcpathRight" ] ; then
   tcpathRight=/R=`cygpath -d -a "${tcpathRight}"`
fi

message "TC with left [$tcpathLeft], right [$tcpathRight] with new tab [$newTab]."

$totalCommander /O $newTab "${tcpathLeft}" "${tcpathRight}" &

# echo Done.

Thursday, July 16, 2009

Adding to the Subversion global ignore pattern for Tortoise and Cygwin

I hate to say this, but I spent two hours trying to find out how to add global ignores to my Subversion clients. There is plenty of documentation and forum posts, but strangely nothing that told me exactly what I needed to do! *sigh* Flame me if you wish.

In particular, it took me ages to realise that svn propedit svn:ignore . only sets up ignores for the current directory only - these properties are not recursive.

Tortoise - add to the global ignore list

  1. Right click on any folder.
  2. Select Tortoise SVN
  3. Select Settings
  4. Navigate to General
  5. Add "*.bak " to the global ignore pattern (note the space at the end).

Cygwin's SVN command line client - add to the global ignore list

  1. Edit your subversion config file. E.g. vim ~/.subversion/config
  2. Uncomment this line (and add the *.bak) global-ignores = *.bak *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo

Set up Cygwin Day 0

Day 0 instructions for setting up Cygwin on a fresh install.

Save this as a file, chmod 777 it and run it - or just c&p the code below into Cygwin. Important: make sure to take into account the two pre-requisites listed.

#!/bin/bash

# Pre-requisite 1. I have made a Windows HOME variable.
# right click on My Computer > select Properties
#   > select Advanced tab > click Environment Variables
#   > add new personal variable: HOME = "C:\rob\cygHome" for example

# Pre-requisite 2. Edit "mkpasswd options" to run one or the other.


# Make sure $USERNAME and $HOME are ok.
if [ ! -e "$HOME" ] ; then
    echo "Warning: HOME ($HOME) does not exist."
    exit 2
fi
if [ -z "$USERNAME" ] ; then
    echo "Warning: USERNAME ($USERNAME) is empty."
    exit 2
fi

# It is annoying always typing /cgydrive/
mount -s --change-cygdrive-prefix /

# Delete default home dir and replace as a link to HOME.
if [ -e /home/$USERNAME ] ; then
    rm -rf /home/$USERNAME
fi
ln -s $HOME /home/$USERNAME

# mkpasswd options
# Run this if in a corporate environment with domains.
# mkpasswd -l -c > /etc/passwd; mkgroup -l -d > /etc/group
# Otherwise..
# mkpasswd -l > /etc/passwd; mkgroup  -l > /etc/group

# Update passwd file with new home dir.
cat /etc/passwd | sed "s|:/home/$USERNAME:|:$HOME:|" > /etc/passwd

# Make links between Windows and Cygwin homes.
if [ -e $HOME/winHome ] ; then
    rm $HOME/winHome
fi
if [ -e /c/Documents\ and\ Settings/$USERNAME/cygHome ] ; then
    rm /c/Documents\ and\ Settings/$USERNAME/cygHome
fi
ln -s /c/Documents\ and\ Settings/$USERNAME $HOME/winHome
ln -s $HOME /c/Documents\ and\ Settings/$USERNAME/cygHome

Install PuttyCyg.

Thursday, July 02, 2009

Working with FatWire and Eclipse

The project I am currently working with uses FatWire 5.5. It has been very painful to work without Eclipse since the plugin doesn't work for FatWire 5.5. Here is a technique I introduced that allows me to use Eclipse in concert with Content Server Explorer. It is not as nice as the plugin would be, but for my money it is vastly superior to working with plain old text editors!

Eclipse Project for FatWire Code

FatWire 5.5 needs JDK 1.3, so I set up JDK1.3 as an installed JRE in my Eclipse workspace. Get JDK 1.3 from Sun's Archive Page.

  1. Within Eclipse, go to Windows > Preferences > Java > Installed JREs.
  2. Click "Add".
  3. Click "Standard VM" and then click Next.
  4. For "JRE Home", click Directory and navigate to the location of your JDK 1.3 install (for example C:\Java\jdk1.3.1_20).
  5. Click OK.
  6. For "JRE Name", enter something like "jdk1.3.1_20".
  7. Click Finish and then click OK.

Now I make a Java project for my FatWire based code that uses JDK 1.3. Unlike other web applications I have worked on, I don't need to make a Dynamic Web Project for the code I will deploy to FatWire Content Server; I just need a standard Java Project.

Eh?

Under the FatWire paradigm, all JSPs are created and maintained through FatWire tools - Content Server Advanced Interface and Content Server Explorer. I will deploy an EAR/WAR, but it will not contain any of my JSPs - which are CSElements. Instead, Content Server puts those files into the exploded EAR/WAR at runtime initialisation. This means that I never store JSPs in my own project (or static image or HTML files), so there is little advantage in using a Dynamic Web Project. I chose to use a standard Java Project for my project's FatWire code to keep the project structure simple. I use Ant build scripts to create the appropriate EAR/WAR file as needed.

Eclipse Project for Test Code

I keep unit tests in a separate project, which also means I can use a more recent JDK for unit tests. I set up another standard Java Project for the unit tests - and this project uses JDK 1.6. After I make the project (in the same workspace as the above project), I make the main project available to the unit test project. To do this, I select the unit test project and select Project > Properties > Java Build Path > Projects > click Add > check the box against the main FatWire code project. Now my unit test project will have all of the main FatWire project's code in its classpath.

Local JumpStart

In this section, I will explain the steps required to set up a local version of JumpStart that can be used for development and testing of both elements and Java backend code. I will integrate this JumpStart with my FatWire code project.

JumpStart 5.5 uses Resin underneath the hood.

  1. I get the JumpStart kit from the company repository (it's proprietary software and not available from the 'net) and unzip it somewhere such as C:\WorkSpaces\FatWireJsk_5.5.
  2. Click C:\WorkSpaces\FatWireJsk_5.5\CLICK ME FIRST.exe to start Content Server.
  3. I have a short-cut for this (for Windows).
    1. I right click on CLICK ME FIRST.exe and select "Create Shortcut"
    2. I rename the short-cut to something like "JumpStart - CS 5.5".
    3. I click and drag the shortcut to my Quick Launch bar.
    4. I do the same with Content Server Explorer (C:\WorkSpaces\FatWireJsk_5.5\JumpStart\tools\ContentServerExplorer\ContentServerExplorer.exe) and name it something like "CS-Explorer 5.5".
    5. It is important to keep track of the version numbers - CS-Explorer 7.02 is a bit flaky when connecting to Content Server 5.5 for example.
  4. I copy any JAR files I use in my FatWire code project to JumpStart's WEB-INF\lib folder, e.g. C:\WorkSpaces\FatWireJsk_5.5\resin\webapps\servlet\WEB-INF\lib. At least two exceptions are standard.jar and jstl.jar! Resin has its own jar files that cover this functionality.
  5. I next go to the WEB-INF directory that classes will be served from for JumpStart. For CS 5.5, this is C:\WorkSpaces\FatWireJsk_5.5\resin\webapps\servlet\WEB-INF.
  6. I create a classes directory within that folder.
  7. Within Eclipse I create an Ant build script (build.xml) in the main FatWire code project.
  8. I create an Ant task that will copy class files from the main FatWire code project to the WEB-INF\classes directory I just created. For example:
  9. <target name="deployClassesToLocalJumpstart">
      <fail unless="classes.dir"
            message="You must set classes.dir, such as -Dclasses.dir=C:\WorkSpaces\FatWireJsk_5.5\resin\webapps\servlet\WEB-INF\classes" />
      <copy todir="${classes.dir}">
         <fileset dir="bin">
            <include name="**/*.*" />
         </fileset>
      </copy>
    </target>
    
  10. In Eclipse, I create a run configuration to make it easy to run this task from within Eclipse.
    1. From within Eclipse, I select Run > External Tools > External Tools Configurations..
    2. I right click on Ant Build and select New and then select the new Ant build configuration just created.
    3. On the Main tab, I make sure the Buildfile points to my build.xml.
    4. Within the Arguments text area, I fill in the classes.dir argument. For example: -Dclasses.dir=C:\WorkSpaces\FatWireJsk_5.5\resin\webapps\servlet\WEB-INF\classes.
    5. On the Targets tab, I make sure the target I just wrote (deployClassesToLocalJumpstart) is ticked - and no others.
    6. On the Common tab, I select the Shared File radio button and click the Browse tab to select a directory in which to save the "run configuration". I do this so that I can check the "run configuration" file into source control for other programmers to use. Within my Eclipse project, I create a folder such as tools\eclipseIde for these sorts of files.
    7. Under "Display in favourites menu" I check the box for "External Tools". This makes it easier for me and other programmers to invoke the "run configuration".
    8. I click Apply.
    9. I click Close.
  11. Whenever I want to run this to deploy classes to my local JumpStart, I go Run > External Tools > DeployClassesToJumpstart. Personally, I use the keyboard shortcut for these run configurations: Alt, R (for Run), E (for External Tools), X (whatever number DeployClassesToJumpstart is assigned in the menu). For me, I currently type Alt,R,E,2 to deploy classes locally.
  12. After running this, I don't have to re-start JumpStart, but I do have to re-login to ContentServer and Content Server Explorer, because the web application gets restarted.

Now I have a local JumpStart running that I can run my own Java code within - and an Ant task to copy code over to Content Server. I use Content Server Explorer and the Advanced Interface as usual to interact with the other parts of Content Server.

Dynamic Web Project for CS Element Development

Now I need a way to edit CSElement files (primarily JSPs) in Eclipse. In this section I will go over how to create a Dynamic Web Project in Eclipse and set it up with all the ContentServer TLDs and Jar files. In the next section I will explore how to edit Content Server files in the Dynamic Web Project.

  1. In the same Eclipse workspace, I make a Dynamic Web Project. Since I am using FatWire 5.5, I made sure that "Dynamic Web Module Version" is at 2.3.
  2. Copy all of the files inside JumpStart's WEB-INF\lib folder to my dynamic web project's WEB-INF\lib folder, e.g. for FatWire 5.5 this was JumpStart5.5\resin\webapps\servlet\WEB-INF\lib.
  3. I copy the FatWire TLDs to my dynamic web project. For FatWire 5.5 this means copying the futuretense_cs folder (JumpStart5.5\resin\webapps\servlet\WEB-INF\futuretense_cs) to my dynamic web project's WEB-INF folder, i.e. I now have WEB-INF\futuretense_cs.
  4. Copy all of the TAGLIB elements from FatWire's web.xml (JumpStart5.5\resin\webapps\servlet\WEB-INF\web.xml) into my dynamic web project's web.xml.
    • Note the differences between web.xml in Servlet 2.3 (used in FatWire 5.5) and Servlet 2.4 (used in FatWire 7 and beyond).

      Excerpt from a Content Server web.xml using Servlet 2.3 - note that taglib is a child of web-app.

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
      <web-app id="WebApp_ID">
        <display-name>Fatwire5.5 Web</display-name>
        <welcome-file-list>
          <welcome-file>index.jsp</welcome-file>
          ....
        </welcome-file-list>
      
        <taglib>
          <taglib-uri>futuretense_cs/sessionobjects.tld</taglib-uri>
          <taglib-location>/WEB-INF/futuretense_cs/sessionobjects.tld</taglib-location>
        </taglib>
      </web-app>
      

      Excerpt from a Content Server web.xml using Servlet 2.4 - note that taglib is a child of jsp-config.

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app id="WebApp_ID" version="2.4"
            xmlns="http://java.sun.com/xml/ns/j2ee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <display-name>Fatwire7.0 Web</display-name>
        <welcome-file-list>
          <welcome-file>index.jsp</welcome-file>
          ....
        </welcome-file-list>
        <jsp-config>
          <taglib>
            <taglib-uri>futuretense_cs/csmac.tld</taglib-uri>
            <taglib-location>/WEB-INF/futuretense_cs/csmac.tld</taglib-location>
          </taglib>
          ....
        </jsp-config>
      </web-app>
      
  5. I give the dynamic web project access to my FatWire project code by selecting the dynamic web project and selecting Project > Properties > Java Build Path > Projects > click Add > check the box against the main FatWire code project. Now my dynamic web project project will have all of my main FatWire project's code in its classpath.

Editing CSElements

Now I have a dynamic web project with access to all the FatWire tag and Java libraries plus my own project work. I still need to hook this project up to my Content Server files so that I can edit them with Eclipse. Normally, I access Content Server files (CSElements such JSPs, XML files etc) through Content Server Explorer, which opens them up in a text editor of my choice. But this means I won't find out about compilation errors 'till I run the file - and I can't take advantage of the Eclipse tooling for JSP, Javascript, XML etc. I will fix this now.

Set up Eclipse to edit Content Server Explorer files in place. Whenever I edit or open some element through Content Server Explorer, it creates a copy of that file into temporary storage on my hard disk: these are the files I should edit with Eclipse.

  1. Find out what directory Content Server Explorer uses when creating local copies of the element files. UltraEdit tells me file locations when I use it to edit element files (I can also right click on a file tab and select "Open Folder" to open that directory in Windows Explorer). For me, running a FatWire 5.5 instance locally, it makes the files here: C:\Documents and Settings\rbram\Local Settings\Temp\localhost7001\ElementCatalog. Note the localhost7001 part: it is always a concatenation of the host-name/IP plus port number.
  2. I go to the WebContent/WEB-INF folder of my dynamic web project, right click and select New > Folder.
  3. Click Advanced.
  4. Check "Link to folder in the file system".
  5. Click Browse and navigate to the ElementCatalog directory Content Server Explorer is creating the local files within.
  6. I always change the "Folder name" of the folder to reflect the environment I am working within e.g. Local ElementCatalog or Dev ElementCatalog etc.
  7. Click OK.
  8. Click Finish.
  9. I can now directly modify any Content Server element from Eclipse, as long as I lock it and open it through Content Server Explorer first - then refresh my Navigator or Package Explorer view in Eclipse to pick up the file.
  10. Whenever I make an edit, I still have to go back to Content Server Explorer and select "save" there to have it upload the changes to the running application.
  11. Advantages to this approach:
    • I get to see all the files I am currently editing or just looking at - by that I mean all the files I have either opened or locked through Content Server Explorer.
  12. Disadvantages to this approach:
    • Every time I save in Content Server Explorer and go back to Eclipse, I get an annoying dialog that says "the file has been changed outside of Eclipse: do I want to reload the file?" I tried enabling the auto-refresh preference in Eclipse: Window > Preferences > General > Workspace > Refresh automatically. This had no effect so it seems I am stuck with that dialog every time.

Now I can do the following:

  1. My JSPs will compile and I will know about compilation errors etc immediately, without needing to run them.
  2. I have access to all the FatWire tags and classes because the dynamic web project includes the TLDs and APIs for them in the project classpath.
  3. I have access to all the classes in my main FatWire project because the dynamic web project includes the main FatWire project source in its project classpath.

Paste Unformatted Text into Word

Usually, when I want to copy and paste text into Word from a web page, I don't want the formatting. I just want the text and nothing else. In this entry I discuss various ways I have used to do just that.

Updates.
13/08/2009 9:59:07 AM. Corrected macro text thanks to the very helpful comment by Robert Kszan. Thank you Rob!
10/05/2010 3:46:58 PM. Added my preferred choice - using AutoHotkey!

Use Autohotkey Script

This is an amazing Windows scripting engine that is easy to write for and continually amazes me at the fantastic things it can do. First, install Autohotkey. Then create a plain text script file called utilities.ahk (or anything you want - as long as it has extension ahk) with the following contents.

; http://superuser.com/questions/7271/most-useful-autohotkey-scripts
; Paste as plain text
^+v::
    ClipSaved := ClipboardAll ; Save the entire clipboard to a variable of your choice.
    clipboard = %clipboard%  ; Convert any copied files, HTML, or other formatted text to plain text.
    ClipWait, 2
    Send ^v
    Sleep, 1000
    Clipboard := ClipSaved   ; Restore the original clipboard. Note the use of Clipboard (not ClipboardAll).
    ClipSaved =   ; Free the memory in case the clipboard was very large.
return

Save it and double click it - that's enough for AutoHotkey to pick up the script and have it ready. You should now see the AutoHotkey icon in your system tray. Test it out: copy something from a web-page; paste it into Word to see it pasted with formatting; then use control+shift+v to see it pasted as plain text.

Such an amazing tool, this is my preferred method for doing this now. Forget the rest of my post. :)

If you are as hooked as I am, feel free to try out the other scripts in the Superuser - Most useful AutoHotkey scripts? forum posting I got this one from. I have filled my utilities.ahk with others from that page; and since I want these shortcuts always available, I have put a shortcut to the file in my Startup folder (e.g. C:\Documents and Settings\Robert Bram\Start Menu\Programs\Startup.

Use a Text Editor

One way is to first paste the formatted text into a text editor which ignores the formatting (such as UltraEdit or NotePad) and then re-copy the plain text from the text editor, and paste it into Word.

Use a Firefox Add-On

Alternatively, if I am copying the formatted text from Firefox, I use the Copy Plain Text add-on. I select and right click the text I want and select "Copy as Plain Text". Then I can paste the copied plain text directly into Word.

Use Paste Special

If I have copied the text from another browser (or maybe another Word Document or PDF or something else that copies as formatted text), I can use Word 2007's "Paste Special" function.

Use the paste keyboard shortcut: CTRL+V. This pastes the formatted text, but the "Paste Special" icon appears (a little clipboard icon). Click on this icon and select "Keep Text Only".

Alternatively, access the "Paste Special" dialog through Word's menus.

  1. On the Ribbon's Home Tab, select Paste (select the word "Paste", not the clip-board icon) to bring up the Paste menu.
  2. Select "Paste Special".
  3. In the "Paste Special" dialog, select "As:" "Unformatted Text".
  4. Note there is a keyboard combination of ALT keys you can use to bring up the "Paste Special" dialog: ALT, H (Home tab), V (Paste), S (Paste Special).

Earlier version of Word (that don't have the supposedly super useful Ribbon) have the "Paste Special" dialog under Edit > Paste Special (ALT, E (Edit), S (Paste Special)).

Use a Macro

The Paste Special function is excruciatingly tedious for repeated uses. Luckily, we can make a macro for it and assign a keyboard shortcut to the macro.

Word 2007

  1. On the Ribbon's View tab, select Macros (select the word "Macros", not the icon) to bring up the Macros menu.
  2. Select "View Macros" to bring up the Macros dialog.
    • Or just press Alt+F8 to bring up the Macros dialog!
  3. In "Macro name", enter PasteUnformattedText.
  4. Click Create.
  5. This opens Microsoft Visual Basic and creates a new Sub (Sub Procedure), called PasteUnformattedText. Make sure the Sub Procedure is in Normal > Modules > General. Type the following line into the Sub Procedure.
    Selection.PasteSpecial DataType:=wdPasteText
  6. The code window should look something like this:

    (Click to open larger image.)
  7. Save your work and close Microsoft Visual Basic (ALT+Q).
  8. Back in Word, select Microsoft Office button in the upper left-hand corner.
  9. Select "Word Options".
  10. Select Customize on the left hand side.
  11. Click the Customize button down at the bottom of the "Word Options" dialog to bring up the "Customize Keyboard" dialog.

    (Click to open larger image.)
  12. In the "Customize Keyboard" dialog, select Macros on the left hand side.
  13. Select the macro you just made (PasteUnformattedText) on the right hand side.
  14. Click in "Press new shortcut key" and type the shortcut you want to use. I use "CTRL+SHIFT+V". It says this is currently assigned to something else, but I don't care - I override the old assignment because it isn't something I use.
  15. Click Assign and then Close to exit the "Customize Keyboard" dialog.
  16. Click OK to exit the "Word Options" dialog.
  17. You can now use that shortcut to access your macro.

Word 2003 and earlier

  1. Press Alt+F8 to bring up the Macros dialog.
  2. In "Macro name", enter PasteUnformattedText.
  3. Click Create.
  4. This opens Microsoft Visual Basic and creates a new Sub (Sub Procedure), called PasteUnformattedText. Make sure the Sub Procedure is in Normal > Modules > General. Type the following line into the Sub Procedure.
    Selection.PasteSpecial DataType:=wdPasteText
  5. Save your work and close Microsoft Visual Basic (ALT+Q).
  6. Back in Word, select Tools > Customize to bring up the Customize dialog.
  7. Select the Commands tab.
  8. On the left hand side, select Macros.
  9. On the right hand side, select Normal.NewMacros.PasteUnformattedText (the macro you just created).
  10. Click the Keyboard button down at the bottom of the "Customize" dialog to bring up the "Customize Keyboard" dialog.
  11. Click in "Press new shortcut key" and type the shortcut you want to use. I use "CTRL+SHIFT+V". It says this is currently assigned to something else, but I don't care - I override the old assignment because it isn't something I use.
  12. Click Assign and then Close to exit the "Customize Keyboard" dialog.
  13. Click OK to exit the "Word Options" dialog.
  14. You can now use that shortcut to access your macro.

Other Links

Other pages that helped me make this entry.

Wednesday, June 24, 2009

Where did my global variable go?

Came accross this problem the other day - thanks to David! Wanted to test if the javascript variable had already been defined (globally) and supply a default value if it wasn't defined.

  var name = "Rob";

  function testScope() {
    document.write("<p>Before IF. My name is " + name + "</p>");
    if (!name) {
      var name = "Rob2";
    }
    document.write("<p>After IF. My name is " + name + "</p>");
  }

  document.write("<p>Before testScope(). My name is " + name + "</p>");
  testScope();
  document.write("<p>After testScope(). My name is " + name + "</p>");

Here is the result.

   Before testScope(). My name is Rob

   Before IF. My name is undefined

   After IF. My name is Rob2
 
   After testScope(). My name is Rob

Unfortunately, simply declaring the var again (var name = "Rob2";) created a locally scoped version of the var for the entire function - even though I only declared it within the IF. The fix was easy: just remove the var.

  var name = "Rob";

  function testScope() {
    document.write("<p>Before IF. My name is " + name + "</p>");
    if (!name) {
      name = "Rob2";  // No var!
    }
    document.write("<p>After IF. My name is " + name + "</p>");
  }

  document.write("<p>Before testScope(). My name is " + name + "</p>");
  testScope();
  document.write("<p>After testScope(). My name is " + name + "</p>");

Here is the result.

   Before testScope(). My name is Rob

   Before IF. My name is Rob

   After IF. My name is Rob

   After testScope(). My name is Rob

It had a value all along!

Remember that global variables belong to the window object, thus the following would also have worked.

  if (!window.name) {
    window.name = "Rob3";
  }

My Favourite way to Google

keyboardr.com is my new favourite way to Google. It mashes results from Google (including blog and image search), Wikipedia, and YouTube. It shows results as you type and lets you keyboard through the results using the cursor keys.

Use the nightly build site to sample the most recent functionality.

Update: 4/08/2009 11:34:43 AM
I still like keyboardr, but Google has their own version, which I like more: Google Search with Keyboard Shortcuts on their experimental page. Here is a sample query.

Sunday, June 07, 2009

Tools for Java and Web Development

A programmer needs good tools, and a good memory in order to remember what things to re-install each time they get a new machine. I lack the second, so this page is my crutch. :)

Updates.
15/06/2009 12:15:36 PM. Added new row to Firefox v Chrome comparison: Bookmarks/Search. This article is copied from my Google App Engine site.

IDE

Eclipse is my IDE of choice, though I prefer Dreamweaver for HTML editing. Eclipse is fantastic for code editing, but sucks for HTML editing when compared to Dreamweaver. Dreamweaver lets you customize existing keyboard shortcuts.

Here is a list o the Eclipse plugins I use.

  • Andrei Loskutov has a set of Any Edit Eclipse plugins. I always install AnyEdit Tools so that I can do things like various on-save actions like remove trailing spaces. Update site: http://andrei.gmxhome.de/eclipse/.
  • StartExplorer is a very handy plugin for opening Windows Explorer from any path in Navigator view (or the like) or copying the qualified name of a resource to the clipboard: a couple of tasks I have wanted to perform from within Eclipse enough times to make this plugin well worthwhile. Update site: http://startexplorer.sourceforge.net/update
  • Multi clipboard and Tiny HTML. Tiny HTML gives a few quick ways to insert common HTML tags, but it is Multi-Clipboard that I really like! Multi-Clipboard gives you a clipboard view and lets you copy to/paste from multiple clipboard slots. Many is the time I wished to copy two or more items simultaneously to the clipboard, and this plugin is perfect for it. It is something UltraEdit has had since I started using it and which I have ever since wished to see in Eclipse! I tend to keep a couple of often used snippets in the first two slots because it is so easy once you assign the right short-cuts to it. Update site: http://www.bastian-bergerhoff.com/eclipse/features.
  • FindBugs is a very important tool for warning you of many common errors and helps you write better code. Update site: http://findbugs.cs.umd.edu/eclipse.
  • CheckStyle is another very important tool: it helps you write consistent code according to whatever common practices you or your team accept. Update site: http://eclipse-cs.sourceforge.net/update.
  • Aptana Studio is a stand-alone product that also offers a plugin for Eclipse that has a very nice Javascript Editor, plus a ton of other features. Not a necessary plugin, and I find it a bit heavy and occasionally flaky. Update site: http://update.aptana.com/update/studio/3.4/.
  • Dead. Column Mode for Eclipse was my all time favourite for about two months: it gave UltraEdit style column mode editing, but now (as of Eclipse Version: 3.4.2) it doesn't work for some reason. Eclipse 3.5 will have it's own column edit mode of some sort though, so here's hoping!
  • Dead. Eclipse Bookmarks was a favourite of mine for making and navigating around quick bookmarks with simple keyboard shortcuts. At last something that makes the Bookmarks view actually useful. I say "was", because the site is dead.

Browser

Mozilla's Firefox is in a very close fight with Google's Chrome for being my browser of choice.

Feature Firefox Chrome
Plugins Huge array of very useful plugins a.k.a. add-ons. Favourite plugins: Xmarks and Firebug. None, yet. Xmarks is promised but not here yet. The in-built developer tools don't seem to be as useful as Firebug.
Memory Despite various tips on how to reduce memory usage, Firefox (2 and 3) still becomes a sluggish memory hog after a few hours of usage. This may be the fault of an errant plugin, but there is no easy way to tell when you are using 20+ add-ons. One process per tab and a process manager that shows per tab and per plugin memory use with the ability to end either.
Tabbed UI So faster and more flexible than IE. Can split tabs with Split Browser plugin. Ditto IE comment, but better than Firefox: with Chrome you can rip tabs off into their own window - much better than Firefox's Split Browser add-on.
Bookmarks/Search Has a very functional bookmarks sidebar, enhanced by a few good plugins. Lets you access bookmarks and quick searches from the address bar.

Brilliant search technique from the address bar: Google search by default; type "youtube.com" and press tab to search youtube.com.

But only shows three bookmarks results at a time when you type in the address bar. What's up with that??

What about Javascript engines? To be honest, I haven't noticed a difference - both seem to be great.

I usually make sure to have Safari, Opera and IE (or the sometimes buggy Standalones) handy for testing all platforms.

Here is a list of the Firefox add-ons I use.

  • Adblock Plus to get rid of pesky ads.
  • All-in-One Sidebar groups things like bookmarks and add-ons into one side bar instead of pop-ups etc.
  • Better Gmail 2 allows you to customize Gmail.
  • Boox allows me to locate a bookmark when I search for it. I.e. in the bookmark view I can type "java", see all matching bookmarks, right click on it and select "locate" and see where in my folder hierarchy the bookmark actually is.
  • CacheViewer view my cache.
  • CustomizeGoogle allows you to customize lots of different Google tools like search, maps, mail etc.
  • Download Statusbar shows status of downloads in the status bar - much better than Firefox's downloads view.
  • FEBE backs up your add-ons or entire profile.
  • Fetch Text URL opens plain text URLs.
  • Firebug is the tool for debugging CSS and Javascript.
  • Firecookie is a cookies add-on for Firebug.
  • FireGestures brings mouse gestures to Firefox. Now I use StrokeIt on Windows because it offers mouse gestures for all programs.
  • Xmarks Bookmark Synchronizer (formerly FoxMarks) synchronizes your bookmarks and passwords across Firefox/IE on any machine. Soon support will be added for Chrome too, hopefully.
  • FoxyTunes controls your music player from within Firefox.
  • Gmail Manager is a Gmail notifier for multiple accounts.
  • Greasemonkey allows you to customize the way a web page displays using small bits of JavaScript.
  • gui:config adds an advanced settings panel with easy access to options normally hidden behind cryptic about:config options.
  • IE Tab can view any tab in IE.
  • iMacros for Firefox can record/play macros which you can bookmark and add your own javascript to. Inserting Javascript is a bit awkward though. You can't insert Javascript into a macro: you have to write Javascript that launches (and manipulates data from) macros. Has one macro language.
  • It's All Text! lets you edit text area content in your favourite text edit.
  • LastTab allows tab navigation (with tab preview) in a most recently used manner.
  • NoScript allow active content to run only from sites you trust, and protect yourself against XSS and Clickjacking attacks. This one is beginning to annoy me though, because I forget to allow a site and wonder why it isn't working!
  • PDF Download gives better control of PDF files within Firefox.
  • Selenium IDE is another macro add-on that allows you to bookmark the macros and use Javascript. Unlike iMacros, you can insert Javascript into the macros. Selenium allows you to write the macros in a wide variety of client languages.
  • Show Keywords creates short-cuts to site specific searches. Not really needed any more though - use Smart Keywords.
  • Speed Dial puts 9 (by default) shortcuts to your favourite URLs on a newly opened tab. Lets you open any of them with keyboard shortcuts (control+1-9 to open the URL in the current tab; control+shift+1-9 to open the URL in a new tab).
  • Split Browser brings split screens to Firefox. Not as nice Chrome's ability to rip tabs off into their window.
  • StatusbarEx adds useful stats to the status bar, like current memory and bandwidth usage for Firefox.
  • Tab Clicking Options gives you a bunch of extra tab actions when you click on a ... tab.
  • Taboo lets you save a page for later (taking a screen shot, and using the Session Saver code to remember scroll location and form fields).
  • TagSifter lets you search through bookmarks by tags. Has a tool to add tags to existing bookmarks based on the folder hierarchy.
  • TwitKit is a Twitter sidebar, TwitterBar posts to Twitter from the address bar, TwitterFox is a FireFox Twitter client with a nice looking unobtrusive UI.
    • I have given all of these up in favour of Twhirl, an Adobe Air desktop client. I was using TweetDeck for a while (another Adobe Air desktop client) but it doesn't show new messages in the pop-up - which Twhirl does (and TwitterFox, but TwitterFox shows the pop-up only within FireFox).
  • Undo Closed Tabs Button re-opens tabs you just closed.
  • Video DownloadHelper lets you download streaming videos.

Database

As far as database clients go, DBVisualizer is my client of choice. It works against every DB I know of and has an impressive feature list. The personal version is free, but you can continually renew an evaluation license of the full version. One of my favourite aspects is the references view that gives you a great ERD. Doesn't run PL/SQL.

Eclipse comes in-built with some good database tooling too - a very easy way to execute selected pieces of SQL. Doesn't run PL/SQL.

Command line/Scripting environment

I think it is important as a programmer to get cosy with a Linux command line environment and a scripting language and build up a library of useful custom tools and utilities. I use Cygwin, a Linux-like environment for Windows, with PuttyCyg as the terminal. I use bash and have written over 50 bash scripts over the past few years to do various jobs like searching and file/project management tasks. Some of my favourite ones are shared on my blog.

Text editor

UltraEdit has always been my "go-to" editor. It has great basic to advanced functionality like column edit mode and a diff function. It supports roll-your-own macros, templates, Javascript scripts, tags, syntax highlighting and function lists. About the only thing I wish it had was Textpad's ability to automatically highlight all instances of the currently selected token.

For the times when I am on a command line, I made it my business to get comfortable with vim. You get Gvim from the same place. Vim has a steep learning curve if you are a Windows user, and there is a full on religious war between lovers of vim and Emacs, but I chose vim because at some level it seemed easier. I have since found that vim is quite extensible: you can configure so many aspects of it, and its macro system is great too. I put up some vim tricks I find on my blog.

I am also just beginning to teach myself Jedit, which I want to use so that I can write macros in Java!

Thursday, May 07, 2009

Ant: multi-line message/echo

Use the ${line.separator} property to split up long echo or message values. An example is below.

<target name="runTest" description="Run a test!">
 <echo>This is the first line.${line.separator}This is the second line.</echo>
</target>

This produces the following output:

> ant runTest
Buildfile: build.xml

runTest:
     [echo] This is the first line.
     [echo] This is the second line.

BUILD SUCCESSFUL
Total time: 0 seconds

Tuesday, February 10, 2009

Displaying the Java Console

My set up:

  • Windows XP, SP 2.
  • JDK V6, Update 11
  • I.E. 7
  • Firefox 3.0.6
  • Google Chrome 1.0.154.48
  • Safari 3.2.1

You cannot open the Java console from any of these browsers any more. Instead, look at your system tray. You should see a small Java icon (one for each browser). Right click on the icon and select "Open Console" (or "Open [version number] Console".

What I would like to see is a tabbed console, with the tabs labelled in such a way to identify which browser (or even browser tab/instance) they are for. Perhaps this would use a shared VM, or perhaps it would rely on message passing?