Sass::SyntaxError: File to import not found or unreadable: compass.

If you see the error

1
Sass::SyntaxError: File to import not found or unreadable: compass.

while building your theme, search to find your temp folder and empty it. In the next build, the error should be gone.

But, what is this error? The building process unzips a ruby-gems.jar in the temp dir to get some scripts for the parsing of the css files. This alone is not a problem. But if you have two liferay instances in your system, and they have two different versions of this jar, this could be a problem, because the build script will try to use the version of the other liferay instance (of an old build from the other instance).

P.S. The temp directory in a linux machine is per default the “/temp”. You can change it using

1
-Djava.io.tmpdir=/new/tmp/dir

In our case (at least in liferay 6.1) we tried to give ant this parameter but the task that does the work with ruby-gems.jar was running a new java vm and didn’t pass the temp parameter to it, so this new vm was using the machines default temp directory. Perhaps somebody could change the build.xml to use a specific temp directory.

Liferay Kaleo workflows: How to get rid of no-reply@liferay.com

When a kaleo workflow in Liferay 6.2 sends an email, it adds automatically as the sender the email no-reply@liferay.com. If you want to change that, you can’t… at least not directly through the UI of control panel.

You have to go to the workflow XML and change some things there. In the actions element, and above the notification element add a new action element like this:

1
2
3
4
5
6
7
8
9
10
11
12
<action>
    <name>setNotificationStuff onEntry</name>
    <script>

workflowContext.put(Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.CONTEXT_NOTIFICATION_SENDER_ADDRESS,­"liferay@cosmo-one.gr");  

workflowContext.put(Packages.com.liferay.portal.kernel.workflow.WorkflowConstants.CONTEXT_NOTIFICATION_S­ENDER_NAME,"DEI-DSA");

    </script>
    <script-language>javascript</script-language>
    <execution-type>onEntry</execution-type>
</action>

Add as many execution types you need.
Have a look also here.

How to lose time with something you can’t see…

While working I encounter a strange exception:

java.net.URISyntaxException: Illegal character in query at index 79: http:// ...

Strange, because there was no special character in my URL. The index 79 was here:

&v​4003=
  ^

I couldn’t figure out what the problem was… Then I decided to try something out:

System.out.println(URLEncoder.encode("v​4003=", "UTF-8"));

And the output was

v%E2%80%8B4003%3D

So, what is this %E2%80%8B? After so many years I learned for the first time that this is the zero width space character. A very devious character, really!

So, how did this character came in my URL? It was a result of (of course) a copy paste from the google docs. I was too lazy to write 4000 with the keyboard. And laziness is something that always creates strange problems.

Internal Compiler Error while building a liferay 6.1.10 plugin

The problem
I recently encounter a strange problem on a functioning project. I made a svn branch of it, and then I tried to build the branch in the same sdk, but it failed. And it failled with an internal compiler error: NullPointerException. This was very strange. The exact error was:

[javac] 1. ERROR in /XXXX/liferay-plugins-sdk-6.1.10-ee-ga1/portlets/XXXX-portlet/docroot/WEB-INF/src/XXXX/ObjectFactory.java (at line 0)
[javac]
[javac]     ^
[javac] Internal compiler error
[javac] java.lang.NullPointerException
[javac]     at org.eclipse.jdt.internal.compiler.ast.SingleTypeReference.getTypeBinding(SingleTypeReference.java:44)
[javac]     at org.eclipse.jdt.internal.compiler.ast.TypeReference.internalResolveType(TypeReference.java:130)
[javac]     at org.eclipse.jdt.internal.compiler.ast.TypeReference.resolveType(TypeReference.java:197)
[javac]     at org.eclipse.jdt.internal.compiler.ast.TypeReference.resolveType(TypeReference.java:193)
[javac]     at org.eclipse.jdt.internal.compiler.ast.Annotation.resolveType(Annotation.java:231)
[javac]     at org.eclipse.jdt.internal.compiler.ast.ASTNode.resolveAnnotations(ASTNode.java:594)
[javac]     at org.eclipse.jdt.internal.compiler.apt.dispatch.AnnotationDiscoveryVisitor.resolveAnnotations(AnnotationDiscoveryVisitor.java:143)
[javac]     at org.eclipse.jdt.internal.compiler.apt.dispatch.AnnotationDiscoveryVisitor.visit(AnnotationDiscoveryVisitor.java:131)
[javac]     at org.eclipse.jdt.internal.compiler.ast.TypeDeclaration.traverse(TypeDeclaration.java:1198)
[javac]     at org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration.traverse(CompilationUnitDeclaration.java:687)
[javac]     at org.eclipse.jdt.internal.compiler.apt.dispatch.RoundEnvImpl.(RoundEnvImpl.java:56)
[javac]     at org.eclipse.jdt.internal.compiler.apt.dispatch.BaseAnnotationProcessorManager.processAnnotations(BaseAnnotationProcessorManager.java:148)
[javac]     at org.eclipse.jdt.internal.compiler.Compiler.processAnnotations(Compiler.java:794)
[javac]     at org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:423)
[javac]     at org.eclipse.jdt.internal.compiler.batch.Main.performCompilation(Main.java:3543)
[javac]     at org.eclipse.jdt.internal.compiler.batch.Main.compile(Main.java:1645)
[javac]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[javac]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[javac]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[javac]     at java.lang.reflect.Method.invoke(Method.java:597)
[javac]     at org.eclipse.jdt.core.JDTCompilerAdapter.execute(JDTCompilerAdapter.java:79)

