It’s last post on blog.com

by Vjacheslav Ignatyev on October 30, 2012

I’ve relocated the blog to Blogger Service. Meet the Software Design And Development blog!

Make Jdb Sourcepath

by Vjacheslav Ignatyev on July 2, 2012

I’ve reimplemented script which scans sources and makes rc file for the Jdb. Now it’s in Elisp jdb-sourcepath.el.

Here is init.el snippet:

(require 'jdb-sourcepath)
(add-hook
 'jdb-mode-hook
 (lambda ()
   (set 'gud-jdb-sourcepath (jdb-sourcepath-from-rc))))

(run-at-time "1:00am" (* 60 60 24) 'jdb-setup)

“Connection Manager” for the Sqlplus Mode

by Vjacheslav Ignatyev on June 27, 2012

As a developer you have to deal with several different databases. It’s not easy to keep all of your environments in mind. Let’s use Org-mode to help yourself.

Keep an environment’s description in “org-mode” table:

* environments
** databases
|---------------+-----------+--------|
| service (sid) | user      | pwd    |
|---------------+-----------+--------|
| prod          | owner app | god    |
| dev           | dbo       | love   |
| uat           | dba       | secret |
|---------------+-----------+--------|

Place the point to a connection line, call sqlplus-x-connect and you will get connected sqlplus-mode buffer. If different users have the same password you can write them in one cell.

Here is the sqlplus-x-connect

(require 'sqlplus)
(require 'org-table)
(defvar sqlplus-x-columns '(sqlplus-x-service sqlplus-x-user sqlplus-x-pwd))
(defun sqlplus-x-connect ()
  "Build a connection string and make a connection. The point must be in an org-mode table.
Columns of the table must correspond to the `sqlplus-x-columns' variable."
  (interactive)
  (org-table-force-dataline)
  (let
      ((cur-row (nth (org-table-current-dline) (org-table-to-lisp)))
       (is-user-selected (= (org-table-current-column) (+ 1 (position 'sqlplus-x-user sqlplus-x-columns)))))
    (sqlplus
     (format
      "%s/%s@%s"
      (if is-user-selected
          (thing-at-point 'symbol)
        (nth (position 'sqlplus-x-user sqlplus-x-columns) cur-row))
      (nth (position 'sqlplus-x-pwd sqlplus-x-columns) cur-row)
      (nth (position 'sqlplus-x-service sqlplus-x-columns) cur-row))
     (concat (nth (position 'sqlplus-x-service sqlplus-x-columns) cur-row) ".sqp"))))

(global-set-key [f4] 'sqlplus-x-connect)

Advice. Use EasyPG package to keep your connections table in secret.

Java Development With Emacs

by Vjacheslav Ignatyev on June 22, 2012

I would like to share my J2EE development environment. Currently it’s Emacs 23 on Linux, Maven and few additional pieces of software.

JDE

The JDE is a major mode for editing java sources. I will not describe the whole package, just emphasize customizations and a way I use it. Since JDE has lack of Maven support I use Maven2 Jdee plugin to transforms pom.xml to prj.el. Here is oneliner which periodically performs such transformation on projects tree:

$ crontab -l
...
0 2 * * * find ~/projects/ -path \*/arch -prune -o \( -name pom.xml -print \) | \
sed 's/pom.xml//' | sort | awk 'BEGIN {P="doh"} {if (index($0, P)==0){P=$0; print P "pom.xml"}}' | \
xargs -P1 -n1 $M2_HOME/bin/mvn install jdee:jdee -DskipTests=true -q -f
...

Unfortunately this script is quite complex because there are multi-module Maven POMs and we have to exclude their subprojects.

The JDE’s settings are quite simple. I just set compiler output directory to the temporary folder to prevent the source directories from useless compiled files.

(load "jde-autoload")
(setq jde-check-version-flag nil)
(setq jde-compile-option-directory
      (concat user-emacs-directory "tmp"))

(require 'gud)
(defun java-my-minor ()
 (progn
  (gtags-mode t)
  (glasses-mode t)
  (auto-complete-mode t)
  (add-to-list 'ac-sources ac-source-gtags)
  (local-set-key [f8] 'gud-next)
  (local-set-key [f9] 'gud-cont)
  (local-set-key (kbd "M-/") 'hippie-expand)
  (local-set-key (kbd "C-c C-v .") 'jde-complete-minibuf)
  (add-hook 'before-save-hook
            (lambda ()
              (jde-import-kill-extra-imports)
              (jde-import-all)
              (jde-import-organize))
            nil t)
  (add-hook 'after-save-hook 'jde-compile nil t)))
(add-hook 'jde-mode-hook 'java-my-minor)

Documention

The JDE has nice feature “Context-Sensitive Class Help”. There are no problems when you have graphical UI (XServer, Windows, etc.), you just specify your favourite browser (I’m sure it’s “Conkeror” ) and use it. I wish I had graphical UI. Console is all that I have. So I use text mode browser “w3″. It’s unable to display local files so there is small fix:

(require 'jde-help)
;; w3 fail to load local file, so skip this feature
(defmethod jde-jdhelper-show-url ((this jde-jdhelper) url)
  (let ((doc-url (jde-url-name url)))
   (message "Displaying %s from %s"
            (oref url :class)
	     (oref (oref url :docset) :description))
   (jde-jdhelper-show-document this doc-url)))

Building

One of the most boring routine in Java language is specifying imports. The JDE might do it for us automatically. All we need is just to append calls to “before-save-hook”. To provide fast call back each file is compiled after saving, so you can efficiently fix cause of error without full project rebuilding.

...
  (add-hook 'before-save-hook
            (lambda ()
              (jde-import-kill-extra-imports)
              (jde-import-all)
              (jde-import-organize))
            nil t)
  (add-hook 'after-save-hook 'jde-compile nil t)))

I use “compile” command to run Maven goals. It’s suitable for all targets such as building, testing, running. Torstein K. Johansen suggests to use “C-z” binding to call “compile”. Setting “jde-compile” variable to “compile” seems reasonable as well. Anyway:

(setq jde-compile 'compile)
(global-set-key (kbd "C-z") 'compile)

Here is a few additional regexps to recognize compilers output:

(require 'compile)
(setq compilation-error-regexp-alist
      (list
       ;; works for maven 3.x
       '("^\\(\\[ERROR\\] \\)?\\(/[^:]+\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\]" 2 3 4)
       ;; works for maven jde javac server
       '("^\\(/[^:]+\\):\\([0-9]+\\):" 1 2)
       ;; surefire
       '("^\\sw+(\\(\\sw+\\.\\)+\\(\\sw+\\)).+<<< \\(FAILURE\\|ERROR\\)!$"2)))

I append predefined command lines from “java-compile.org”. Header of each line is part of effective command so is possible to find a line in mini-buffer’s history by pressing “M-r” + “header”:

;; append compilation snippets
(let ((snippets-buf
        (find-file-noselect
          (concat user-emacs-directory "/etc/java-compile.org")))
  (setq compile-history nil)
  (with-current-buffer
      snippets-buf
    (org-map-region
     '(lambda nil
        (add-to-list
         'compile-history
         (format
          "#%s\\\n%s"
          (nth 4 (org-heading-components))
          (mapconcat 'string (org-get-entry) ""))))
     1 (buffer-end 1))
    (kill-buffer snippets-buf)))

Here an is example of predefined command lines (“java-compile.org”):

* ALL
P="dev,risk"; SKIP="true"; \
mvn clean install -f ~/projects/h/vaadin-components/pom.xml -DskipTests=$SKIP && \
mvn clean install -f ~/projects/h/hierarchies/pom.xml  -DskipTests=$SKIP -P$P 

* RUN
P="dev,risk"; SKIP="true"; \
MAVEN_OPTS="$MAVEN_OPTS -Xrunjdwp:transport=dt_socket,address=40487,server=y,suspend=n"; \
mvn  -pl application/ jetty:run-exploded -f ~/projects/h/hierarchies/pom.xml  \
-P$P -Djetty.port=40480 

* CRUN
PL="core"; P="dev,risk"; SKIP="true"; \
mvn clean install -f ~/projects/h/hierarchies/pom.xml  -DskipTests=$SKIP -P$P -pl "${PL}" && \
MAVEN_OPTS="$MAVEN_OPTS -Xrunjdwp:transport=dt_socket,address=40487,server=y,suspend=n"; \
mvn  -pl application/ jetty:run-exploded -f ~/projects/h/hierarchies/pom.xml  \
-P$P -Djetty.port=40480

Tags

I use GNU GLOBAL as tagging system. It provides more correct tags table for Java then ctags or etags.

(require 'gtags)
(autoload 'gtags-mode "gtags" "" t)
(setq gtags-suggested-key-mapping t)
(global-set-key (kbd "C-c C-f") 'gtags-find-file)
(add-hook 'gtags-select-mode-hook
  '(lambda ()
     (setq hl-line-face 'underline)
     (hl-line-mode 1)))

Logs

Log4j mode nice and only mode for viewing log4j logs in Emacs.

(require 'log4j-mode)
(setq auto-mode-alist
      (append '(("server.log" . log4j-mode)
                ("catalina.out" . log4j-mode)
                ("tomcat.log" . log4j-mode))
              auto-mode-alist))
(add-hook
 'log4j-mode-hook
 (lambda ()
   (setq truncate-lines t)
   (text-scale-set -1)
   (toggle-read-only t)
   (buffer-disable-undo)
   (end-of-buffer)))

Completing

There are no special settings for Auto Complete Mode except adding “jde-mode” to “ac-list” and adding “gtags” as source.

(require 'auto-complete-config)
(ac-config-default)
(add-to-list 'ac-dictionary-directories "~/.emacs.d/site-lisp/auto-complete/ac-dict")
(add-to-list 'ac-modes 'jde-mode)
(setq ac-ignore-case 'smart)
(setq ac-use-menu-map t)
(define-key ac-menu-map "\C-n" 'ac-next)
(define-key ac-menu-map "\C-p" 'ac-previous)

Debugging

I use jdb as a debuger. There are some additional steps to make it work properly. I’ve made script wich appends all sources from the projects tree into ~/.jdbrc and ~/.emacs.d/var/jdb-directories.el. Both of them are used for proper navigation within sources. Script runs periodically.

#!/bin/bash

BASE_NAME=${HOME}/projects
EMACS_JDB_DIR=${HOME}/.emacs.d/var/jdb-directories.el

SEARCH_EXT="java groovy"
SEARCH_EXLUDE_PATH="examples test samples tests tmp vendors target"

TMP_LIST=/tmp/.jdb.list
# construct searching regexp
REGEXP_SEARCH=$(
    echo -n ${BASE_NAME}
    echo -n '.*\.\('
    echo -n ${SEARCH_EXT} | sed 's/\ /\\|/g'
    echo -n '\)$'
)

REGEXP_EXCLUDE=$(echo ${SEARCH_EXLUDE_PATH} | sed 's/\ /\\|/g' )
REGEXP_EXCLUDE="\/\(${REGEXP_EXCLUDE}\)\/"

# findup sources
find $BASE_NAME -follow \( -path \*/.svn -o -path \*/target \) -prune -type f -o \( -path \*/src/\* \) -iname '*.java' \
| xargs -n1 -P0 awk '/^\t*package/ { sub(";",""); num=match(FILENAME, $2); print substr(FILENAME, 1, num - 2); exit}'  \
| sort | uniq | sed '/^$/ d; s/cygdrive\/c/c:/;' > ${TMP_LIST}

(awk 'BEGIN {print "use ."} {sub("/cygwin/c","c:/"); print $0 }' ${TMP_LIST} | tr '\n' ':' > ${HOME}/.jdbrc ) &
(awk 'BEGIN {print "(setq gud-jdb-sourcepath (quote ("} END {print ")))"} { print "\"" $0 "\"" } ' ${TMP_LIST} \
| tr '\n' ' '  > ${EMACS_JDB_DIR}) &

This is the hook which sets sources path for the jdb:

(add-hook
 'jdb-mode-hook
 (lambda ()
   (load-file
     (concat
       user-emacs-directory
       (convert-standard-filename "var/jdb-directories.el")))))

The brilliant Jdb feature is redefining class on fly. Here is a shortcut for it:

;; Redefine class thru jdb
(gud-def
 gud-redefine
 (gud-call
  (format
   "redefine %%c %s/%s.class"
   (file-truename jde-compile-option-directory)
   (replace-regexp-in-string "\\." "/" (gud-format-command "%c" arg))))
 "\C-r" "Redefine class")