Introduction

Imagine that you have few developers working on Java project. Code of the project is committed to GIT repository and there are ANT scripts implemented to facilitate builds and deployments of the system as well as additional activities that might be useful. The developers using this infrastructure push code changes to GIT repository and automatic build and deployment of the latest code version should be automatically deployed on Tomcat server. This blog describes simple automatic build system that users GIT hooks to invoke appropriate ANT tasks depending on files that were changed in the system.

Users

There are two users that are crucial to run the automatic builds:

  • git – this user is owner of GIT repository and the commits are made as git user
  • tomcat – this user should run Tomcat

To allow the deployments, which involve stopping and starting Tomcat server, git user should be able to run tomcat as tomcat user. This functionality can be enabled in /etc/sudoers file.
Run:

sudo visudo

and add the following line

git ALL = (tomcat) NOPASSWD: ALL

To run a command as Tomcat user type

sudo -u tomcat {command name}

If you set some variables you might want not to reset them once you run sudo command. To do so add variable names to sudoers file

Defaults        env_keep += "JAVA_HOME"

Project structure

Let’s assume that our project has the following structure:

  • project – source of the project to be compiled and deployed
    • src – source code
  • configuration – Tomcat configuration files
  • git – GIT configuration files
    • post-receive – script to be invoked after push is made to GIT repository
  • build.xml – ant build script

Ant script

Let’s assume that ant script has following targets defined:

  • build-deploy – build the project and deploy it on Tomcat server
  • deploy-configuration – deploy Tomcat configuration

Depending on code changes the following targets should be run:

  • on change in project/src folder build-deploy tasks should run
  • on change in configuration folder deploy-configuration task should run

Git repository

Hooks

Git allows to run actions on several events, which mechanism is implemented using hooks. There are several hooks defined in git. Some of them are client side and some of them are server side. More information regarding hooks can be found here

Bare git repository is located on the server. Hooks are located in {git repository path}/hooks/. We are going to use server-side post-receive hook to make automatic builds. The post-receive hook runs after the entire process is completed and can be used to update other services or notify users. It takes a list of references that are being pushed from stdin.

The hooks will run as user which logs into GIT therefore it is important to ensure that tasks can be run as this user or user can run tasks as other user.

Configuration

To use ant build file (build.xml) and post-receive script, the checkout of the repository has to be done on the same server:

git clone {local path to repository}

The checkout should be done as tomcat user.

Each time push will be made to the repository, the checkout repository should be updated (git pull) and then the files from the repository could be used for builds. Having both files in the repository (build.xml and post-receive) allows dynamic configuration changes and flexible build system without a need to make any changes on the server.

post-receive hook configuration

We can invoke post-receive script which is in our git repository by invoking the script from post-receive hook in GIT repository. To do so post-receive file should be created in {git repository path}/hooks/ and made executable. The file, which is in fact bash script, should include the following commands:

#!/bin/sh

TEMP_GIT_FILE="/tmp/git.txt"
# Path to cloned version of git repository
GIT_CLONE="/opt/git-clone"

cd "$GIT_CLONE"
# Update cloned version of git repository as tomcat user
sudo -u tomcat git pull > /dev/null

rm $TEMP_GIT_FILE

while read line
do
  echo $line >> $TEMP_GIT_FILE
done

# Run post-receive script located in git repository
cat $TEMP_GIT_FILE | ./git/post-receive

Automatic build script – post-receive

The following listing presents automatic build script. The script is located in GIT repository in git folder, so whenever it is changed the changes are automatically applied. The comments regarding parts of the script are within the code.

#!/bin/sh

# Log all the messages to the file
exec >> /opt/logs/git.log

# Path variables
TOMCAT="/opt/tomcat"
GIT="/opt/git"
GIT_CLONE="/opt/git-clone"

# Export variables
export JAVA_HOME="/opt/java/jdk1.7.0_07"
export PATH="$PATH":"$JAVA_HOME/bin"
export ANT_HOME="/opt/ant/apache-ant-1.8.4"
export PATH="$PATH":"$ANT_HOME/bin"
export TOMCAT_HOME=$TOMCAT

# Global variables to track code changes
configuration_change_global=1
code_change_global=1

echo "***********************************************************"
echo "BUILD"
echo $(date)
echo "***********************************************************"

cd "$GIT"

# Variables given 
while read oldrev newrev refname
do

  # Commit
  commit=$(git show $newrev | grep 'commit')
  # Date of commit
  date=$(git show $newrev | grep 'Date:')
  # Author of commit
  author=$(git show $newrev | grep 'Author:')
  
  echo "-----------------------------------------------------------" 
  echo "$commit" 
  echo "$date" 
  echo "$author" 
  echo "-----------------------------------------------------------"  
  
  # Code changes since last commit 
  git diff --name-only $newrev $oldrev | grep 'project/src' > /dev/null
  code_change=$? 
  git diff --name-only $newrev $oldrev | grep 'configuration' > /dev/null
  configuration_change=$? 
  
  if [ $code_change -eq 0 ]  
  then 
    code_change_global=0 
    echo "Source code changed" 
  fi 
  if [ $configuration_change -eq 0 ]  
  then 
    configuration_change_global=0 
    echo "Configuration changed" 
  fi  
