To see a very simple example of the script console in action, log into the portal as an administrator and navigate to the Control Panel → Server Administration area of the Control Panel. Then click on Script. This is Liferay DXP’s script console. Change the script type to Groovy and replace the code in the script console with the following:
number = com.liferay.portal.kernel.service.UserLocalServiceUtil.getUsersCount();
out.println(number);
Click the Execute button and check the script console or the log for the output.
Next, consider a less simplistic example. You’ll retrieve some user information
from the database, make some changes, and then save those changes to Liferay’s
database. Suppose that your company has updated the terms of use and wants each
user to be presented with the updated terms of use whenever they next log in.
When users agree to the terms of use, a boolean attribute called
agreedToTermsOfUse
is set in their user records. As long as the value of this
variable is true
, Liferay DXP will not present the user with the terms of use.
However, if you set this flag to false
for each user, each user must agree to
the terms of use again before they can log in.
You’ll use Groovy again. Ensure that the script type in the script console is set
to Groovy. Then execute the following code to check the status of the
agreedToTermsOfUse
user attribute:
import com.liferay.portal.kernel.service.UserLocalServiceUtil
userCount = UserLocalServiceUtil.getUsersCount()
users = UserLocalServiceUtil.getUsers(0, userCount)
for (user in users) { println("User Name: " + user.getFullName() + " -- " +
user.getAgreedToTermsOfUse()) }
The code above just prints the value of the agreedToTermsOfUse
attribute for
each user. Next, you’ll actually update each user in the system to set his or
her agreedToTermsOfUse
attribute to false
. Your script will make sure to
skip the default user as well as the default admin user that’s currently signed
in and running the script.
import com.liferay.portal.kernel.service.UserLocalServiceUtil
userCount = UserLocalServiceUtil.getUsersCount()
users = UserLocalServiceUtil.getUsers(0, userCount)
long currentUserId = Long.parseLong(userInfo.get("liferay.user.id"))
for (user in users){
if(!user.isDefaultUser() && (user.getUserId() != currentUserId)) {
user.setAgreedToTermsOfUse(false)
UserLocalServiceUtil.updateUser(user)
}
}
To verify the script has updated the records, run the first script again and you should see that all users (except the default user and your user) have been updated.
That’s all that’s needed to run scripts and to access the Liferay service layer.
Keep these things in mind when working with the script console:
- There is no undo.
- There is no preview.
- When invoking local services, no permissions checking is enforced.
- Scripts are executed synchronously. Be careful with scripts that might take a long time to execute.
For these reasons, you should use the script console cautiously. It’s best to test run your scripts on non-production systems before running them on production. Follow the tips in the subsequent sections to make better use of Liferay’s script console. Note: These tips originated from a Liferay blog post. The following scripts are Groovy scripts but they can be adapted to other languages.
Tip 1: Use the Predefined Variables
The following predefined variables are available to scripts executed from Liferay’s script console:
out
(java.io.PrintWriter
)actionRequest
(javax.portlet.ActionRequest
)actionResponse
(javax.portlet.ActionReponse
)portletConfig
(javax.portlet.PortletConfig
)portletContext
(javax.portlet.PortletContext
)preferences
(javax.portlet.PortletPreferences
)userInfo
(java.util.Map<String, String>
)
Note that if you use System.out.println
, for example, your output will be
printed to Liferay’s log file. If you use out.println
instead (using the
predefined variable), your output will be printed to the script console.
The predefined variables can all be very useful when you’re creating scripts.
The actionRequest
variable can be especially useful, as this script
demonstrates:
import com.liferay.portal.kernel.util.*
company = PortalUtil.getCompany(actionRequest)
out.println("Current Company:${company.getName()}\n")
out.println("User Info:")
userInfo.each {
k,v -> out.println("${k}:${v}")
}
Tip 2: Embed HTML Markup in Script Outputs
The output of the script console is rendered as HTML content. Thus, you can embed HTML markup in your outputs to change their look and feel. Here’s an example:
import com.liferay.portal.kernel.service.*
number = com.liferay.portal.kernel.service.UserLocalServiceUtil.getUsersCount();
out.println(
"""
<div style="background-color:black; text-align: center">
<h1 style="color: #37A9CC; font-size:xx-large">${number}</h1>
</div>
""");
Tip 3: Show Exceptions in the Script Console
When any exception occurs during script execution, the error message is always the same:
Your request failed to complete.
This message gives no detail about the error. To find information about the error and what caused it, you usually need to examine the server logs.
However, you can use the following technique to make exception details appear in the script console. Wrap your code with a try / catch block and print the stack trace to the console output from the catch clause. Note that even this technique does not catch script syntax errors. Here’s an example:
try {
nullVar = null
out.println(nullVar.length())
} catch(e) {
out.println("""<div class="portlet-msg-error">${e}</div>""")
e.printStackTrace(out)
}
Tip 4: Implement a Preview Mode
Since Liferay’s script console does not provide an undo feature, it can be very
convenient to set up a kind of preview mode. The purpose of a preview mode is to
determine any permanent effects of a script before any information is actually
saved to the Liferay database. The preview mode consists in using a
previewMode
flag which determines whether the operations with permanent
effects should be executed or not. If previewMode
is true
, all of the data
which would be permanently affected by the script is systematically printed.
This providers the user executing the script with an outline of the data
impacted by the script. If the user determines that everything is OK, the flag
can be switched so that the script can make permanent updates to the database.
Here’s an example Groovy script that show the preview mode concept in action:
import java.util.Calendar
import com.liferay.portal.kernel.service.*
import com.liferay.portal.kernel.model.*
import com.liferay.portal.kernel.dao.orm.*
import static com.liferay.portal.kernel.workflow.WorkflowConstants.*
//
// Deactivate users never logged and created since more than 2 years
//
previewMode = true // Update this flag to false to really make changes
Calendar twoYearsAgo = Calendar.getInstance()
twoYearsAgo.setTime(new Date())
twoYearsAgo.add(Calendar.YEAR, -2)
DynamicQuery query = DynamicQueryFactoryUtil.forClass(User.class)
.add(PropertyFactoryUtil.forName("lastLoginDate").isNull())
.add(PropertyFactoryUtil.forName("createDate").lt(twoYearsAgo.getTime()))
users = UserLocalServiceUtil.dynamicQuery(query)
users.each { u ->
if(!u.isDefaultUser() && u.getStatus() != STATUS_INACTIVE) {
out.println(u.getEmailAddress())
if(!previewMode) {
UserLocalServiceUtil.updateStatus(u.getUserId(), STATUS_INACTIVE)
}
}
}
if(previewMode) {
out.println('Preview mode is on: switch off the flag and execute '
+ 'again this script to make changes to the database')
}
Tip 5: Plan a File Output for Long-Running Scripts
When a script has been running for a long time, it’s possible for the script console to return an error even though the script can continue running and potentially conclude successfully. But it’s impossible to know the outcome without the corresponding output!
To bypass this limitation, you can send the output of the script console to a custom file instead of to the console itself or to the Liferay log. For example, consider this script:
import com.liferay.portal.kernel.service.*
import com.liferay.portal.kernel.dao.orm.*
// Output management
final def SCRIPT_ID = "MYSCRIPT"
outputFile = new File("""${System.getProperty("liferay.home")}/scripting/out-${SCRIPT_ID}.txt""")
outputFile.getParentFile().mkdirs()
def trace(message) {
out.println(message)
outputFile << "${message}\n"
}
// Main code
users = UserLocalServiceUtil.getUsers(QueryUtil.ALL_POS, QueryUtil.ALL_POS)
users.each { u ->
trace(u.getFullName())
}
The script above creates a subfolder of
Liferay Home
called scripting
and saves the script output to a file in this folder. After
running the script above, it’s possible to read the generated file without
direct access to the file system. Here’s a second script that demonstrates this:
final def SCRIPT_ID = "MYSCRIPT"
outputFile = new File("""${System.getProperty("liferay.home")}/scripting/out-${SCRIPT_ID}.txt""")
out.println(outputFile.text)
One advantage of using a dedicated output file instead of using a classic logger is that it’s easier to get the script output data back. Getting the script output data would be more difficult to obtain from the portal log, for example, because of all the other information there.
Of course, Liferay’s script engine has uses beyond the script console. Next, you’ll learn how to leverage Liferay’s script engine for designing workflows.
Related Topics
Invoking Liferay Services From Scripts