Categories
Coding

Spring and Hibernate’s getCurrentSession()

If you are using Spring to wrap a Hibernate SessionFactory and you are not using Spring-managed transactions, you may run into an issue. The reason is that Spring by default will wrap Hibernate’s SessionFactory implementation and delegate to its own transactional version. If you are just using the simple ThreadLocal-based session-per-request functionality, then when you attempt to open the Session, you will get an IllegalStateException thrown, with the error message "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here". This happens because Spring’s SessionFactoryUtils checks if the Session is bound to Spring’s transactional support, and by default throws an error if it is not.

The solution to this is to set the property

<property name="exposeTransactionAwareSessionFactory"><value>false</value></property>

in the Spring config. This will return the “raw” SessionFactory instead of the proxied one. A snippet of code from AbstractSessionFactoryBean shows where the check is done:

 
/**
   * Wrap the given SessionFactory with a transaction-aware proxy, if demanded.
   @param rawSf the raw SessionFactory as built by <code>buildSessionFactory()</code>
   @return the SessionFactory reference to expose
   @see #buildSessionFactory()
   @see #getTransactionAwareSessionFactoryProxy
   */
  protected SessionFactory wrapSessionFactoryIfNecessary(SessionFactory rawSf) {
    if (isExposeTransactionAwareSessionFactory()) {
       return getTransactionAwareSessionFactoryProxy(rawSf);
    }
    else {
      return rawSf;
    }
  }

A sample Spring config is shown below.

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
    <property name="url" value="jdbc:hsqldb:hsql://localhost:9001"/>
    <property name="username" value="sa"/>
    <property name="password" value=""/>
  </bean>

  <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
     <property name="exposeTransactionAwareSessionFactory"><value>false</value></property>
    <property name="annotatedPackages">
      <list>
        <value>uk.co.researchkitchen.hibernate</value>
      </list>
    </property>
    <property name="annotatedClasses">
        <list>
                <value>uk.co.researchkitchen.hibernate.Product</value>
                <value>uk.co.researchkitchen.hibernate.ProductDescription</value>
        </list>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.HSQLDialect
        hibernate.show_sql=true
            hibernate.hbm2ddl.auto=create
            hibernate.current_session_context_class=thread
      </value>
    </property>
  </bean>

</beans>
Categories
Coding

Ignoring Bash Aliases

If you have any aliases defined in your .bashrc or .bash_profile files, occassionally you may run into a situation where you would like to selectively ignore those aliases. In my shell, I have aliased ls like so:

alias ls ‘ls -lF –color’

However, when running a simple command like the following (which searches for filenames within a set of jar files), this breaks, as the output of ls is in long format. Instead of having to use cut or awk to slice off the parts of the output we need, we can escape the aliased command, effectively telling bash to ignore the alias:

for j in $(\ls *.jar); do jar tvf $j | grep -i “gfxjavactask” ; done

Note the \ in front of the command name. This is an obscure one, I know! 🙂

Categories
Coding

Using the NSIS Install Engine

Whilst packaging up a plugin based on the Skype API that I had been writing, I was looking for a way to bundle it all up cleanly. The finished plugin consisted of an .exe, a COM wrapper DLL (the very useful Skype4COM wrapper), and some HTML documentation for the C++ code (generated by doxygen). I thought this might be a good opportunity to have a look at NSIS, the installer generator that is used by a huge number of open-source (and other) projects.

My install requirements were quite simple. The following steps needed to be performed:

  • Copy the .exe and associated HTML docs to the target system;
  • Copy the COM DLL to the target system;
  • Register the COM server (by invoking regsvr32);
  • Create any necessary Start Menu items (and an uninstaller);
  • Open a web browser automatically on the index page documentation.

Obviously, the uninstaller would need to remove all files, and also unregister the COM server before uninstalling.

I downloaded NSIS from the web site and fired up the NSIS Compiler. This is a very simple interface that allows you to drag-and-drop .NSI script files into its interface and execute them. The NSIS scripting runtime is a very simple scripting language, with some basic language constructs, and the ability to define and import macros and plugins for extended functionality.
A screenshot of the compiler interface is shown below:

NSIS Compiler Interface

Here is the full installation script for my plugin, annotated with some comments.

; Skype Plugin NSIS Installer Script File
; Rory Winston <rory@researchkitchen.co.uk>
;--------------------------------
;Include some predefined NSIS libraries (for modern UI look and feel)

  !include "MUI.nsh"