NullPointerException and at line 0? Where should I search…? The liferay sdk is using per default the eclipse java compiler, which is the ecj.jar included in the lib dir of the sdk directory. And it seems to be a very old version.
Even the eclipse guys didn’t know about it.

A simple update of the ecj.jar to the newest version was the solution of the problem of the compilation error.

The solution
Updating the ecj.jar in the liferay SDK includes the following steps:

  1. replace the file ecj.jar with the newest one,
  2. delete the ecj.jar from the ant lib directory,
  3. run the ant war task to copy the new ecj.jar int the ant lib directory (it will seem like an error, but it isn’t),
  4. run the ant war again to build your plugin.
But…
Although the problem is solved I am not happy. Something is still bothering me: Why did the original version of the same plugin compile without errors? It had the same code/files. If someone has an idea, please tell me.

Liferay Studio 2.2.x won’t do the update thing

If you want to try to update your Liferay Studio, you may encounter the following problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
An error occurred while collecting items to be installed
session context was:(profile=epp.package.jee, phase=org.eclipse.equinox.internal.p2.engine.phases.Collect, operand=, action=).
No repository found containing: osgi.bundle,org.eclipse.egit,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.eclipse.egit.core,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.eclipse.egit.doc,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.eclipse.egit.mylyn.ui,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.eclipse.egit.ui,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.eclipse.jgit,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.eclipse.jgit.archive,3.7.1.201504261725-r
No repository found containing: org.eclipse.update.feature,org.eclipse.egit,3.7.1.201504261725-r
No repository found containing: org.eclipse.update.feature,org.eclipse.egit.mylyn,3.7.1.201504261725-r
No repository found containing: org.eclipse.update.feature,org.eclipse.jgit,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.eclipse.jgit.java7,3.7.1.201504261725-r
No repository found containing: org.eclipse.update.feature,org.eclipse.jgit.java7,3.7.1.201504261725-r
No repository found containing: osgi.bundle,org.slf4j.impl.log4j12,1.7.2.v20131105-2200

To bypass this problem, try updating the problematic plugin with the marketplace. Search for the plugin and press the update button. This update will work.

Portlets communication on the same page in render phase.

Once again I faced the same old problem: I have one portlet A which carries a value X and 2 other portlets on the same page B and C that needs this value X on their render phase. The problem exists, because also the portlet A has this value on its render phase. So, how can you transfer the value X from the render phase of the portlet A to the render phases of the portlets B and C?

According to this wiki article we cannot use the IPC methods because we have no action phase on portlet A. So, only two options remain:

  1. portlet session
  2. cookies
Lets have a look at the portlet session and lets assume we have made all the modifications on the portlets so, that the portlet A can set the value X in the session in application scope and the portlets B and C can read it.
There is a still a (big) problem: You cannot ensure that portlets A render phase will be executed before the render phases of portlet B and C.
But this time the search on the internet was fruitful. I found out that there is an element in liferay-portlet.xml which defines the order of the render phase of the portlets on the same page. At last. And the solution was always there, in the DTD. The hint of Olaf, to read the dtds, was correct.
So, the element is
1
<render-weight>1</render-weight>

According to the documentation in the DTD (liferay 6.1):

The default value of render-weight is 1. If set to a value less than 1, the portlet is rendered in parallel. If set to a value of 1 or greater, then the portlet is rendered serially. Portlets with a greater render weight have greater priority and will be rendered before portlets with a lower render weight. If the ajaxable value is set to false, then render-weight is always set to 1 if it is set to a value less than 1. This means ajaxable can override render-weight if ajaxable is set to false.

So, setting those element value to 3 for portlet A and to 2 for the portlets B and C will ensure that A will execute its render method before the other two portlets.

JCaptcha in Liferay (multiple instances per page)

Liferay supports simpleCaptcha and reCaptcha by default. The problem is that if you want more instances of a captcha in one page (say, you have a complicated registration form for different kind of users), then none of those captcha engines will satisfy you, because they do not support it.

