In this article I am sharing the guidelines / recommendations to be followed while developing plugins for Liferay or developing the application without dependencies of liferay.

The recommendations are based on established standards collected from a number of sources, individual experience, local requirements/needs.  

 

Adding new Entity / Service / Persistence Class

 When you add an entry in the service.xml, make sure that it is in alphabetical order as a best practice for improving readability of the file and the generated code.

JSP/HTML Coding Guidelines

Tabs and Linebreaks

  • There should be one linebreak (not the <br> tag, but the newline '\n') between (before and after) scriplet and html code snippet.
  • There should be no tab spacing between the <form> tag and the enclosed form elements.
  • The hidden form fields should immediately follow the <form> tag, followed by the other form elements.
  • Between the <form> tag and the input elements, there should be no line breaks, but between <form> tag and any form table, there should be a linebreak.
  • There should be a linebreak between the typical save and the cancel buttons at the end of the form. 
  • There should be no tab spacing between <table> and <tr> element, but a tab spacing is required between <tr> and <td>. There should be a tab spacing betwen <td> and the elements inside the <td>, even if it is a scriplet that goes inside.
  • There should be a blankspace after the starting tag of the JSP expression ( <%=) and before the closing tag (%>)
  • <%= expression %>
  • For if and for loops in scriplets, there should be a space after for/if and '(' and before the starting paranthesis '{'
  • for (int i = 0; i< results.size(); i++) {
  • Last, but not the least, it is recommended to check every line of the file for formatting and patterns.

Suggestions for using Liferay Tags

  • For tables displaying data, it is recommended to use the SearchContainerobject: <liferay-ui:search-iterator>
  • For forms that require inputs from the users, it is best recommended to enclose the form elements inside a two-column lfr-table class (a table), with one input per row: the label being the first column and the input element being the second column. (For examples, refer to an existing Liferay JSP)
  • To obtain request parameters, ParamUtil.getString(request, paramName) is recommended.
  • All JSPs are to include an init.jsp - which imports the required java classes in alphabetical order.
  • For actions to be performed on entities - (edit, delete, manage), it is recommended to use an alternate JSP - entity_action.jsp and include it as the last element in the SearchContainer object.
  • Use of jQuery is preferred to Javascript on the client side.
  • The names of forms are patternized :   <form action="<portlet:actionURL />" method="post" name="<portlet:namespace />fm"> is the recommended pattern.
  • An input parameter - redirect that has <%= currentURL %> as value should be passed in all the forms along with the other input parameters, This points to the current URL and should be the redirect URL for cancel buttons typically.
  • If the JSP has multiple view elements, based on conditions (read as actions), use of <c:choose> and <c:when> is recommended.
  • We can use JQUERY for pagination, tabs , accordion  to display data in tabular format.

 JSP Coding Rules

  • Use the jsp extension for JSPs invoked from struts or tiles or included dynamically
  • Use the jspf extension for JSPs included statically

 JavaScript (and jQuery) Code Style

Recommended convention is just always use single quotes for strings everywhere in Javascript. The reason is because this: jQuery('<a class="modify-link" href="javascript: ;"></a>')

looks more readable than this: jQuery("<a class=\"modify-link\" href=\"javascript: ;\"></a>")

(especially on large html blocks).

Events

When triggering an event (like change) which is not naturally fired we prefer to use: trigger('event name') instead of methods like change(), dblclick()... etc The reason is that these events are not naturally fired for anything except for form elements, but jQuery allows us to trigger custom events that aren't natively supported. Especially in cases like this, we prefer to use trigger('event name') so that it's explicit that we're triggering an event.

Adding Startup Actions

If your fix / feature requires you to add/modify a startup action,

  1. Any hooks for your code(portlet,web,theme) which are needed to be done at the startup can be added to StartupAction.Java.
  2. This is a struts action similar to LoginAction.java and LogoutAction.java.

Referencing jar files

 If there are any jar files which are already present in portal\WEB-INF\lib and you also want to use them in your plugin, don't package those jars again. Instead just add the reference in docroot\WEB-INF\liferay-plugin-package.properties.

Java Code Style

Apart from the normal Java coding standards,

  • Methods in {Model}ServiceImpl classes
  1. Should be ordered alphabetically.
  2. They should only return either instances of Model or lists of instances of Model.Example: TagsEntryLocalService can only return TagsEntry or Lists of TagsEntry because the soap generator then knows how to convert List to a typed array
  • Processing order within add and delete methods in {Model}ServiceImpl classes

                            When "adding":

    • expando
    • model
    • resource
    • portal package
    • local package
    • other package
    • indexer
    • status
    • file
    • email / subscribers
    • ping
    • When "deleting":
    • model
    • resource
    • portal package
    • local package
    • other package (expando is in here)
    • indexer
    • status
    • file
    • email / subscribers
    • ping

 Naming Conventions

A naming convention is a rule to follow as you decide what to name your identifiers (e.g. class, package, variable, method, etc…).

  • Package Names: All characters must be lowercase 

Examples

com.riitesh.intranet.servicename Acceptable

com. riitesh.intranet.serviceName  Unacceptable

com. riitesh.intranet.service_name Unacceptable 

  • Classes: Names should be in Camel Case. Try to use nouns because a class is normally representing  something in the real world:

  class Customer

 class Account

 Interfaces: Names should be in Camel Case.

 Class = UserImpl, Interface = User

 

  • Variables: Names should be in mixed case. The names should represent what the value of the variable represents:

                             String firstName

                             int orderNumber

  • Constants: Names should be in uppercase.

                                         static final int DEFAULT_WIDTH

                                         static final int MAX_HEIGHT 

  • Class and Package Imports:

To make for more readable code, types used in code should be imported rather that fully qualifying the class name. In general, import only those classes necessary.

 I                            Importing java.util.* when only two or three classes are needed will increase the runtime footprint of the application. 

  • Returning Collection :-

Any method that returns a Collection should always return a valid Collection -- never null. However, the returned Collection can be empty. 

  • class (When necessary to distinguish from similarly named interfaces):

            ClassNameEndsWithImpl OR ClassNameEndsWithObject

  • constants (finals)

            UPPERCASE_WITH_UNDERSCORE_IF_MORE_THAN_ONE_WORD

 In Java, constants, values that do not change, are typically implemented as static final fields of classes. The convention is to use full English words, all in upper case, with underscores between the words

             Example:

             MINIMUM_BALANCE

            MAX_VALUE

            DEFAULT_START_DATE 

  • private or protected

            firstWordLowerCaseAndInternalWordsCapitalized

  • streams

When there is a single input and/or output stream being opened, used, and then closed within a member function the convention is to use in and out for the names of these streams, respectively.

  • loop counters

A common way is to use words like loopCounters or simply counter because it helps facilitate the search for the counters in the program.

i, j, k can also be used as loop counters but the disadvantage is that search for i ,j and k in the code will result in many hits.

  • parameters

            Parameters should be named following the exact same conventions as for local variable

            Name parameters the same as their corresponding fields (if any)Example: 

If Account has an attribute called balance and you needed to pass a parameter representing a new value for it the parameter would be called balance. The field would be referred to as this.balance in the code and the parameter would be referred as balance 

  • local variables

firstWordLowerCaseButInternalWordsCapitalized 

Use full English descriptors with the first letter of any non-initial word in uppercase.

  • methods/member functions

firstWordLowerCaseButInternalWordsCapitalized()

 

Field Visibility

Fields should not be declared public for reasons of encapsulation. All fields should be declared private and accessor methods should be used to access / modify the field value. This results in less coupling between classes as the protected / public / package access of field can result in direct access of the field from other classes

Documenting the Field

Document the following:

 It’s description

Document all applicable invariants Invariants of a field are the conditions that are always true about it. By documenting the restrictions on the values of a field one can understand important business rules, making it easier to understand how the code works / how the code is supposed to work

Examples For fields that have complex business rules associated with them one should provide several example values so as to make them easier to understand

Concurrency issues

Visibility decisions If a field is declared anything but private then it should be documented why it has not been declared private.

 

Use of Accesors

Accessors can be used for more than just getting and setting the values of instance fields. Accesors should be used for following purpose also:

 

Initialize the values of fields Use lazy initialization where fields are initialized by their getter member functions.

 

Example

/**

  * Answer the branch number, which is the leftmost four digits of the full account

  * number. Account numbers are in the format BBBBAAAAAA.

  */

protected int getBranchNumber()

{

            if(branchNumber == 0)

            {

                        // The default branch number is 1000, which is the

                        // main branch in downtown Bedrock

                        setBranchNumber(1000);

            }

            return branchNumber;

}

 

Note:

This approach is advantageous for objects that have fields that aren’t regularly accessed

Whenever lazy initialization is used in a getter function the programmer should document what is the type of default value, what the default value as in the example above.

                                

Access Constant Values

Commonly constant values are declared as static final fields. This approach makes sense for “constants” that are stable.

 If the constants can change because of some changes in the business rules as the business matures then it is better to use getter member functions for constants.

 By using accesors for constants programmer can decrease the chance of bugs and at the same time increase the maintainability of the system.

 

Liferay Custom Message Handling

Steps to follow to display message in jsp page.

 1. Create Language.properties file under src/content/Language.properties. “message” displays a localized message for a key. The key can be one of the predefined keys from liferay custom portlet (Language_xx_xx.properites in src/content/) .

For Arabic Language create file name like Language_ar_SA.properties and English Language_en_US.properties .

 2. Make an entry in the portlet.xml file for support language 

            <supported-locale>ar_SA</supported-locale>

            <supported-locale>en_US</supported-locale>

            <resource-bundle>content/Language</resource-bundle>

 

    2.1 Create Language.properties file and enter key / value 

            success-welcome-message = Welcome custom message

            message-example = STC Message Example

            custom-error-message = This is an custom error message

 3. Add <liferay-ui/> tag library in jsp page. 

             <%@ taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %> 

 4. Display custom message in jsp file. Use <liferay-ui:message/> tag. 

            <liferay-ui:message key="message-example" /> 

              It will print “message-example” translated with selected language . 

5.) Display “Success Message” in jsp file.           

    5.1)  import class com.liferay.portal.kernel.servlet.SessionMessages in your controller. 

            Eg . SessionMessages.add(request,key); 

            Add the piece of code where business logic will be successed.

            SessionMessages.add(renderRequest, "success-welcome-message");

    5.2) To display message in success-jsp page.

            <liferay-ui:success key="success-welcome-message" message="success-welcome-message"/>