;--------------------------------

XPStyle on

;General

  ;Name and file
  Name "Skype Plugin"
  OutFile "SkypePluginInstaller.exe"

  ;Default installation folder
  InstallDir "$PROGRAMFILES\Skype Plugin"

  ;Get installation folder from registry if available
  InstallDirRegKey HKCU "Software\Skype Plugin" ""

;--------------------------------
;Interface Settings

  !define MUI_ABORTWARNING

;--------------------------------
;Pages
; These are predefined "wizard pages" that NSIS can generate for us. Note that I 
; am including a custom license file on the MUI_PAGE_LICENSE page.
  !insertmacro MUI_PAGE_LICENSE "NOTICE.txt"
  !insertmacro MUI_PAGE_COMPONENTS
  !insertmacro MUI_PAGE_DIRECTORY
  !insertmacro MUI_PAGE_INSTFILES

  !insertmacro MUI_UNPAGE_CONFIRM
  !insertmacro MUI_UNPAGE_INSTFILES

;--------------------------------
;Languages

  !insertmacro MUI_LANGUAGE "English"

; Show a custom splash screen on installer entry
Function .onInit
        InitPluginsDir
        File /oname=$PLUGINSDIR\splash.bmp "installer.bmp"

        splash::show 1000 $PLUGINSDIR\splash

        Pop $0 ; $0 has '1' if the user closed the splash screen early,
                        ; '0' if everything closed normally, and '-1' if some error occurred.
FunctionEnd

;--------------------------------
;Installer Sections

Section "Install Skype Plugin" SecSkypePlugin

  SetOutPath "$INSTDIR"

  ; Copy all of the required files (note the /r switch to recursively copy directories)
  File "SkypePlugin.exe"
  File "Tariffs.dat"
  File /r "..\docs"
  File "Skype4COM.dll"

  ; Register the COM server
  RegDLL Skype4COM.dll

  ;Store installation folder
  WriteRegStr HKCU "Software\Skype Plugin" "" $INSTDIR

  ;Create uninstaller
  WriteUninstaller "$INSTDIR\Uninstall.exe"

  ; Open the docs using the default (shell-assigned) browser
  ExecShell "open" "$INSTDIR\docs\html\index.html"

SectionEnd

; Optional section (can be disabled by the user)
Section "Start Menu Shortcuts"

  CreateDirectory "$SMPROGRAMS\Skype Plugin"
  CreateShortCut "$SMPROGRAMS\Skype Plugin\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
  CreateShortCut "$SMPROGRAMS\Skype Plugin\Skype Plugin.lnk" "$INSTDIR\SkypePlugin.exe" "" "$INSTDIR\SkypePlugin.exe" 0
  CreateShortCut "$SMPROGRAMS\Skype Plugin\Documentation.lnk" "$INSTDIR\docs\html\index.html" "" "$INSTDIR\docs\html\index.html" 0
SectionEnd


;--------------------------------
;Descriptions

  ;Language strings
  LangString DESC_SecSkypePlugin ${LANG_ENGLISH} "Skype Plugin Installation."

  ;Assign language strings to sections
  !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
    !insertmacro MUI_DESCRIPTION_TEXT ${SecSkypePlugin} $(DESC_SecSkypePlugin)
  !insertmacro MUI_FUNCTION_DESCRIPTION_END

;--------------------------------
;Uninstaller Section

Section "Uninstall"

  Delete "$INSTDIR\Uninstall.exe"

  ; Unregister the COM server
  UnRegDLL "$INSTDIR\Skype4COM.dll"

  ; Delete all installed files
  RMDir "$INSTDIR"

  ; And registry entries
  DeleteRegKey /ifempty HKCU "Software\Skype Plugin"

  ; Remove shortcuts, if any
  Delete "$SMPROGRAMS\Skype Plugin\*.*"
  RMDir "$SMPROGRAMS\Skype Plugin"

SectionEnd

Some points of note:

  • The RegDLL and UnRegDLL directives will register and unregister a COM server on your behalf;
  • NSIS provides “hooks” at various points of the installer lifecycle. For instance, the splash screen in shown by the .onInit handler.
  • The ExecShell command (which seems to be a high-level wrapper around the ShellExecute function), can be used to open arbitrary files.

NSIS is a great application, and incredibly easy to pick up and use. The installers it produces are very slick looking, and can be extensively customised. It’s no wonder that this framework is now so popular.