done 
 
# Stop Tomcat 
cd "$TOMCAT/bin" 
sudo -u tomcat ./shutdown.sh
sleep 15 
 
pid=$(sudo -u tomcat ps aux | grep "tomca[t]" | awk '{print $2}') 
if [ -n "$pid" ]
then
    sudo -u tomcat kill -9 $pid
    sleep 5
fi

echo ""

cd "$GIT_CLONE"
sudo -u tomcat git pull  > /dev/null

echo "***********************************************************"
if [ $code_change_global -eq 0 ]
then
  echo ""
  echo "COMPILE AND DEPLOY CODE"
  sudo -u tomcat ant build-deploy
  success=$?
  if [ $? -eq 0 ]
  then
    echo "SUCCESSFUL"
  else
    echo "FAILED"
  fi
  echo "-----------------------------------------------------------"  
fi
if [ $configuration_change_global -eq 0 ] 
then
  echo ""
  echo "DEPLOY CONFIGURATION"
  sudo -u tomcat ant deploy-configuration
  success=$?
  if [ $? -eq 0 ]
  then
    echo "SUCCESSFUL"
  else
    echo "FAILED"
  fi
  echo "-----------------------------------------------------------"  
fi
  
echo ""   
  
#Start Tomcat  
cd "$TOMCAT/bin"  
sudo -u tomcat ./startup.sh 

Bash and zsh both have a very neat feature for expanding a single word into more: brace expansion.
For the simplest example, imagine you need to move file.old as file.new. Normally you type:

$ mv file.old file.new

Brace expansion can save you a little bit of typing:

$ mv file.{old,new}

The command actually executed will be identical to the previous one, “file.{old,new}” gets converted into “file.old file.new”.

You can also provide a number range inside the brace:

% echo test{1..13}
test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 test12 test13

With a third parameter, the number will be increased by that much each time (step):

% echo test{1..13..2}
test1 test3 test5 test7 test9 test11 test13

Only a zsh feature is padding. You can add leading zeros to generated number to make them all the same (character) size, by adding zero(s) to the third parameter:

 % echo test{1..100..010} 
test001 test011 test021 test031 test041 test051 test061 test071 test081 test091

Zsh offers even more flexibility after setting BRACE_CCL option – you can use range of characters as well:

% setopt BRACE_CCL
% echo test{a-d} 
testa testb testc testd

I needed to locate current user’s home directory, to find and parse a config file like ~/config.ini. The current user is a user that is currently running a PHP CLI script. I have found a neat solution in drush, ready to copy & paste into your function:

  // getenv('HOME') isn't set on windows and generates a Notice.
  $home = getenv('HOME');
  if (empty($home)) {
    if (!empty($_SERVER['HOMEDRIVE']) && !empty($_SERVER['HOMEPATH'])) {
      // home on windows
      $home = $_SERVER['HOMEDRIVE'] . $_SERVER['HOMEPATH'];
    }
  }
  return empty($home) ? NULL : $home;

Normally, when you want to redirect (standard) output of a script to a file, you run it with a redirection, like:

$ ./script.sh > out.log

However – you can also accomplish the same from inside the script by using exec. The following will write “Test” and then current time into /tmp/out.log”

#!/bin/bash
 
exec >/tmp/out.log
echo Test
date

You can find more information about exec on tldp.


I try to keep the same .zshrc dotfile on all the machines I use. I store the “master” copy in SVN, so any improvements I make can easily go to other computers.
However, some parts of zshrc configuration only make sense for particular machine. To keep one common master copy but also allow for some “local” configuration, you can simply use an include in your .zshrc like this:

[[ -r ~/.zsh/local.zsh ]] && . ~/.zsh/local.zsh

solr can be easily extended to handle binary files and extract the information from them. Apache Tika library is used for the file analysis.