6.) Display “Error Message” in jsp file.           

    6.1)  import class com.liferay.portal.kernel.servlet.SessionMessages in your controller. 

            Eg . SessionErrors.add(renderRequest,request,key); 

            Add the piece of code where if business logic will be failed.

            SessionErrors.add(renderRequest, "custom-error-message");

    6.2) To display eror-message in success-jsp page.

            <liferay-ui:error key="custom-error-message" message="custom-error-message" />

    6.3) There seem to be another way of displaying errors directly from an Exception . The syntax is

           <liferay-ui:error exception="<%=Exception.class%" message="message" />            

           Note:- We can implement the resource bundle by adding the properties files which will display the custom messages based on language              selection.

Code Formatting

               We will use Jalopy a Java based formatter plugin for eclipse. It layouts any valid Java source code according to some widely configurable rules to meet a certain coding style. It will do the formatting on the source code automatically based on certain rules defined.

 We will install the Jalopy Plugin in eclipse with pre-defined standard rules for java source code. It Comply with naming conventions, arrange methods, generate and sanitize Javadoc comments, insert missing or remove obsolete braces, add override annotations, serial version UIDs, optimize import declarations, remove redundant modifiers. Some of the key feature mentioned below:- 

  • Line Wrapping
  • Auto Insertion of braces
  • Removal of empty braces
  • Indentation
  • Code Sorting
  • Removal of empty lines

 Line Constraints 

  • Do not use more than one line as a separator
  • Avoiding writing lines exceeding 80 characters. If a line cannot fit within 80 characters, it should be wrapped as follow
    • Break after a comma
    • Break before an operator
    • Prefer higher-level breaks to lower-level breaks
    • If the above rules lead to confusing code or to code that's squished up against the right margin, just indent 8 spaces instead.

 

