Wednesday, June 30, 2010

Use cases for Alfresco.

This is a description of the general use cases for Alfresco as I see them. The audience for this document consists of IT/technical experts in a group focused on Java development. This is relevant to Alfresco version 3.

This is how I think about Alfresco: web client vs share interface vs web project vs external project.

Thank you to Jeff Potts - author of the Alfresco Developer Guide for reviewing this description and adding detail.

  1. Alfresco Web Client is a highly customizable administration front end for Alfresco. The focus of this interface is document management (Alfresco objects are documents with added meta-data) and administration (of users/groups/directories/rules/workflows etc).
  2. Alfresco Share interface is a much more customizable and user friendly Portal-like interface composed of Pages and Dashboards: we can create custom Dashlets (similar to portlets) that show up on the Dashboards. The user can add or remove dashlets. Site owners can add or remove pages. The focus of the Share interface is primarily team collaboration using tools such as a Document Library, Blogs, Wiki, Bookmarks, and a Team Calendar. With Share, users can provision their own team - or project - focused sites without the need for IT involvement.
  3. Alfresco Web Projects are specialized folders with the Alfresco Web Client used to implement Web Content Management (WCM) functionality. Web Projects can contain any type of web assets. For example, we could create a Java web app of our own using any Java framework we want (Spring, Seam, Surf etc) and manage it via Alfresco WCM. The focus of this mechanism is developer created front ends (web sites) that are managed by Alfresco: we write web apps that do whatever we want and look however we want them to look and are versioned with and deployed by Alfresco tools. The web apps can optionally manipulate Alfresco objects in the back end.
  4. An external project is any other sort of web application that makes use of the same remote APIs that the first 3 do, but is not managed by Alfresco. The focus of this mechanism is to allow any sort of front end (including Joomla) to use Alfresco as a back-end repository. Think of Alfresco as a database for rich or semi-structured content.

The real power of Alfresco is two fold: it allows it's own interfaces (point 1 and 2) to be customised using XML and Java and; it provides a number of remote APIs (such as Web Services, both SOAP and RESTful) so that any sort of project can be a client to Alfresco (point 3 and 4). Additionally, Alfresco provides functionality specific to managing rich content, such as:

  • Full-text and metadata search (powered by Lucene).
  • Extensible content model.
  • Check-in/check-out.
  • Workflow (powered by JBoss jBPM).
  • Numerous options for getting content into the repository (CIFS, WebDAV, FTP, SMTP, IMAP).

Recommended use of Alfresco for an IT development company with Java developers skilled in Alfresco: keep it Java, but be aware that other technologies can be an Alfresco client too. Use the Web Client (point 1) and Share (point 2) interfaces for inward facing administration and collaboration respectively and a Web Project (point 3) for any web site that could benefit from WCM-specific functionality such as Sandboxes, Deployment, or (light) Structured XML Authoring. Use 4) when we come across a client crawling across the desert in search of a document management tool and literally cannot move off away from the rest of their stack or when the amount of customization necessary to the out-of-the-box Alfresco clients is such that building a custom UI on top of Alfresco would be faster, easier to maintain, or a better fit.

Monday, June 28, 2010

Script to backup directories on a regular basis v2 - with ZIPs

Update: Monday 21 May 2012, 02:30:59 PM. Added use of invisible script to hide DOS box from scheduled invocation.

Update: Monday 12 September 2011, 07:53:04 PM. Re-wrote use of FORFILES to use / switches. Included %ZIP% variable to avoid relying on 7z being in the path. Also added Pro Tip for changing paths depending on the environment.

Version 4 of my Script to backup directories on a regular basis, this one backs up the directories as ZIP files. The first version worked just by copying directories. The reason I didn't go straight to ZIP in the first place is that on Windows, there is no built in ZIP functionality suited to the purpose: Windows compress command isn't a real zip replacement; WinZip isn't free; and I wanted batch script rather than a bash script (though I still love Cygwin). So this one uses 7-zip, a FREE and open source alternative to WinZip. Version 4 adds invisibleness! The scheduler uses a vbs script so that each time Windows Scheduler invokes this script, you don't get a DOS box popping up.

The script below has two functions. The first is to backup a set of directories and delete old backups. You edit the script to define what directories it backs up, which directory they get backed up to and how long backups should be kept for. The second function is to schedule the script so that it will be called every few hours. You edit the script to define how often it should be called.