This can be set up in solr by using Extracting Request Handler that is already set up in solrconfig.xml. All we need to do is to add extra libraries. Once you have your solr set up, copy:

  • contrib/extraction/lib/* (from the downloaded solr package) into /var/lib/tomcat6/webapps/solr/WEB-INF/lib
  • solr/apache-solr-4.0.0-BETA/dist/apache-solr-cell-4.0.0-BETA.jar into /var/lib/tomcat6/webapps/solr/WEB-INF/lib

Restart tomcat and index sample document (I’m using test.pdf that I have in the same, current directory). Handler is available at update/extract:

curl "http://localhost:8080/solr/update/extract?literal.id=doc1&commit=true" -F "myfile=@test.pdf"

I have provided an unique id for the document by passing literal.id=doc1 option, to index second document I’d use:

curl "http://localhost:8080/solr/update/extract?literal.id=doc2&commit=true" -F "myfile=@test.pdf"

That’s all – here is the result of executing “*” query:

<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">4</int><lst name="params"><str name="q">*</str><str name="wt">xml</str></lst></lst><result name="response" numFound="2" start="0"><doc><str name="id">doc1</str>
<str name="author">Tomasz Muras</str>
<str name="author_s">Tomasz Muras</str><arr name="content_type">
<str>application/pdf</str></arr>
<arr name="content">
<str>Test Test Test</str></arr>
<long name="_version_">1413927282391646208</long></doc>
<doc><str name="id">doc2</str>
<str name="author">Tomasz Muras</str>
<str name="author_s">Tomasz Muras</str>
<arr name="content_type"><str>application/pdf</str></arr>
<arr name="content"><str>Test Test Test</str></arr>
<long name="_version_">1413934423130243072</long></doc>
</result>
</response>

I had a problem when I created document/folder name in Alfresco Share that included Polish characters, e.g., ą, ę, ł, ż, ź. The Polish characters at first were rendered correctly but in the database (MySQL) they were saved wrong, which means that ? character was put instead of Polish letters. To make it more confusing the names were rendered wrong not necessary straight away but for example after server restart. Such behaviour implies that there had to be a communication issue between Alfresco and database and the data were saved using wrong encoding in the database. Alfresco application had file names saved in cache so it did not use the database to obtain their names. When server was restarted the data were read from the database and ? were shown. Unfortunately having ? characters caused problems to read for example folder content.

The solution to this issue was to change default encoding in the database to UTF-8. In MySQL it can be done in configuration file (/etc/mysql/my.cnf on Ubuntu). The following lines should be added to the appropriate sections in configuration file.

[mysqld]

...
collation-server=utf8_unicode_ci
character-set-server=utf8

[mysql]

...
default-character-set=utf8

After logging to MySQL and running status command the following information regarding encoding should be shown:

Server characterset:	utf8
Db     characterset:	utf8
Client characterset:	utf8
Conn.  characterset:	utf8

Update on 2012.09.20: updated for Solr 4.0-BETA (from ALPHA, thanks for the comment Dorthe).
Update on 2013.07.09: updated for Solr 4.3.1
Update on 2013.07.28: the guide works with Solr 4.4, Ubuntu server 13.04 and tomcat7, just replace tomcat6 with tomcat7 and /var/lib/tomcat6/shared with /var/lib/tomcat7/lib

This short guide will describe how to install solr 4 on Ubuntu server. The versions I’m using are: Ubuntu Server 12.04 and Apache Solr 4.3.1. I will also show how to test the installation & perform a sample indexing and query.

Installation on tomcat Ubuntu 12.04 LTS

1. Install packages

  
 apt-get install tomcat6 curl

2. Download solr 4 from http://lucene.apache.org/solr (at the time of writing it was solr-4.3.1.tgz)
3. Choose directory for solr – know as SOLR_HOME. I’ve chosen to put it into /opt/solr so my SOLR_HOME=/opt/solr. Replace /opt/solr with your own location if you want a different one.
4. Extract downloaded files anywhere and copy following to your $SOLR_HOME and to your tomcat installation:

  • copy example/solr/* to /opt/solr
  • copy example/webapps/solr.war to /opt/solr
  • copy example/lib/ext/* to /var/lib/tomcat6/shared

5. Edit dataDir in solr configuration file /opt/solr/collection1/conf/solrconfig.xml:

  
<dataDir>${solr.data.dir:/opt/solr/data}</dataDir>

6. Create directory for solr data and make it write-able for tomcat server

  
% mkdir /opt/solr/data
% sudo chown tomcat6 /opt/solr/data

Here is how my /opt/solr directory looks like (showing only directories):

 
$ tree -d
├── bin
├── collection1
│   └── conf
│       ├── lang
│       ├── velocity
│       └── xslt
└── data

7. Setup new context in tomcat server pointing to our solr files. Create file /etc/tomcat6/Catalina/localhost/solr.xml with the following content:

  
<?xml version="1.0" encoding="utf-8"?>
<Context docBase="/opt/solr/solr.war" debug="0" crossContext="true">
  <Environment name="solr/home" type="java.lang.String" value="/opt/solr" override="true"/>
</Context>

8. Restart tomcat

  
/etc/init.d/tomcat6 restart

9. Enjoy your newly set up solr4 by pointing your browser to http://localhost:8080/solr.

Sample indexing and UTF-8 test

solr installation files come with sample schema.xml (we’ve already copied it into our $SOLR_HOME) and some .xml files with sample data we can import. We will use one of them to test if UTF-8 encoding is working as expected.
1. Go to the directory with extracted solr installation files and import utf8-example.xml using curl

  
URL=http://localhost:8080/solr/update
curl $URL --data-binary @example/exampledocs/utf8-example.xml -H 'Content-type:application/xml'

The response from the server should be similar to

  
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">22</int></lst>
</response>
</xml>

2. Commit the documents

  
curl "$URL?softCommit=true"

3. Test it by searching for êâîôû string. Use solr administrative UI or this GET request should do: http://localhost:8080/solr/collection1/select?q=êâîôû. You should see exactly one result.


Introduction

This post describes how to debug JavaScript in Alfresco/Share.

There are two types of js files used in Alfresco/Share:

  • client side – they are placed in Share root directory
  • server side – they are placed in the path within WEB-INF/alfresco directory in Share and Alfresco and are used for example for by web scripts

Client side

Share Debugger

To debug JavaScript on client side client-debug and client-debug-autologging flags in Share configuration file share/WEB-INF/classes/alfresco/share-config.xml can be set to true as presented below. That allows to use JavaScript debugger after pressing (Ctrl, Ctrl, Shift, Shift). Setting client-debug to true causes using original *.js files instead of their minimised versions *-min.js. Setting client-debug-autologging to true enables the JavaScript debugger console.

  <flags>
         <!--
            Developer debugging setting to turn on DEBUG mode for client scripts in the browser
         -->
         <client-debug>true</client-debug>
         <!--
            LOGGING can always be toggled at runtime when in DEBUG mode (Ctrl, Ctrl, Shift, Shift).
            This flag automatically activates logging on page load.
         -->
         <client-debug-autologging>true</client-debug-autologging>
      </flags>

Web Browser Debugger

Apart from that standard tools provided by web browsers can be used. They are really great and include:

  • Web Console (Tools -> Web Developer) in Firefox
  • Developer Tools (Tools) in Chrome

Server side

Log file

It is not so straight forward to debug server side script in Alfresco. Therefore there is logging class that saves the logging messages from JavaScript to standard log files/output. To see those change logging level for org.alfresco.repo.jscript.ScriptLogger class to DEBUG. Corresponding line of WEB-INF/classes/log4j.properties file is presented below:

log4j.logger.org.alfresco.repo.jscript.ScriptLogger=DEBUG

Then you can use the following command in your JavaScript to log the messages:

 logger.log("Log me");

Alfresco/Share Debuger

You can also activate server side JavasScript debugger to assist your development. To do so use the following links and enable debugger there:

  • Share: share/service/api/javascript/debugger
  • Alfresco: alfresco/service/api/javascript/debugger

Make sure that that the following lines is set to “on” in WEB-INF/classes/log4j.properties

log4j.logger.org.springframework.extensions.webscripts.ScriptDebugger=ON
log4j.logger.org.alfresco.repo.web.scripts.AlfrescoRhinoScriptDebugger=ON

Normally authentication is handled by Symfony nearly automatically – you just need to define and configure your firewalls. Sometimes, however you may want to perform authentication manually from the controller.
Imagine implementing automated login for a user upon visiting a URL like: /autologin/{secret}. I am not considering here the security of such a solution – you are discourage to do it this way, unless the information available for this kind of “logins” is not confidential.

Here is a fragment from my security.yml:

security:
    firewalls:
        secured_area:
            pattern:    ^/
            form_login:
                check_path: /login_check
                login_path: /login

The actual authentication is very straight-forward. Since I’m redirecting at the end of request, I don’t even need the user to be authenticated in this action. All that is needed is to persist the information about authenticated user to the session. This means storing serialized class that implements TokenInterface. Normally this is done by Symfony framework in ContextListener. In my scenario I’m using form login that uses UsernamePasswordToken, so in short here is what I need to do:

  • Find user
  • Create the Token
  • Store Token in the session

Pay attention to “secured_area” string – it matches the firewall name from the security.yml and is used to create the token and when creating a session key.

 /**
     * @Route("/autologin/{secret}")
     */
    public function autologinAction($secret) {
        $em = $this->getDoctrine()->getEntityManager();
        $repository = $em->getRepository('MiedzywodzieClientBundle:Reservation');
        $result = $repository->matchLoginKey($secret);
        if (!$result) {
            return $this->render('MiedzywodzieClientBundle:Default:autologin_incorrect.html.twig');
        }
        $result = $result[0]; 
 
        $token = new UsernamePasswordToken($result, $result->getPassword(), 'secured_area', $result->getRoles());
 
        $request = $this->getRequest();
        $session = $request->getSession();
        $session->set('_security_secured_area',  serialize($token));
 
        $router = $this->get('router');
        $url = $router->generate('miedzywodzie_client_default_dashboard');
 
        return $this->redirect($url);
    }