Overriding equals constraints

When overriding the equals() method, one should ensure that it is:

  • reflexive : x.equals( x ) for all non-null objects x

  • symmetric : x.equals( y ) implies y.equals( x ) for all non-null objects x and y

  • transitive : x.equals( y ) and y.equals( z ) implies x.equals( z ) for all non-null objects x, y and z

  • null sensitive : x.equals(null) == false for all non-null objects x

  • consistent : x.equals( y ) should stay constant if no changes are made to x and y for all non-null objects x and y

  

Define both equals() and hashCode()

If the method Object.equals is overridden, so should be the method Object.hashCode, and vice-versa.

  

Define equals when adding fields

When adding fields to a class C, which extends a class C0 (different from Object) in which equals is overridden (defined), then C should also override (define) equals.

  

Avoid using finalizer

The finalize() method should not be used.

  

Do not implement the Cloneable interface

The clone() method should never be overridden or even called.

 

Do not call nonfinal methods in constructors

A nonfinal method should not be called from within a constructor.

 

Make fields private

Fields in a class should be made private with accessor member methods granting access to them to external entities.

 

 

Do not use static mutable fields

There should be no static mutable fields. A static field is mutable if it is not declared final, or if it is declared final but points to a mutable object.

 

Exceptions to the rule

An exception is a singleton, where a class is instantiated to a single object, which is needed to coordinate actions across the system. In this case it would become cumbersome to pass this object around as parameter to constructors of classes referring to the object.

Another exception is a counter used to keep track of the use of a class, for example counting how many objects are created of the class.

 

Initialize fields before use

Fields should be explicitly initialized before used. Specifically, it should be ensured that static fields have sensible values even if no instances are ever created. Use static initializers (static) if necessary. All fields should be initialized in constructors (or object factories if used instead of constructors).

 