You can of course try a workaround, like load the captcha with ajax when it is necessary, but in some cases, this is also not a acceptable solution.

The solution described in this post will allow you one instance per portlet, because the string that we use in the session to validate the user input against the captcha image is the session id. You are free to change that and use, for example, the form name, or something else, to have multiple instances in a portlet.

So, here is a solution with another captcha engine, JCaptcha. It is relative easy to use and straight forward.

We assume you have created a liferay portlet plugin project with a MVCPortlet.

Those are the steps you have to do:

  1. download JCaptcha jar and put it in the lib directory of your portlet project
  2. create a CaptchaServiceSingleton class
  3. create the serveResource method in your portlet and implement it to serve the captcha image
  4. create an action to validate the captcha image
  5. create a jsp that shows the image in a form were the user can type the letters of the image shown.

More or less, that is all you have to do.

Lets have a closer look at those steps.

Download JCaptcha and copy it in the lib dir

This should be an easy thing to do. The lib directory is in

1
docroot/WEB-INF/lib

Currently, the file name is “jcaptcha-1.0-all.jar”.

There is also one dependency: you have to add the “commons-collections.jar” in the “liferay-plugin-package.properties” file.

Create a CaptchaServiceSingleton class

JCaptcha need a singleton class for its own use. So, we create it. Lets give to this class the name “CaptchaServiceSingleton”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

public class CaptchaServiceSingleton {

public static ImageCaptchaService getInstance() {

return instance;
}

private static final Log logger = LogFactoryUtil.getLog(CaptchaServiceSingleton.class);

private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();
}

serverResource method

In the portlet class create the following method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private static final Log logger = LogFactoryUtil.getLog(TestCaptcha.class);

@Override
public void serveResource(ResourceRequest resourceRequest, ResourceResponse resourceResponse)
throws IOException, PortletException {

ThemeDisplay themeDisplay = (ThemeDisplay) resourceRequest.getAttribute(WebKeys.THEME_DISPLAY);

byte[] captchaChallengeAsJpeg = null;
// the output stream to render the captcha image as jpeg into
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
// get the session id that will identify the generated captcha.
// the same id must be used to validate the response, the session id is a good candidate!
String captchaId = resourceRequest.getPortletSession().getId() + StringPool.UNDERLINE + getPortletName();

logger.info("GENERATING CAPTCHA IMAGE FOR " + captchaId);

// call the ImageCaptchaService getChallenge method
BufferedImage challenge =
CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId, themeDisplay.getLocale());

// a jpeg encoder
JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
jpegEncoder.encode(challenge);

}
catch (IllegalArgumentException e) {
logger.error(e.getMessage(), e);
}
catch (CaptchaServiceException e) {
logger.error(e.getMessage(), e);
}
catch (Exception e) {
logger.error(e.getMessage(), e);
}
catch (Throwable e) {
logger.error(e.getMessage(), e);
}

captchaChallengeAsJpeg = jpegOutputStream.toByteArray();

HttpServletResponse response = PortalUtil.getHttpServletResponse(resourceResponse);

// flush it in the response
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType(ContentTypes.IMAGE_JPEG);

ServletResponseUtil.write(response, captchaChallengeAsJpeg);
}

validateCaptcha method

We will create a private method for the captcha validation and an action method that will be called on the submission of the form. The validation method will use the singleton calls we created on the first step.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public void validateCaptcha(ActionRequest request, ActionResponse response) {

if (validateCaptcha(request)) {
SessionMessages.add(request, "Everything went fine");
}
else {
SessionErrors.add(request, "Input is wrong. Please try again");
}
}

public boolean validateCaptcha(PortletRequest request) {

Boolean isResponseCorrect = Boolean.FALSE;
// remenber that we need an id to validate!
String captchaId = request.getPortletSession().getId() + StringPool.UNDERLINE + getPortletName();
// retrieve the response

String response = ParamUtil.getString(request, "j_captcha_response");
// Call the Service method

logger.info("captchaId:" + captchaId);
logger.info("response:" + response);

try {
isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId, response);
}
catch (CaptchaServiceException e) {
// should not happen, may be thrown if the id is not valid
logger.error(e.getMessage(), e);
}

return isResponseCorrect;
}

view.jsp file

So, now, the view… In our “view.jsp” file we put the following code:

1
2
3
&nbsp;

<img src="${serveCaptchaUrl}" alt="" /> <input type="text" name="j_captcha_response" value="" /> <button type="submit">Submit</button>

And that’s all.

If you need a refresh link you can add a link that runs a javascript function that removes and add the src of the captcha image. For example, using jQuery, this method could be like this:

1
2
3
4
$("# refreshCaptcha").click(function(){
$("# captchaImg").attr("src", "");
$("# captchaImg").attr("src", "${serveCaptchaUrl}");
});