Alfresco repository full text search example using CMIS webservices

It’s easily achieavable to perform a full text search on common format documents (like .doc, .pdf) stored in Alfresco repository. What’s more it’s also possible to get relevance of documents found against desired keywords.

A short example:

POST <host>/alfresco/service/cmis/queries
Content-Type:application/cmisquery+xml
Http basic auth required!
<cmis:query xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/">
1.	<cmis:statement>SELECT cmis:name, SCORE() FROM cmis:document WHERE CONTAINS('niceWord')</cmis:statement>
	<cmis:searchAllVersions>true</cmis:searchAllVersions>
        <cmis:includeAllowableActions>false</cmis:includeAllowableActions>
        <cmis:includeRelationships>none</cmis:includeRelationships>
        <cmis:renditionFilter>*</cmis:renditionFilter>
2.     	<cmis:maxItems>50</cmis:maxItems>
3.     	<cmis:skipCount>0</cmis:skipCount>
</cmis:query>

A few important details:

1. SCORE() returns relevance of document found against expression passed to CONTAINS() function. In Alfresco you can use powerful FTS language as CONTAINS() parameter but it means losing compliance with CMIS-SQL standard.

2. , 3. Paging effect. It’s recommend to always use paging because Alfresco doesn’t guarantee that it will return all entries if there is a lot of them.

And that’s all, you will receive a neat list of entries meeting your requirements.

How to upload a new file to Alfresco using web services?

There are some examples how to upload a file to alfresco using UploadContentServlet but they all show how to code it directly in Java. Documentation and forum lacks an example showing how to upload a large file using Alfresco web services. After a bit of struggle I figured it out.

Quick and dirty recipe:

  1. Perform ticket authorization
POST /alfresco/service/api/login
{
"username" : "admin",
"password" : "admin"
}

You’ll get response with ticket in it.

  1. Create a new document using CMIS services
POST /alfresco/service/cmis/i/176c5f4d-db63-49ec-9886-c19d6d9eefce/children
Content-Type:application/atom+xml;type=entry

<?xml version="1.0" encoding="utf-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/"
xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/">
<title>important document</title>
<summary>VERY important document</summary>
<content type="text/plain">
MS4gR2l0YSAKIDIuIEthcm1heW9nYSBieSBWaXZla2FuYW5k
</content>
<cmisra:object>
<cmis:properties>
<cmis:propertyId propertyDefinitionId="cmis:objectTypeId"><cmis:value>cmis:document</cmis:value></cmis:propertyId>
</cmis:properties>
</cmisra:object>
</entry>

/i/176c5f4d-db63-49ec-9886-c19d6d9eefce denotes folder to create document within.

It is also possible to refer to directories in more natural way – using names.

More info provided here:  http://wiki.alfresco.com/wiki/CMIS_Web_Scripts_Reference#Create_.2F_Move_a_Folder_or_Document_.28createDocument.2C_createFolder.2C_createPolicy.2C_moveObject.29You will get quite big chunk of xml with a lot info about newly uploaded document, among these informations you’ll find ID of the document.

3.  Overwrite the new document with your big file

PUT /alfresco/upload/workspace/SpacesStore/85c43689-4a38-4a0a-8e58-e24333ffec14/test.pdf?ticket=TICKET_fc7af4c45f138ad366dd5905aaf7a4ab8b9da268

Send file as body of request.

More info about UploadContentServlet : http://wiki.alfresco.com/wiki/URL_Addressability#UploadContentServlet

And that’s all, your file is ready in Alfresco repository!

I get NoClassDefFound for ContextLoaderListener class using Spring and Eclipse IAM Maven plugin

My most common headache during my last Spring project was:


java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

during start of Tomcat.

Every source pointed to problems with spring.jar, so I suspected having some version conflict between my Spring libraries (eg. I used also Spring-WS in an old version). But that wasn’t real cause and I’d wasted a lot of time. The real problem was faulty Eclipse IAM plugin.

Try out some tricks I’ve described in my another article : Problems using Eclipse IAM and Maven

They really may help you.

Problems using Eclipse IAM and Maven