This is a Windows DOS Batch script. I have only tested it on Windows 7. It has two dependencies. The first is forfiles.exe which should be native to Windows 7, since XP. If you haven't got it, get it from the magnificent site: An A-Z Index of the Windows XP command line. Make sure to put it in the path before running this script. The second dependency is 7-zip, a FREE and open source alternative to WinZip. Download and install it, then edit the ZIP variable in the script if 7z wasn't installed here: C:\Program Files\7-Zip\7z.exe. Notes about running the script itself appear below the script.

@ECHO OFF

REM Directory backup utility.
REM http://robertmarkbramprogrammer.blogspot.com.au/2010/06/script-to-backup-directories-on-regular_28.html
REM    - v1. Written by Robert Mark Bram, 23/06/2010 5:10:55 PM.
REM    - v2. Robert Mark Bram, 28/06/2010 6:03:28 PM: modified to backup
REM       directories to zip files instead of backing by copying directories.
REM    - v3. Robert Mark Bram, Monday 12 September 2011, 07:34:52 PM
REM       modified the way FORFILES is called to use / switches.
REM       Plus, added ZIP variable instead of relying on it being in the PATH.
REM    - v4. Robert Mark Bram, Saturday 19 May 2012, 11:43:42 AM
REM       integrated invisible.vbs to hide DOS box.
REM - Tested on Win 7 and XP 64 bit.
REM - Dependency: invisible.vbs - small script that lets this batch file be run
REM    without popping up a DOS box. Is used when you schedule this batch.
REM    Put invisible.vbs in the same folder as this batch file.
REM    http://dl.dropbox.com/u/60106937/invisible.vbs
REM - Dependency: forfiles.exe - Windows 7/XP-bit and later should have the
REM    FORFILES command by default. For earlier Windows builds, get it from:
REM      http://ss64.com/nt/forfiles.html
REM    and make sure to put forfiles.exe in the PATH (e.g. C:\WINDOWS\system32\
REM    for Windows XP).
REM - Dependency: 7zip, a FREE and open source alternative to WinZip - get it
REM    from here: http://www.7-zip.org and edit the ZIP variable below if the
REM    path is NOT C:\Program Files\7-Zip\7z.exe.

REM BACKUP AND DELETE OLD BACKUPS
REM Run this script without arguments and it will backup selected directories to
REM a backup directory and delete old backup directories.

REM SCHEDULE BACKUP TASKS
REM Run this script with argument "sched" and it will schedule this script to run
REM every few hours. You will need to enter your Windows password.
REM For example:
REM    D:\work\MyProject>backupDataHourly.bat sched
REM    Scheduling task.
REM    The task will be created under current logged-on user name ("SPIKE\Robert Bram").
REM    Please enter the run as password for SPIKE\Robert Bram: **************
::
REM    SUCCESS: The scheduled task "Backup data hourly" has successfully been created.
REM    D:\work\MyProject>


REM =======================================
REM EDIT THIS SECTION.
REM =======================================
REM Where is 7zip installed to?
SET ZIP="C:\Program Files\7-Zip\7z.exe"

REM Where do you want to put the backup files?
SET BACKUP_HOME=D:\files\backups

REM How long (days) do you want to keep them?
SET DAYS_B4_DELETE=10

REM Define path and label (no spaces) for each directory you want to backup.
SET DIR1="D:\work\MyProjects\FirstProject"
SET LBL1=FIRST_PROJ
SET DIR2="D:\work\MyProjects\SecondProject"
SET LBL2=SECOND_PROJ

REM How many dir/lbl combinations did you define?
SET MAX=2

REM How often (in hours) do you want to run this script?
SET HOURS=1

REM What name to give the scheduled task.
SET SCHED_TASK_LABEL=Backup data hourly

REM =======================================
REM DON'T CHANGE BELOW THIS POINT unless you know what you are doing!
REM =======================================

REM Directory Checks
IF "%BACKUP_HOME%" == "" (
   echo Warning: BACKUP_HOME has not been set.
   GOTO END
)
IF NOT EXIST "%BACKUP_HOME%"  (
   echo Warning: BACKUP_HOME [%BACKUP_HOME%] does not exist.
   GOTO END
)

REM Are we scheduling or backing up?
IF "%1" == "sched" GOTO :SCHEDULE
GOTO :BACKUP

