Introduction

At igniterealtime.org we had a problem with spam. As it is a public community everyone can join and post. We did try a lot of things with little or no real success:

  • captcha for registration
  • email validation
  • no external bookmarks
  • adding 'rel=nofollow' to all external links

These steps did not really help, so we were looking for other solutions. The keyword interceptor does help to moderate messages, but too much messages need moderation now.

 

Solution

The solution was to modify the keyword interceptor to add an URL whitelist. The interceptor is now written and tested, we will likely install it. Actually we did re-use only the email alerting, everything else was replaced.  We try to get it added to Jive SBS and make it available for everyone.

 

This blog describes how to write a simple interceptor, the business logic to block or moderate potential spam links is not included.


Getting Started

Writing an Interceptor in a plugin is quite easy, one needs only a class and a property file. To get started with a lightweight dummy interceptor sources are attached. Use 7zip, tar/gzip or similar zip programs to extract the archive.

Prerequisite: Setup the SDK and the Maven build process and make sure that you can build SBS without issues.

 

Creating the GUI

The GUI is generated by Jive SBS, we only need to provide the text and save it to "src/java/beans/DummyInterceptor.properties". Replace "Dummy" with the name of your interceptor.

There are global values to identify the interceptor:

displayName=Dummy
version=1.0
shortDescription=This is a dummy interceptor
author=LG

And there are properties / values which can be enabled or disabled or text can be entered. This depends on the implementation of the business logic, we do not configure it here. Here only the informational text is specified. We can use "\" to break long lines in the property file, these do not affect the GUI. We can also add HTML codes like <b> or <br/> to adjust the GUI output a little bit.

propertyName.displayName=Title
propertyName.shortDescription=A long text.

 

It may be necessary to add a large text field to enter up to 3500 instead of 250 characters, if this is the case add also

propertyName.useLargeTextField=true

 

Let's create two properties: "interceptorEnabled" and "logString" and make use of the things we learned:

interceptorEnabled.displayName=Description
interceptorEnabled.shortDescription=Select "no" to disbale this interceptor.<br/>This \
interceptor intercepts every message.
logString.displayName=Log String
logString.shortDescription=We will log this string in the error log.
logString.useLargeTextField=true

 

Save the file to complete 30% of the interceptor development.

 

Business Logic

Required Methods

Now we need business logic to intercept messages. In the package "com.jivesoftware.community.interceptor" we will create a new class "DummyInterceptor" which implements JiveInterceptor. Of course you want to replace again "Dummy" with the name of your interceptor.

We will find three methods:

1) getTypes() returns the interceptor types which we want to intercept. Messages of type "TYPE_PRE" can be blocked but they can not be moderated. We will get "org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0" exceptions if we try to moderate content with this type while blocking works fine. So we skip this type:

return Lists.newArrayList(Type.TYPE_POST, Type.TYPE_EDIT);

2) isSystemLevel() returns false, we want to read the documentation before changing the return value to true.

3) invokeInterceptor(JiveObject jo, Type t) may throw a RejectedException, this works for all content types (according to the docs it works only for TYPE_PRE). We will ignore the Type "t".

Let's get the username and log it with the defined "logString". Then force moderation of the message.

String userName = ((JiveContentObject) jo).getUser().getUsername();
log.error("Content of " + userName + " will be moderated because of " + logString);
ModerationUtil.forceContentObjectModeration(content);

 

To be able to install the plugin also public constructor methods are needed:

public DummyInterceptor() {
}
public DummyInterceptor(int objectType, long objectID) {
}

 

Now the interceptor is 60% complete.

 

Getters and Setters

The naming of the getters and setters is almost self-explaining, for strings use getXxx/setXxx and for boolean values use isXxx/setXxx. Append the property name starting with an upper case letter. A "java.beans.IntrospectionException: Method not found: ..." exception is thrown if something is wrong with the naming.

It is important to add an annotation to get things working:

@PropertyNames( { "interceptorEnabled", "logString" })

 

Now let us add code to interact with the two properties which we did define.

 

Boolean Values

For the property "interceptorEnabled" we add "isInterceptorEnabled()" and "setInterceptorEnabled(boolean b)". We have now a boolean property, Jive will render "Yes/No" as possible values in the GUI

public final boolean isInterceptorEnabled() {
    return interceptorEnabled;
}
public final void setInterceptorEnabled(boolean interceptorEnabled) {
    this.interceptorEnabled = interceptorEnabled;
}

 

String Values

The property "logString" should allow to enter a string which we will log. So we need "getLogString()" and "setLogString(String s)".

public final String getLogString() {
    return logString;
}
public final void setLogString(String logString) {
    this.logString = logString;
}

 

Now we have completed 90% of the interceptor. It is time to complete the imports and local variables. Then compile it and everything else and deploy the new sbs.jar files.

After start-up we need to add the interceptor manually in the admin GUI. Select "Spaces", "Settings, "Interceptors", enter "com.jivesoftware.community.interceptor.DummyInterceptor" (replace again "Dummy") and click on "Add Interceptor". Now we can install and configure it. After configuration create a new discussion. After clicking on "Post Message" Jive SBS should display "Please note, your discussion will need to be approved by a moderator before it will be viewable by others.". Let us verify the log file, there we should find a line like this: "ERROR com.jivesoftware.community.interceptor.DummyInterceptor - Content of admin will be moderated because of DummyInterceptor". The user name and the end of the log message vary depending on the user and your interceptor configuration.

 

Now test and comment your code to reach 100%.

 

Hint

Avoid long running loops or web-service calls as this uses a thread in the Jive SBS application and delays the message processing for the user.

 

More useful interceptors which you may want to write could

  • verify that at least one tag is specified
  • verify that the specified tags match the content
  • automatically add a tag "question"/"discussion" for threads or "information" for documents
  • count the number of word occurrences and add tags automatically
  • enforce that the singular of words is used (eg. property instead of properties)
  • ...