Make your control panel custom portlet visible per site

Lets us assume we want to have an admin portlet in the content area in our site. We can do this by adding the following xml elements in the liferay-portlet.xml

1
2
3
4
5
6
...
        <control-panel-entry-category>
            content
        </control-panel-entry-category>
        <control-panel-entry-weight>1.5</control-panel-entry-weight>
...

But then we notice that this portlet exists also in the other sites. And we don’t want that.

The solution to this problem is to add a class that implements the ControlPanelEntry interface.

This interface declares 3 methods that can allow you to restrict the visibility of the menu item:

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
        @Override
    public boolean hasAccessPermission(PermissionChecker permissionChecker, Group group, Portlet portlet)
        throws Exception {

        if (MY_GROUP_ID == group.getGroupId()) {
            return true;
        }
        return false;
    }

    @Override
    public boolean isVisible(PermissionChecker permissionChecker, Portlet portlet)
        throws Exception {

        return true;
    }

    @Override
    public boolean isVisible(Portlet portlet, String category, ThemeDisplay themeDisplay)
        throws Exception {

        if (MY_GROUP_ID == themeDisplay.getScopeGroupId()) {
            return true;
        }

        return false;
    }

This class must be also declared in liferay-portlet.xml like following

1
2
3
4
5
6
7
...
        <control-panel-entry-category>
            content
        </control-panel-entry-category>
        <control-panel-entry-weight>1.5</control-panel-entry-weight>
        <control-panel-entry-class>your.entry.ClassHere</control-panel-entry-class>
...

Getting the preview URL of a File Entry

If you are working in a custom portlet and with FileEntries, it is very likely that you will need the preview url of this file, to use it in your UI.

There is a class with the name DLUtil that provide you with a method for this.

But, is you don’t have the themeDisplay (because, for example, you are writing the code of a scheduler job), you can’t use this class. You have to do this alone:

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
         public String getFileUrl(FileEntry fileEntry, boolean appendToken) throws Exception{

        try {
            StringBundler sb = new StringBundler();

            sb.append("/documents/");
            sb.append(fileEntry.getRepositoryId());
            sb.append(StringPool.SLASH);
            sb.append(fileEntry.getFolderId());
            sb.append(StringPool.SLASH);
            sb.append(HttpUtil.encodeURL(HtmlUtil.unescape(fileEntry.getTitle()), true));
            sb.append("?version=");
            sb.append(fileEntry.getFileVersion().getVersion());

            if (appendToken) {
                sb.append("&t=");

                Date modifiedDate = fileEntry.getFileVersion().getModifiedDate();

                sb.append(modifiedDate.getTime());
            }

            return sb.toString();
        }
        catch (PortalException | SystemException e) {
            throw e
        }

        return null;
    }

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.