REM Schedule this script to run regularly - user will have to enter password.
:SCHEDULE
echo Scheduling task: %0.
REM Schedule task.
schtasks /create /SC HOURLY /MO %HOURS% /tn "%SCHED_TASK_LABEL%" /tr "wscript.exe %~dp0invisible.vbs %0"
GOTO :END

REM Run backup tasks.
:BACKUP
echo Backing up files.

REM Create timestamp.
SET hh=%time:~0,2%
if "%time:~0,1%"==" " SET hh=0%hh:~1,1%
SET YYYYMMDD_HHMMSS=%date:~10,4%%date:~7,2%%date:~4,2%_%hh%%time:~3,2%%time:~6,2%

REM Backup selected paths.
SetLocal EnableDelayedExpansion
For /L %%i in (1,1,%MAX%) Do (
   IF EXIST !DIR%%i! (
      %ZIP% a -tzip -r "%BACKUP_HOME%\!LBL%%i!_%YYYYMMDD_HHMMSS%.zip" !DIR%%i!
   )
)
EndLocal


REM Delete old backups.
echo Deleting old files.
IF "%DAYS_B4_DELETE%" == "" (
   echo WARNING! DAYS_B4_DELETE not set. Not deleting old backups.
   GOTO :END
)

REM SetLocal EnableDelayedExpansion
SetLocal EnableDelayedExpansion
For /L %%i in (1,1,%MAX%) Do (
   FORFILES /P "%BACKUP_HOME%" /M !LBL%%i!_*.zip /D -%DAYS_B4_DELETE% ^
      /C "CMD /C del /F /Q @FILE & echo Deleted @FILE "
)
EndLocal

REM Use this for testing - echo what files will be deleted.
REM SetLocal EnableDelayedExpansion
REM For /L %%i in (1,1,%MAX%) Do (
REM    FORFILES /P "%BACKUP_HOME%" /M !LBL%%i!_*.zip /D -%DAYS_B4_DELETE% ^
REM       /C "CMD /C echo @FILE will be deleted"
REM )
REM EndLocal

:END