During my last project I was involved, I used Eclipse IAM plugin for integration with Maven. It caused many problems, mainly Class not found exceptions and issues with Tomcat server.

Generally I perceived that Eclipse IAM tends to lose jars from pom.xml, what leads to unexpected, bizarre time wasting NoClassDefFoundError.

Unfortunately I hadn’t been sucessful in finding causes of my problems but I’d like to share with you my standard ‘IAM problems checklist’ 😉

If you have any problems try this (in specified order) :

  1. Use refresh, then fetch source jars option from maven menu.
  2. Try cleaning maven libraries, then do ‘1.’
  3. After doing ‘2.’, remove your app from Tomcat, clean server, then deploy again.
  4. Try removing whole server, then add it again.
  5. REMOVE AND REGENERATE WHOLE WORKSPACE

Any step mentioned above is not a joke. I had really to ‘reset’ workspace a few times to make things work again.. First three steps helped me in 80% cases.

I hope my tips will save your time.

JNA causes JVM to crash althoug I allocate memory properly

During my work with JNA I experienced a following problem:

Memory intMem = new Memory(4);  // allocating space
intMem.setInt(0, 666); // setting allocated memory to an integer
Pointer intPointer = intMem.getPointer(0);
dlllib.method1(intMem);  // OK
dlllib.method1(intPointer);  /// JVM crash !!

I can’t find the reason for such behaviour, I’ve only found out that passing Memory object (which inherits from Pointer) to Pointer parametered methods works perfectly fine. It’s rather strange that getPointer results in invalid(?) pointer but it’s just the way it is.

For more info about JNA and calling native library functions from java I recommend you to read my another article: How to call/invoke external DLL library method/function from Java code?

How to call/invoke external DLL library method/function from Java code?

Introduction

Java’s JVM allows you to do many smart things but sometimes you may be forced to directly use external library or writing code in pure java would be very time-consuming comparing it with something more low-leveled. I stumbled upon such a problem and had to use a .dll driver from a hardware provider. Of course I googled it and didn’t find much info, and what I’ve found  mostly concerned about JNI (Java Native Interface). I would like to tell you about JNA which is fast and simple to use in aforementioned task.

So, how does it work? The only thing you have to do is to download and import JNA (Java Native Access) to your project and write a simple class.
Hereunder you can analyse a simple Java program which uses a sample .dll. You can download my java code and .dll library sources later.

Java code:

package jnahelloworldtest;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Platform;
import com.sun.jna.*;

/** Simple example of native library declaration and usage. */
public class Main {
    public interface simpleDLL extends Library {
        simpleDLL INSTANCE = (simpleDLL) Native.loadLibrary(
            (Platform.isWindows() ? "simpleDLL" : "simpleDLLLinuxPort"), simpleDLL.class);
		// it's possible to check the platform on which program runs, for example purposes we assume that there's a linux port of the library (it's not attached to the downloadable project)
        byte giveVoidPtrGetChar(Pointer param); // char giveVoidPtrGetChar(void* param);
        int giveVoidPtrGetInt(Pointer param);   //int giveVoidPtrGetInt(void* param);
        int giveIntGetInt(int a);               // int giveIntGetInt(int a);
        void simpleCall();                      // void simpleCall();
    }