Use assertions

Use assertions to check method boundary conditions.

 

Note

In order for such assertions to be enabled the code has to be compiled with option -ea (enable assertions). This has the advantage that assertions can be disabled in case they are computationally expensive. The fact that assertions are not activated by default, however, has the disadvantage that unless care is taken, the assertions may not be checked.

 

Use annotations

Annotations should be used to indicate intentions that can then be checked by the compiler or by static analyzers.

Restrict method overloading

Method overloading on argument types should be restricted to cases where the argument types are radically different.

 

Use braces in control structures

Braces should be used to group statements that are part of a control structure, such as an if-else or for statement.

Do not have empty blocks

Empty code blocks '{}' should be avoided.

Use breaks in switch statements

An unconditional break statement should terminate every non-empty switch clause.

End switch statements with default

The final clause of a switch statement should be the default clause. In general it is recommended to only use switch statements over enumerated types.

 

Restrict side effects in expressions

Side effects should be limited as follows:

  1. the assignment operator =, its derived compound assignment forms (such as +=), and the increment ++ and decrement -- operators should only occur in statement expressions (as statements).
  2. side effects should not occur in:
    1. boolean conditional expressions as part of conditional statements (if, while, do), in expressions in the control-part of for loops, or in the expression in switch statements.
    2. sub-expressions of composite expressions built by applying Java's built in operators (&&, ||, +, ...).
    3. actual argument expressions in method and constructor calls.

 

Use named constants for non-trivial literals

Literals (specifically integers, floating point numbers, and strings) should as a general rule not be coded directly, except for the simple integer values -1, 0, and 1, which can appear in a for loop as counter values. Instead such literals should be defined as constants (static final).

 

 

Make operator precedence explicit

In compound expressions with multiple sub-expressions the intended grouping of expressions should be made explicit with precedence should not be relied upon as commonly mastered by all programmers.

 

Do not use reference equality

One should normally use the equals method instead of the == and != operators when comparing objects. This includes St primitives such as Integer and Long.

 

Use only short-circuit logic operators

The Boolean non-short-circuit operators | and & should not be used. Note that the corresponding Integer operators are not covered by this rule (they are allowed).

 

Do not use octal values

Integer literals should not start with '0'. An integer starting with 0 is interpreted as an Octal value.

 

Do not use floating point equality

Expressions of type float and double should not be tested with == or !=.

Use one result type in conditional expressions

When using the (p?e1:e2) operator with numeric operands, one should use the same numeric type for both the second and third operands.

 

Do not use string concatenation operator in loops

The String concatenation operator + should not be used in a loop statement. Instead one should use a java.lang.StringBuffer or java.lang.StringBuilder for efficiency.

 

The String concatenation operator + creates a new String object, which is costly. If performed in a loop with many iterations, a new String object is created for each + operator, for each loop iteration. This at first hand may just seem as a performance issue, but it can become a correctness issue in case the application response time is affected severely.

Do not drop exceptions

Exceptions should not be dropped or ignored. Either exceptions should be caught and handled, or they should be thrown to the outermost level. Note that checked exceptions typically should be handled, whereas unchecked exceptions typically can be thrown to the outermost level.

 

Do not abruptly exit a finally block

A finally block should not contain a return statement and should not throw any exceptions that are not caught within the finally block.

 

Use primitive types

One should use primitive types (byte, short, int, long, float, double, boolean, char) in preference to boxed primitives (Byte, Short, Integer, Long, Float, Double, Boolean, Character) whenever there is a choice.

 

 Important Tips

  • Put all jsp Imports in init.jsp and include the init.jsp in other jsp's 
  • Avoid HTML tags such as <input>, instead use <aui> liferay tag 
  • To Identify the unique Id of any element append <portlet:namespace/>. This is very useful when one page contains multiple portlets and the id's of two elements are the same. <portlet:namespace/> gives the unique value of the element of the portlet on the page.
  • Comments : Is you are customizing the Liferay  code, add comments as follows:
  • <!--(Project Name) Customization: Information regarding the customized code-->
  • // (Project Name) Customization: Information regarding the customized code
  •  Naming Conventions: to reduce the effort needed to read and understand source code, use meanigful variable, class, method names.
  •  The impl class method can be called directly in jsp using the util class.
  • Do not place the service.jar and portlet-impl.jar in portlet lib, instead put those in build path whenever required
  • To share the portlet classes at the portal level, place the portlet jar in tomcat/lib/ext
  • Note : Delete the jar from the portlet’s WEB-INF/lib directory to avoid conflicts
  •  Avoid inline css in jsp tags.
  •  Logging: Use Kernel Logging (com.liferay.portal.kernel.log. 
  • Create a private static final _log variable and declare it at the bottom of the file.