REM Uncomment the "pause" line if you want the command window to stick around
REM until you "Press any key to continue . . ."
REM (Let's you see the output of every run.)
REM pause


You can run the script just by double clicking it or running it on the command line without any parameters, but the intention is that you schedule the script to run every few hours.

You can get invisible.vbs from my Dropbox. It's just a one line script however, so you can just as easily save it to a file yourself from this: CreateObject("Wscript.Shell").Run """" & WScript.Arguments(0) & """", 0, False. Save it to the same directory as the backup script itself (also available from my Dropbox).

Save the backup and invisible script somewhere and edit the variables in the section labelled EDIT THIS SECTION. Make sure to give values to the variables there:

  • ZIP - location where 7z is installed, C:\Program Files\7-Zip\7z.exe by default.
  • BACKUP_HOME - where to store the backups.
  • DAYS_B4_DELETE - how many days backups should be kept before deleting them.
  • DIRX and LBLX - a directory and label combination for each directory you want to back up. For example, DIR1="D:\work\MyProjects\FirstProject" and LBL1=FIRST_PROJECT will result in a backup ZIP being created such as FIRST_PROJECT_20100624_004014.zip - the label plus a time stamp.
  • MAX - how many DIRX and LBLX combinations you have (needed for loop control).
  • HOURS - how often to run the script (in hours).
  • SCHED_TASK_LABEL - what to call the task in the Scheduled Tasks applet.

Once you have edited the values, you can just run the script to create the backups - or you can run the script to schedule backups by running it with the parameter “sched”. You will have to enter your login password. Here is an example:

D:\work\MyProjects>backupDataHourly.bat sched
Scheduling task.
The task will be created under current logged-on user name ("SPIKE\Robert Bram").
Please enter the run as password for SPIKE\Robert Bram: **************

SUCCESS: The scheduled task "Backup data hourly" has successfully been created.
D:\work\MyProjects>

Pro Tip: Change Configuration per Environment

Pro Tip. I like to run my own personal source control system and check my important scripts into it. If possible, I like to set up my various computers such that the same script will run equally everywhere. The biggest road-block for having this work is paths: no matter how much I try, I always end up with different paths on my different machines. No matter, for this script, you can set different paths depending on what machine you are running on! Do it with code like that shown below.


SET ZIP="C:\Program Files\7-Zip\7z.exe"

REM My Workplace
if "%computername%" == "WORKLAPTOP" (

   REM Where do you want to put the backup files?
   SET BACKUP_HOME=D:\files\backups

   REM How long (days) do you want to keep them?
   SET DAYS_B4_DELETE=10

   REM Define path and label (no spaces) for each directory you want to backup.
   SET DIR1="D:\work\MyProjects\FirstProject"
   SET LBL1=FIRST_PROJ
   SET DIR2="D:\work\MyProjects\SecondProject"
   SET LBL2=SECOND_PROJ

   REM How many dir/lbl combinations did you define?
   SET MAX=2

   REM How often (in hours) do you want to run this script?
   SET HOURS=1

   REM What name to give the scheduled task.
   SET SCHED_TASK_LABEL=Backup data hourly

) else if "%computername%" == "HOMEPC" (

   REM Where do you want to put the backup files?
   SET BACKUP_HOME=C:\files\backups

   REM How long (days) do you want to keep them?
   SET DAYS_B4_DELETE=10

   REM Define path and label (no spaces) for each directory you want to backup.
   SET DIR1="C:\work\MyProjects\ThirdProject"
   SET LBL1=THIRD_PROJ
   SET DIR2="C:\work\MyProjects\FourthProject"
   SET LBL2=FOURTH_PROJ

   REM How many dir/lbl combinations did you define?
   SET MAX=2

   REM How often (in hours) do you want to run this script?
   SET HOURS=1

   REM What name to give the scheduled task.
   SET SCHED_TASK_LABEL=Backup data hourly
)

In this example, I have all the same paths, except that on my work machine everything is in D:, but in C: at home! Also, when I am at home, I work on different projects - I don't want to back up work projects, so I change what projects (path and label pairs) are targeted. Find out %computername% simply by opening up a DOS command shell and typing echo %computername%

So now I am sure I has backups!

 

Thursday, June 24, 2010

Script to backup directories on a regular basis

Update 28/06/2010 6:30:58 PM. This script works by copying directories. version 2 of this script backs up directories as ZIP files.

I have had many issues with backups. Let me re-phrase: I have had many issues with “Oh, what? I did WHAT? To all of them? How did that happen?” No more, I say! And this script is how I intend on making sure I has backups. I use it to make copies of each project directory I am actively working on right now.

The script below has two functions. The first is to backup a set of directories and delete old backups. You edit the script to define what directories it backs up, which directory they get backed up to and how long backups should be kept for. The second function is to schedule the script so that it will be called every few hours. You edit the script to define how often it should be called.

This is a Windows DOS Batch script. I have only tested it on Windows XP. It has one dependency, forfiles.exe which you can get from the magnificent site: An A-Z Index of the Windows XP command line. Make sure to put it in the path before running this script. Notes about running the script itself appear below the script.

@ECHO OFF

REM Directory backup utility.
REM - Written by Robert Mark Bram, 23/06/2010 5:10:55 PM.
REM - Tested on Win XP only.
REM - Dependency: forfiles.exe - get it from: http://ss64.com/nt/forfiles.html
REM    and make sure to put forfiles.exe in the PATH (e.g. C:\WINDOWS\system32\
REM    for Windows XP).

REM BACKUP AND DELETE OLD BACKUPS
REM Run this script without arguments and it will backup selected directories to
REM a backup directory and delete old backup directories.

REM SCHEDULE BACKUP TASKS
REM Run this script with argument "sched" and it will schedule this script to run
REM every few hours. You will need to enter your Windows password. For example:
REM    D:\work\MyProjects>backupDataHourly.bat sched
REM    Scheduling task.
REM    The task will be created under current logged-on user name ("SPIKE\Robert Bram").
REM    Please enter the run as password for SPIKE\Robert Bram: **************
REM
REM    SUCCESS: The scheduled task "Backup data hourly" has successfully been created.
REM    D:\work\MyProjects>
REM =======================================
REM EDIT THIS SECTION.
REM =======================================
REM Where do you want to put the backup files?
SET BACKUP_HOME=D:\files\backups

REM How long (days) do you want to keep them?
SET DAYS_B4_DELETE=10

REM Define path and label (no spaces) for each directory you want to backup.
SET DIR1="D:\work\MyProjects\FirstProject"
SET LBL1=FIRST_PROJ
SET DIR2="D:\work\MyProjects\SecondProject"
SET LBL2=SECOND_PROJ

REM How many dir/lbl combinations did you define?
SET MAX=2

REM How often (in hours) do you want to run this script?
SET HOURS=1

REM What name to give the scheduled task.
SET SCHED_TASK_LABEL=Backup data hourly



REM =======================================
REM DON'T CHANGE BELOW THIS POINT unless you know what you are doing!
REM =======================================

REM Directory Checks
IF "%BACKUP_HOME%" == "" (
   echo Warning: BACKUP_HOME has not been set.
   GOTO END
)
IF NOT EXIST "%BACKUP_HOME%"  (
   mkdir %BACKUP_HOME%
)
IF NOT EXIST "%BACKUP_HOME%"  (
   echo Warning: BACKUP_HOME [%BACKUP_HOME%] does not exist.
   GOTO END
)

REM Are we scheduling or backing up?
IF "%1" == "sched" GOTO :SCHEDULE
GOTO :BACKUP

REM Schedule this script to run regularly - user will have to enter password.
:SCHEDULE
echo Scheduling task.
schtasks /create /sc hourly /mo %HOURS% /tn "%SCHED_TASK_LABEL%" /tr %~dps0\%0
GOTO :END

REM Run backup tasks.
:BACKUP
echo Backing up files.

REM Create timestamp.
SET hh=%time:~0,2%
if "%time:~0,1%"==" " SET hh=0%hh:~1,1%
SET YYYYMMDD_HHMMSS=%date:~10,4%%date:~7,2%%date:~4,2%_%hh%%time:~3,2%%time:~6,2%

REM Backup selected paths.
SetLocal EnableDelayedExpansion
For /L %%i in (1,1,%MAX%) Do IF EXIST !DIR%%i! xcopy !DIR%%i! ^
   "%BACKUP_HOME%\!LBL%%i!_%YYYYMMDD_HHMMSS%" /D /E /C /I /H /R /Y
EndLocal

REM Delete old backups.
echo Deleting old files.
IF "%DAYS_B4_DELETE%" == "" (
   echo WARNING! DAYS_B4_DELETE not set. Not deleting old backups.
   GOTO :END
)

SetLocal EnableDelayedExpansion
For /L %%i in (1,1,%MAX%) Do (
   FORFILES -p"%BACKUP_HOME%" -m!LBL%%i!_* -d-%DAYS_B4_DELETE% ^
      -c"CMD /c rmdir /S /Q @FILE & echo @FILE will be deleted"
)
EndLocal

REM Use this for testing - echo what files will be deleted.
REM SetLocal EnableDelayedExpansion
REM For /L %%i in (1,1,%MAX%) Do (
REM    FORFILES -p"%BACKUP_HOME%" -m!LBL%%i!_* -d-%DAYS_B4_DELETE% ^
REM       -c"CMD /c echo @FILE will be deleted"
REM )
REM EndLocal

:END

REM Uncomment the "pause" line if you want the command window to stick around
REM until you "Press any key to continue . . ."
REM (Let's you see the output of every run.)
REM pause

You can run the script just by double clicking it or running it on the command line without any parameters, but the intention is that you schedule the script to run every few hours.

Save the script somewhere and edit the variables in the section labelled EDIT THIS SECTION. Make sure to give values to the variables there:

  • BACKUP_HOME - where to store the backups.
  • DAYS_B4_DELETE - how many days backups should be kept before deleting them.
  • DIRX and LBLX - a directory and label combination for each directory you want to back up. For example, DIR1="D:\work\MyProjects\FirstProject" and LBL1=FIRST_PROJECT will result in a backup directory being created such as FIRST_PROJECT_20100624_004014 - the label plus a time stamp.
  • MAX - how many DIRX and LBLX combinations you have (needed for loop control).
  • HOURS - how often to run the script (in hours).
  • SCHED_TASK_LABEL - what to call the task in the Scheduled Tasks applet.

Once you have edited the values, you can just run the script to create the backups - or you can run the script schedule backups by running it with the parameter “sched”. You will have to enter your login password. Here is an example:

D:\work\MyProjects>backupDataHourly.bat sched
Scheduling task.
The task will be created under current logged-on user name ("SPIKE\Robert Bram").
Please enter the run as password for SPIKE\Robert Bram: **************

SUCCESS: The scheduled task "Backup data hourly" has successfully been created.
D:\work\MyProjects>

So now I am sure I has backups!

 

Tuesday, June 08, 2010

Notes on Alfresco Developer Guide by Jeff Potts

I am maintaining a set of set of notes on the excellent book Alfresco Developer Guide by Jeff Potts.

1st Edition, 2008. Published by Packt. ISBN: 978-1-847193-11-7

Tutorial code for the book: http://ecmarchitect.com/archives/2009/07/30/1023.

Monday, June 07, 2010

Unlocking files the easy way

Often the clean task in an Ant build will fail due to an error like below.

BUILD FAILED
D:\my\project\build.xml:58: Unable to delete file D:\my\project\build\someFile.txt

It can mean that you don't have write permissions on the file or parent folder. However, more often I find it is because some process has locked the file: perhaps an indexing process like Google Desktop Search or Windows Search, or maybe a Virus Scanner. If you know what process it is, you can kill it through Task Manager, but that's fiddly, especially if it keeps happening. Worse, I usually want the culprit process to continue doing it's job i.e. I don't want to kill it.

My solution begins with using Unlocker (Windows XP) to tell me what processes have locked a file: right click on any file, select Unlocker and see a list of the offending processes. You can choose to kill any of the processes or request that they unlock the file you need access to.

This is great, but awkward if I don't immediately have Explorer open to the directory involved. If this has come about because of a failed Ant build, I will have the path in my console, but then I have to copy the path from the console and paste it into Explorer (after fixing any line wrapping in a text editor). This would be much easier if I had the Ant output in a text file already. By default, I always run Ant tasks by re-directing their output to a temporary file which gets opened in my text editor. For example (in Cygwin):

ant -p > temp.txt ; notepad temp.txt &

I have a script that does this (of course). It means I will always have the offending path in a text document. Next step: the unbelievably amazing AutoHotkey, a Windows scripting engine that lets you assign keyboard shortcuts to scripted functionality. This script invokes Unlocker - on whatever path I currently have selected when I press ctrl+win+u.

; - Unlock X by Copying Text (control+windows key + u)
^#u::
   Send, {CTRLDOWN}c{CTRLUP}
   Run C:\Program Files\Unlocker\unlocker.exe %clipboard%
return

This is just one AutoHokey function I have defined in a single "utilities" AutoHotkey script that gets loaded through my Windows Startup directory so that it is always available. For others, check out this SuperUser post: Most useful AutoHotkey scripts?

To summarise: Ant outputs to a text file, Unlocker can unlock files by absolute path, Autohotkey copies currently selected text (should be a file path) and invokes Unlocker, sending the path as an argument.

Quick and simple log filter

When I am developing locally, I frequently need to search through my local logs. There are already many useful tools already for this: UltraEdit has a great feature that shows all the lines matching your search term; so does Apache Chainsaw. But I want something even quicker, so I wrote a script. :)

This script relies on grep and Cygwin, and is actually a DOS batch file.

@echo off
REM Variables you probably should customize
SET DEFAULT_SEARCH_TERM=someco
SET LOG=%D:\apps\Alfresco-Community-3.3\alfresco.log%
SET EDITOR=C:\Program Files\IDM Computer Solutions\UltraEdit\Uedit32.exe
SET OUTPUT_FILE=C:\Temp\someco.log
SET GREP=C:\cygwin\bin\grep.exe

SET SEARCH_TERM=%1
IF NOT DEFINED SEARCH_TERM SET SEARCH_TERM=%DEFAULT_SEARCH_TERM%
"%GREP%" %2 %3 %4 %5 %6 %7 %8 %9 "%SEARCH_TERM%" "%LOG%" > "%OUTPUT_FILE%"
"%EDITOR%" "%OUTPUT_FILE%"

To use it, save it somewhere and at the very least, edit the variables to reflect whatever you want the default search term to be (DEFAULT_SEARCH_TERM), the path to your log file (LOG) and the path to your text editor (EDITOR). If you run it without any arguments, it will search through your log for the default search term, output the results into a file and open the file in your favourite text editor. Override the search term by giving the script a (quoted) argument.

And for those of you who run the magnificent Launchy, it is even simpler. Save the script into a directory that Launchy is indexing (for *.bat files). Then in Launchy, type the script's name hit TAB, type the quoted search term and the script will run with your search term.

The unquoted positional arguments (%2 %3 %4 %5 %6 %7 %8 %9) mean you can put arguments to grep after the search term when you execute the script, as long you ensure the search term is quoted if it contains spaces. So I can search for "SOMECO" in a case insensitive manner by invoking the script with arguments: "SOMECO" -i.

Sunday, June 06, 2010

Resetting a local Alfresco installation

Alfresco-Community-3.3 includes a couple of batch files to reset a local Alfresco installation by dropping the database, deleting the data directory and then recreating them. The scripts in question are:
<ALFRESCO INSTALL DIR>\extras\databases\mysql\db_remove.bat
<ALFRESCO INSTALL DIR>\extras\databases\mysql\db_setup.bat
The data directory that db_remove.bat removes is <ALFRESCO INSTALL DIR>/alf_data. Thing is, the scripts don’t work. Original scripts are below.

Tear down script.
:: db_remove.bat
@echo off
rem ---------------------------------------
rem MySQL remove DB command
rem ---------------------------------------

echo Deleting Alfresco database and user...
mysql -u root -p < db_remove.sql

echo Deleting indexes...
del /s /q "../../../alf_data"
Set-up script.
:: db_setup.bat
@echo off
rem ---------------------------------------
rem MySQL create DB command
rem ---------------------------------------

echo Creating Alfresco database and user...
mysql -u root -p < db_setup.sql

echo Database prepared.
They don’t work because they assume mysql is in the PATH already. It isn’t for me and I don’t want it to be. Nor do I want to hard-code paths into these files. So, this is how I modified them:

Tear down script.
:: db_remove.bat
@echo off
rem ---------------------------------------
rem MySQL remove DB command
rem ---------------------------------------

set SCRIPT_HOME=%~dps0
cd ..\..\..\mysql\bin

echo Deleting Alfresco database and user...
mysql -u root -p < %SCRIPT_HOME%\db_remove.sql

echo Deleting indexes...
del /s /q "../alf_data"
Set up script.
:: db_setup.bat
@echo off
rem ---------------------------------------
rem MySQL create DB command
rem ---------------------------------------

set SCRIPT_HOME=%~dps0
cd ..\..\..\mysql\bin

echo Creating Alfresco database and user...
mysql -u root -p < %SCRIPT_HOME%\db_setup.sql

echo Database prepared.
Warning: by themselves, these two scripts still aren’t enough to fully reset an Alfresco install. You should also empty out the alfresco webapp of any customisations you have made: <ALFRESCO INSTALL DIR>\tomcat\webapps\alfresco. I am not sure of any really good way to do this yet, other using a backup of that directory, created before you started adding customisations to it.
Also posted this on the Alfresco forum: Scripts to reset Alfresco installation

Learn to use UltraEdit's Function List

UltraEdit's (v16) function list allows you modify the regular expressions used for different document types to pick out and display important aspects of a document in the function list. For example, the Function List (F8) will show methods, variables and imports a Java source file; in an XML file, it will show any tag with name=" in it. Click on any entry in the function list and it will take you there. Not as good as an IDE (e.g. Eclipse, NetBeans) that also has context menus with options relevant to the semantics of each element, but extremely useful for general purpose editing.

Still, the true power of the Function List is that you can edit the settings that define what is shown - including changing the built-ins and adding your own. By default, UltraEdit's XML function definitions (UltraEdit calls them "groups") only shows XML elements with a NAME attribute, and it displays the whole tag in the function list, including the angle brackets < > and space that appears before the tag.


(Click to enlarge.)

I want to see elements with NAME or ID attributes and I wanted to tidy up the display so as not to see leading space or the angle brackets or the contents of the tag if it fits on one line. Here is what I see now:


(Click to enlarge.)

It's easy to do. Right click on the Function List, select Configuration and modify as below.


(Click to enlarge.)

The configuration strings I am using above are *<^(*name=*"^)> and *<^(*id=*"^)>.

But wait - there's more! I am working with Alfresco XML documents right now and one of them contains alfresco-config elements that don't use NAME or ID. They have CONFIG elements, each of which has an EVALUATOR and CONDITION attribute that I would like to see in my XML function view, as per below.


(Click to enlarge.)

Again, it is pretty simple. Edit the groups as above and create a new group called Alfresco Config Evaluator, defined as <config evaluator=^("*^)>.


(Click to enlarge.)

There is a risk that if I edit any other XML document that has an element called CONFIG with an attribute called EVALUATOR I will see it, but I think it's a sufficiently specific rule. Also, the element called CONFIG must have an EVALUATOR attribute immediately afterwards or it won't get displayed, but I can live with that too.

Thursday, June 03, 2010

UltraEdit macro to select HTML/XML tag

Update Sunday 19 April 2015, 12:06:27 AM: this post has been superseded by a new one: UltraEdit macro to select HTML/XML tag (same name, very different content).

Editing HTML or XML in UltraEdit is now just a little bit easier for me with this macro that incrementally selects HTML/XML elements.

Thanks to Bulgrien in my UltraEdit forum post “macro to select HTML tag” the base case macro to select tag start to finish is very simple. Consider the text below. I wanted a macro to select the DIV and its contents (including the DIV tag itself).

<DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>

Here is a very simple macro that will do that.

InsertMode
ColumnModeOff
HexOff
Find Select "</^s>"
Find Up Select "<"

The ^s means “selected text”. To use this macro on the example text, double click the first DIV token and run the macro. Unfortunately, this macro is not so useful if the element contains nested elements with the same tag name, such as in the example below. If you double click on the first DIV token in the text below and run the macro, it will select only to the first DIV close (as the coloured text shows).

<DIV>
   <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
</DIV>

AFAIK UltraEdit’s macro language doesn’t have the logic structures to repeat through nested tags (recursion or looping and arithmetic) - let alone deal with broken nested tags. I could write a Javascript to do this, but I don’t want to invest the time to get it right. So my compromise is to put the decision logic in the hands of a human operator. (Probably for the best; wouldn’t want SkyNet) to start with a run-away UltraEdit macro.)

Here is the new and improved macro.

InsertMode
ColumnModeOff
HexOff
UltraEditReOn
IfSel
Find RegExp Select "</++^c>++"
Else
SelectWord
Copy
Find Select "</^c>"
Find Up Select "<"
EndIf

To use it, put the cursor in the first DIV (don’t select it or copy it) and run the macro. It will still select only to the first close tag, but each time you re-run the macro (control+m) it will expand the selection to the next tag opening or closing. This way, you can count for yourself how many nested tags there are and stop when you need to.

First run:

<DIV>
   <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
   <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
</DIV>

Second run (control+m):

<DIV>
   <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
   <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
</DIV>

Third run (control+m):

<DIV>
     <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
     <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
</DIV>

Fourth run (control+m):

<DIV>
   <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
   <DIV style="...">abc <SPAN>def</SPAN> ghi.</DIV>
</DIV>

And to do the same thing the other way, use this one.

InsertMode
ColumnModeOff
HexOff
UltraEditReOn
IfSel
Find RegExp Up Select "</++^c>++"
Else
SelectWord
Copy
Find Up Select "</^c>"
Find Select ">"
EndIf

Personally, I have the select forward macro mapped to Control+Shift+. and the select backwards macro mapped to Control+Shift+,

Notes.

  • A very simple Perl regex will do almost the same thing as Bulgrien’s macro above: <DIV[^>]*>([^ΓΏ]*?)</DIV>. Unfortunately you can’t use ^s in regular expressions though.

Wednesday, June 02, 2010

Alfresco - method createAuthentication is undefined

I am using Alfresco-Community-3.3 and am trying out the following example code from Jeff Potts book: Alfresco Developer Guide

// client-extensions/src/java/com/someco/module/BootstrapAuthorityCreator.java
// create tuser1, tuser2, tuser3, tuser4
if(!authenticationService.authenticationExists("tuser1")) {
  authenticationService.createAuthentication("tuser1", "password".toCharArray());
  if (logger.isDebugEnabled()) logger.debug("Created tuser1 auth");
}

But I get this error:

The method createAuthentication(String, char[]) is undefined for the type AuthenticationService

And indeed when I look at the javadocs for org.alfresco.service.cmr.security.AuthenticationService there is no createAuthentication() method. It seems to have been moved into org.alfresco.service.cmr.security.MutableAuthenticationService. So, I changed authenticationService into an instance of MutableAuthenticationService:

// private AuthenticationService authenticationService;
private MutableAuthenticationService authenticationService;

You also need to modify the signature of setAuthenticationService().

I posted this on the Alfresco Forums too.