Skip to content

Latest commit

 

History

History
294 lines (215 loc) · 8.29 KB

SLIM-RUNTIME-README.markdown

File metadata and controls

294 lines (215 loc) · 8.29 KB

Liferay Slim Runtime

The Liferay Slim Runtime provides the bare necessities for running Service Builder modules. It's useful for testing applications quickly in a Liferay runtime environment free of Liferay add-ons.

The Liferay Slim Runtime provides

  • Caching infrastructure
  • Database infrastructure
  • HTTP support
  • JAX-RS support
  • Limited set of Liferay utility classes
  • OSGi framework for running modules
  • Service Builder runtime for Service Builder modules
  • Spring infrastructure
  • Transaction infrastructure

It does not provide

  • Authentication/Authorization layers
  • Layout templates
  • Permissions
  • Portlet support (no portlet container)
  • Sites
  • Themes
  • etc.

Build

To build the Slim Runtime, execute the following top-level Ant command:

ant all -Dbuild.profile=slim

It's built in the server directory specified by the app.server.properties file's app.server.parent.dir property. Note that the Slim Runtime only supports Apache Tomcat 8+. This limitation simplifies packaging and configuration.

Launch

To launch the Slim Runtime, run the Tomcat start scripts found in the <tomcat>/bin directory:

./startup.[sh|bat]

Deploying Modules

You can deploy modules from any of the default directories the portal.properties file defines (see properties below) or from a custom auto-deploy directory you add to the module.framework.auto.deploy.dirs property.

module.framework.base.dir=${liferay.home}/osgi

module.framework.configs.dir=${module.framework.base.dir}/configs
module.framework.marketplace.dir=${module.framework.base.dir}/marketplace
module.framework.modules.dir=${module.framework.base.dir}/modules
module.framework.war.dir=${module.framework.base.dir}/war

module.framework.auto.deploy.dirs=\
    ${module.framework.configs.dir},\
    ${module.framework.marketplace.dir},\
    ${module.framework.modules.dir},\
    ${module.framework.war.dir}

Running Pristine Slim Runtime

By default, a pristine Slim Runtime has no UI or apps. Requests to it result in 404 errors.

The modules you add provide all the functionality.

Adding Functionality

A web endpoint is the simplest type of function.

The following snippet demonstrates a simple servlet that responds to all requests to http://localhost:8080[/*]:

package web.sample;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;

@Component(
	immediate = true,
	property = {
		HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN + "=/*"
	},
	service = Servlet.class
)
public class SampleServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void service(
			HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

		response.setContentType("text/html");

		PrintWriter writer = response.getWriter();

		writer.println("<h2>Hello You!</h2>");
	}

}

The Database

The Slim Runtime creates the database schema automatically the first time it runs.

MariaDB [lportal]> show tables;
+------------------+
| Tables_in_lportal|
+------------------+
| ClassName_       |
| Configuration_   |
| Counter          |
| Release_         |
| ServiceComponent |
+------------------+
5 rows in set (0.00 sec)

Only the following core services are available:

  • ClassNameLocalService
  • CounterLocalService
  • ReleaseLocalService
  • ServiceComponentLocalService

No other services are provided! Therefore, any service deployed to this Slim Runtime that depends on services other than these won't work.

Service Builder

The Service Builder runtime bootstraps all deployed Service Builder services (API and service modules).

For example, deploying the com.liferay.contacts.api and com.liferay.contacts.service modules adds the Contacts_Entry table to the database:

MariaDB [lportal]> show tables;
+------------------+
| Tables_in_lportal|
+------------------+
| ClassName_       |
| Configuration_   |
| Contacts_Entry   |
| Counter          |
| Release_         |
| ServiceComponent |
+------------------+
6 rows in set (0.00 sec)

A Basic Service Builder Web App

The servlet in the following snippet implements a simple web app that uses the contacts service.

package web.sample;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;

import com.liferay.contacts.model.Entry;
import com.liferay.contacts.service.EntryLocalService;
import com.liferay.counter.kernel.service.CounterLocalService;
import com.liferay.portal.kernel.dao.orm.DynamicQuery;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.dao.orm.RestrictionsFactoryUtil;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.Validator;

@Component(
	immediate = true,
	property = {
		HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN + "=/*"
	},
	service = Servlet.class
)
public class SampleServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void service(
			HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

		response.setContentType("text/html");

		PrintWriter writer = response.getWriter();

		String fullNameParameter = ParamUtil.getString(request, "fullName");

		if (Validator.isNull(fullNameParameter)) {
			writer.println("<h2>Hello You!</h2>");
			writer.println("Do you want to sign up for this thing?<br/>");
			writer.println("<form action='/join' method='post'>");
			writer.println("<input type='text' name='fullName' placeholder='Full Name'><br>");
			writer.println("<input type='text' name='emailAddress' placeholder='Email Address'><br>");
			writer.println("<input type='submit' value='Sign Up'><br>");
			writer.println("</form>");

			List<Entry> entries = _entryLocalService.getEntries(QueryUtil.ALL_POS, QueryUtil.ALL_POS);

			if (entries.isEmpty()) {
				writer.println("I'm so lonely! :(<br/>");
			}
			else {
				writer.println("Here's a list of others who've already signed up:<br/>");

				for (Entry entry : _entryLocalService.getEntries(QueryUtil.ALL_POS, QueryUtil.ALL_POS)) {
					writer.println(String.format("%s &lt;%s><br/>", entry.getFullName(), entry.getEmailAddress()));
				}
			}

			return;
		}

		String emailAddressParameter = ParamUtil.getString(request, "emailAddress");

		if (Validator.isNull(emailAddressParameter)) {
			writer.println(String.format("Ooops! %s, you forgot your emailAddress :(<br/>", fullNameParameter));
			writer.println("<a href='/'>Retry?</a>");

			return;
		}

		DynamicQuery dynamicQuery = _entryLocalService.dynamicQuery();

		dynamicQuery.add(RestrictionsFactoryUtil.eq("emailAddress", emailAddressParameter));

		long count = _entryLocalService.dynamicQueryCount(dynamicQuery);

		if (count > 0) {
			writer.println(String.format("Ooops! Someone already registered with the email address &lt;%s> :(<br/>", emailAddressParameter));
			writer.println("<a href='/'>Retry?</a>");

			return;
		}

		long entryId = _counterLocalService.increment();

		Entry entry = _entryLocalService.createEntry(entryId);

		entry.setFullName(fullNameParameter);
		entry.setEmailAddress(emailAddressParameter);

		_entryLocalService.updateEntry(entry);

		writer.println(String.format("Great! Thanks for signing up %s :D<br/>", fullNameParameter));
		writer.println("<a href='/'>Go Back!</a>");
	}

	@Reference
	private CounterLocalService _counterLocalService;

	@Reference
	private EntryLocalService _entryLocalService;

}

Note how it uses OSGi Declarative Services to reference an instance of Liferay Core's CounterLocalService and Contacts API's EntryLocalService.