    public static void main(String[] args) {

        simpleDLL sdll = simpleDLL.INSTANCE;

        sdll.simpleCall();  // call of void function

        int a = 3;
        int result1 = sdll.giveIntGetInt(a);  // calling function with int parameter&result
        System.out.println("giveIntGetInt("+a+"): " + result1);

        String testStr = "ToBeOrNotToBe";
        Memory mTest = new Memory(testStr.length()+1);  // '+1' remember about extra byte for \0 character!
        mTest.setString(0, testStr);
        String testReturn = mTest.getString(0); // you can see that String got properly stored in Memory object
        System.out.println("String in Memory:"+testReturn);

        Memory intMem = new Memory(4);  // allocating space
        intMem.setInt(0, 666); // setting allocated memory to an integer
        Pointer intPointer = intMem.getPointer(0);

        int int1 = sdll.giveVoidPtrGetInt(Pointer.NULL); // passing null, getting default result
        System.out.println("giveVoidPtrGetInt(null):" + int1); // passing int stored in Memory object, getting it back
        int int2 = sdll.giveVoidPtrGetInt(intMem);
       //int int2 = sdll.giveVoidPtrGetInt(intPointer);  causes JVM crash, use memory object directly!
        System.out.println("giveVoidPtrGetInt(666):" + int2);

        byte char1 = sdll.giveVoidPtrGetChar(Pointer.NULL);  // passing null, getting default result
        byte char2 = sdll.giveVoidPtrGetChar(mTest);        // passing string stored in Memory object, getting first letter

        System.out.println("giveVoidPtrGetChar(null):" + (char)char1);
        System.out.println("giveVoidPtrGetChar('ToBeOrNotToBe'):" + (char)char2);

    }
}

Mappings table

Not every native type maps directly to Java type, furthermore a class representing pointers had to be introduced.  You can read a handy type mapping table below:

Native Type Size Java Language Type Common Windows Types
char 8-bit integer byte BYTE, TCHAR
short 16-bit short short WORD
wchar_t 16/32-bit character char WCHAR, TCHAR
int 32-bit integer int DWORD
int boolean value boolean BOOL
long 32/64-bit integer NativeLong LONG
long long, __int64 64-bit integer long
float 32-bit FP float
double 64-bit FP double
char* C string String LPTCSTR
void* pointer Pointer LPVOID, HANDLE, LPXXX

Downloads:

  • DLLVisual Studio source project – ready to use Visual Studio 2010 project. You can alter it to continue experimenting with invoking DLL methods of library attached to the Netbeans project.
  • Netbeans project – ready to use NetBeans 6 project using example code explained in this article with appropriate jars and DLL library attached
  • JNA library jars – link to official JNA libraries download page

Useful links:

DLL library C++ functions source :

#include "simpleDLL.h"

#include <stdexcept>

using namespace std;

namespace simpleDLLNS
{
    char simpleDLL::giveVoidPtrGetChar(void* param)
    {
        if(param != 0)
		{
		char* paramChrPtr = (char*)param;
		return *paramChrPtr;
		}
		else
		{
			return 'x';
		}

    }

	int simpleDLL::giveIntGetInt(int a)
	{
		return 2*a;
	}

	void simpleDLL::simpleCall(void)
	{
		int x = 3;
		return;
	}

	int simpleDLL::giveVoidPtrGetInt(void* param)
	{
		if(param!=0)
		{
			int* x = (int*)param;
			return *x;

		}
		else
		{
			return -1;
		}
	}

}

How to capture content of eclipse Console window (web tomcat application)?

The console window in eclipse has rather short ‘history’ and surprisingly the tomcat log file doesn’t appear anywhere on the hardrive when you run your application directly from eclipse. (Or it is situated in some mysterious place) It took me some time to find an option allowing to capture the content of console window to a given file.

The solution :

Run menu – > Run configurations… – ><your tomcat server > – > common – > Standard input and output

Tick the option ‘file’ and type path to your log file.

How to properly run java console application with a doubleclick (Windows)

You’ve developed a java application which runs fine in your IDE but now you want to show your application to the outer world. Running a java program by setting up windows command window and then typing java -jar myProgram.jar paramA paramB .. may be a bit confusing for an everyday user, so the simplier means to do it are quite desirable.

A simple way to achieve this is to use a batch (.bat) file.

Let’s assume you have a console java application which takes one parameter – a configuration filepath and name. You can create a simple script file which will run this application in console for you after a doubleclick.

You should:

1. Create a text file like this :

@echo off
 set jarpath="JavaApp.jar"
 java -jar %jarpath% %CD%\Config.txt
 PAUSE

%CD% is a pseudo-variable which holds the working directory. It’s useful when you eg. want to load a config file located in the same folder as your .bat file.
PAUSE displays a localized version of “Press any key to continue…” message.

2. Save it as .bat file.
3. The program is ready for double click run!