/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.alloy.mvc;
import com.liferay.alloy.mvc.internal.json.web.service.AlloyMockUtil;
import com.liferay.counter.kernel.service.CounterLocalServiceUtil;
import com.liferay.portal.kernel.bean.BeanPropertiesUtil;
import com.liferay.portal.kernel.bean.ConstantsBeanFactoryUtil;
import com.liferay.portal.kernel.dao.search.SearchContainer;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.messaging.Destination;
import com.liferay.portal.kernel.messaging.InvokerMessageListener;
import com.liferay.portal.kernel.messaging.MessageBus;
import com.liferay.portal.kernel.messaging.MessageBusUtil;
import com.liferay.portal.kernel.messaging.MessageListener;
import com.liferay.portal.kernel.messaging.SerialDestination;
import com.liferay.portal.kernel.model.AttachedModel;
import com.liferay.portal.kernel.model.AuditedModel;
import com.liferay.portal.kernel.model.BaseModel;
import com.liferay.portal.kernel.model.Company;
import com.liferay.portal.kernel.model.GroupedModel;
import com.liferay.portal.kernel.model.Layout;
import com.liferay.portal.kernel.model.ModelHintsUtil;
import com.liferay.portal.kernel.model.PersistedModel;
import com.liferay.portal.kernel.model.Portlet;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.portlet.LiferayPortletConfig;
import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
import com.liferay.portal.kernel.portlet.PortletBag;
import com.liferay.portal.kernel.portlet.PortletBagPool;
import com.liferay.portal.kernel.portlet.PortletConfigFactoryUtil;
import com.liferay.portal.kernel.portlet.PortletURLFactoryUtil;
import com.liferay.portal.kernel.scheduler.SchedulerEngineHelperUtil;
import com.liferay.portal.kernel.scheduler.StorageType;
import com.liferay.portal.kernel.scheduler.TimeUnit;
import com.liferay.portal.kernel.scheduler.Trigger;
import com.liferay.portal.kernel.scheduler.TriggerFactoryUtil;
import com.liferay.portal.kernel.search.Document;
import com.liferay.portal.kernel.search.Field;
import com.liferay.portal.kernel.search.Hits;
import com.liferay.portal.kernel.search.Indexer;
import com.liferay.portal.kernel.search.IndexerRegistryUtil;
import com.liferay.portal.kernel.search.SearchContext;
import com.liferay.portal.kernel.search.SearchContextFactory;
import com.liferay.portal.kernel.search.Sort;
import com.liferay.portal.kernel.service.CompanyLocalServiceUtil;
import com.liferay.portal.kernel.servlet.ServletResponseUtil;
import com.liferay.portal.kernel.servlet.SessionMessages;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.transaction.Isolation;
import com.liferay.portal.kernel.transaction.Propagation;
import com.liferay.portal.kernel.transaction.Transactional;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.CalendarFactoryUtil;
import com.liferay.portal.kernel.util.ContentTypes;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.JavaConstants;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.ServiceBeanMethodInvocationFactoryUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.TextFormatter;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.MimeResponse;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletResponse;
import javax.portlet.PortletURL;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.WindowState;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.PageContext;
/**
* @author Brian Wing Shun Chan
*/
public abstract class BaseAlloyControllerImpl implements AlloyController {
public static final String TOUCH =
BaseAlloyControllerImpl.class.getName() + "#TOUCH#";
public static final String VIEW_PATH =
BaseAlloyControllerImpl.class.getName() + "#VIEW_PATH";
public static void setAuditedModel(
BaseModel<?> baseModel, Company company, User user)
throws Exception {
if (!(baseModel instanceof AuditedModel) || (company == null) ||
(user == null)) {
return;
}
AuditedModel auditedModel = (AuditedModel)baseModel;
if (baseModel.isNew()) {
auditedModel.setCompanyId(company.getCompanyId());
auditedModel.setUserId(user.getUserId());
auditedModel.setUserName(user.getFullName());
auditedModel.setCreateDate(new Date());
auditedModel.setModifiedDate(auditedModel.getCreateDate());
}
else {
auditedModel.setModifiedDate(new Date());
}
}
public static void setAuditedModel(
BaseModel<?> baseModel, HttpServletRequest request)
throws Exception {
if (!(baseModel instanceof AuditedModel) || (request == null)) {
return;
}
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
setAuditedModel(
baseModel, themeDisplay.getCompany(), themeDisplay.getUser());
}
public static void setAuditedModel(BaseModel<?> baseModel, User user)
throws Exception {
if (!(baseModel instanceof AuditedModel) || (user == null)) {
return;
}
long companyId = CompanyLocalServiceUtil.getCompanyIdByUserId(
user.getUserId());
setAuditedModel(
baseModel, CompanyLocalServiceUtil.getCompany(companyId), user);
}
public static void setLocalizedProperties(
BaseModel<?> baseModel, HttpServletRequest request, Locale locale)
throws Exception {
Map<String, Object> modelAttributes = baseModel.getModelAttributes();
for (String propertyName : modelAttributes.keySet()) {
boolean localized = ModelHintsUtil.isLocalized(
baseModel.getModelClassName(), propertyName);
if (!localized) {
continue;
}
Class<?> baseModelClass = baseModel.getModelClass();
String setMethodName =
"set" + TextFormatter.format(propertyName, TextFormatter.G);
Method setMethod = baseModelClass.getMethod(
setMethodName, new Class<?>[] {String.class, Locale.class});
String value = ParamUtil.getString(request, propertyName);
setMethod.invoke(baseModel, value, locale);
}
}
@Override
public void afterPropertiesSet() {
initClass();
initServletVariables();
initPortletVariables();
initThemeDisplayVariables();
initMethods();
initPaths();
initIndexer();
initMessageListeners();
registerAlloyController();
}
@Override
public void execute() throws Exception {
Method method = getMethod(actionPath);
if (method == null) {
if (log.isDebugEnabled()) {
log.debug("No method found for action " + actionPath);
}
}
if (!hasPermission()) {
renderError(
"you-do-not-have-permission-to-access-the-requested-resource");
method = null;
}
if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
executeAction(method);
}
else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
executeRender(method);
}
else if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
executeResource(method);
}
if ((alloyNotificationEventHelper != null) &&
!viewPath.equals(VIEW_PATH_ERROR)) {
alloyNotificationEventHelper.addUserNotificationEvents(
request, controllerPath, actionPath,
alloyNotificationEventHelperPayloadJSONObject);
}
}
public BaseModel<?> fetchBaseModel(String className, long classPK)
throws Exception {
AlloyServiceInvoker alloyServiceInvoker = new AlloyServiceInvoker(
className);
return alloyServiceInvoker.fetchModel(classPK);
}
@Override
public Portlet getPortlet() {
return portlet;
}
@Override
public HttpServletRequest getRequest() {
return request;
}
@Override
public String getResponseContent() {
return responseContent;
}
@Override
public ThemeDisplay getThemeDisplay() {
return themeDisplay;
}
@Override
public long increment() throws Exception {
return CounterLocalServiceUtil.increment();
}
@Override
public void indexModel(BaseModel<?> baseModel) throws Exception {
if ((indexer != null) &&
indexerClassName.equals(baseModel.getModelClassName())) {
indexer.reindex(baseModel);
}
else {
Indexer<BaseModel<?>> baseModelIndexer =
(Indexer<BaseModel<?>>)IndexerRegistryUtil.getIndexer(
baseModel.getModelClass());
if (baseModelIndexer != null) {
baseModelIndexer.reindex(baseModel);
}
}
}
@Override
public void persistModel(BaseModel<?> baseModel) throws Exception {
if (!(baseModel instanceof PersistedModel)) {
return;
}
PersistedModel persistedModel = (PersistedModel)baseModel;
persistedModel.persist();
}
@Override
public void setModel(BaseModel<?> baseModel, Object... properties)
throws Exception {
if (baseModel.isNew()) {
baseModel.setPrimaryKeyObj(increment());
}
setAuditedModel(baseModel);
setGroupedModel(baseModel);
setAttachedModel(baseModel);
if ((properties.length % 2) != 0) {
throw new IllegalArgumentException(
"Properties length is not an even number");
}
for (int i = 0; i < properties.length; i += 2) {
String propertyName = String.valueOf(properties[i]);
Object propertyValue = properties[i + 1];
BeanPropertiesUtil.setProperty(
baseModel, propertyName, propertyValue);
}
}
@Override
public void setPageContext(PageContext pageContext) {
this.pageContext = pageContext;
}
@Override
public void setUser(User user) {
this.user = user;
}
@Override
public String translate(String pattern, Object... arguments) {
PortletConfig portletConfig = PortletConfigFactoryUtil.create(
portlet, servletContext);
ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
return LanguageUtil.format(resourceBundle, pattern, arguments);
}
@Override
public void updateModel(BaseModel<?> baseModel, Object... properties)
throws Exception {
BeanPropertiesUtil.setProperties(baseModel, request);
setLocalizedProperties(baseModel);
updateModelIgnoreRequest(baseModel, properties);
}
@Override
public void updateModelIgnoreRequest(
BaseModel<?> baseModel, Object... properties)
throws Exception {
setModel(baseModel, properties);
persistModel(baseModel);
}
protected void addOpenerSuccessMessage() {
Map<String, String> data = (Map<String, String>)SessionMessages.get(
request,
portlet.getPortletId() +
SessionMessages.KEY_SUFFIX_REFRESH_PORTLET_DATA);
if ((data == null) ||
!GetterUtil.getBoolean(data.get("addSuccessMessage"))) {
return;
}
addSuccessMessage();
data.put("addSuccessMessage", StringPool.FALSE);
SessionMessages.add(
request,
portlet.getPortletId() +
SessionMessages.KEY_SUFFIX_REFRESH_PORTLET_DATA,
data);
}
protected void addSuccessMessage() {
String successMessage = ParamUtil.getString(
portletRequest, "successMessage");
SessionMessages.add(portletRequest, "requestProcessed", successMessage);
}
protected MessageListener buildControllerMessageListener() {
return null;
}
protected String buildIncludePath(String viewPath) {
StringBundler sb = new StringBundler(5);
sb.append("/WEB-INF/jsp/");
sb.append(portlet.getFriendlyURLMapping());
sb.append("/views/");
if (viewPath.equals(VIEW_PATH_ERROR)) {
sb.append("error.jsp");
return sb.toString();
}
sb.append(viewPath);
sb.append(".jsp");
return sb.toString();
}
protected Indexer<BaseModel<?>> buildIndexer() {
return null;
}
protected String buildResponseContent(
Object data, String message, int status)
throws Exception {
String responseContent = StringPool.BLANK;
if (isRespondingTo("json")) {
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
if (data instanceof Exception) {
String stackTrace = getStackTrace((Exception)data);
jsonObject.put("data", stackTrace);
}
else if (data instanceof JSONArray) {
jsonObject.put("data", (JSONArray)data);
}
else if (data instanceof JSONObject) {
jsonObject.put("data", (JSONObject)data);
}
else if (data != null) {
jsonObject.put(
"data",
JSONFactoryUtil.createJSONObject(String.valueOf(data)));
}
jsonObject.put("message", message);
jsonObject.put("status", status);
responseContent = jsonObject.toString();
}
return responseContent;
}
protected MessageListener buildSchedulerMessageListener() {
return null;
}
protected void executeAction(Method method) throws Exception {
executeResource(method);
actionRequest.setAttribute(
CALLED_PROCESS_ACTION, Boolean.TRUE.toString());
if (Validator.isNotNull(viewPath)) {
actionRequest.setAttribute(VIEW_PATH, viewPath);
PortalUtil.copyRequestParameters(actionRequest, actionResponse);
}
else if (Validator.isNotNull(redirect)) {
actionResponse.sendRedirect(redirect);
}
}
protected void executeRender(Method method) throws Exception {
boolean calledProcessAction = GetterUtil.getBoolean(
(String)request.getAttribute(CALLED_PROCESS_ACTION));
if (!calledProcessAction) {
executeResource(method);
addOpenerSuccessMessage();
}
if (Validator.isNull(responseContent)) {
if (Validator.isNull(viewPath)) {
viewPath = controllerPath + StringPool.SLASH + actionPath;
}
String includePath = buildIncludePath(viewPath);
include(includePath);
}
touch();
}
protected void executeResource(Method method) throws Exception {
try {
if (method != null) {
Class<?> superClass = clazz.getSuperclass();
Method invokeMethod = superClass.getDeclaredMethod(
"invoke", new Class<?>[] {Method.class});
ServiceBeanMethodInvocationFactoryUtil.proceed(
this, BaseAlloyControllerImpl.class, invokeMethod,
new Object[] {method}, new String[] {"transactionAdvice"});
}
}
catch (Exception e) {
Object[] arguments = null;
String message = "an-unexpected-system-error-occurred";
Throwable rootCause = getRootCause(e);
if (rootCause instanceof AlloyException) {
AlloyException ae = (AlloyException)rootCause;
if (ae.log) {
log.error(rootCause, rootCause);
}
if (ArrayUtil.isNotEmpty(ae.arguments)) {
arguments = ae.arguments;
}
message = rootCause.getMessage();
}
else {
log.error(e, e);
}
renderError(
HttpServletResponse.SC_BAD_REQUEST, e, message, arguments);
}
finally {
if (isRespondingTo()) {
String contentType = response.getContentType();
if (isRespondingTo("json")) {
contentType = ContentTypes.APPLICATION_JSON;
}
writeResponse(responseContent, contentType);
}
}
}
protected Object getConstantsBean(Class<?> clazz) {
return ConstantsBeanFactoryUtil.getConstantsBean(clazz);
}
protected String getControllerDestinationName() {
return "liferay/alloy/controller/".concat(
getMessageListenerGroupName());
}
protected String getMessageListenerGroupName() {
String rootPortletId = portlet.getRootPortletId();
return rootPortletId.concat(StringPool.SLASH).concat(controllerPath);
}
protected Method getMethod(String methodName, Class<?>... parameterTypes) {
String methodKey = getMethodKey(methodName, parameterTypes);
return methodsMap.get(methodKey);
}
protected String getMethodKey(
String methodName, Class<?>... parameterTypes) {
StringBundler sb = new StringBundler(parameterTypes.length * 2 + 2);
sb.append(methodName);
sb.append(StringPool.POUND);
for (Class<?> parameterType : parameterTypes) {
sb.append(parameterType.getName());
sb.append(StringPool.POUND);
}
return sb.toString();
}
protected PortletURL getPortletURL(
String controller, String action, PortletMode portletMode,
String lifecycle)
throws Exception {
return getPortletURL(
controller, action, portletMode, lifecycle,
portletRequest.getWindowState(), null);
}
protected PortletURL getPortletURL(
String controller, String action, PortletMode portletMode,
String lifecycle, Object... parameters)
throws Exception {
return getPortletURL(
controller, action, portletMode, lifecycle,
portletRequest.getWindowState(), parameters);
}
protected PortletURL getPortletURL(
String controller, String action, PortletMode portletMode,
String lifecycle, WindowState windowState)
throws Exception {
return getPortletURL(
controller, action, portletMode, lifecycle, windowState, null);
}
protected PortletURL getPortletURL(
String controller, String action, PortletMode portletMode,
String lifecycle, WindowState windowState, Object... parameters)
throws Exception {
Layout layout = themeDisplay.getLayout();
PortletURL portletURL = PortletURLFactoryUtil.create(
request, portlet, layout, lifecycle);
portletURL.setParameter("action", action);
portletURL.setParameter("controller", controller);
portletURL.setPortletMode(portletMode);
portletURL.setWindowState(windowState);
if (parameters == null) {
return portletURL;
}
if ((parameters.length % 2) != 0) {
throw new IllegalArgumentException(
"Parameters length is not an even number");
}
for (int i = 0; i < parameters.length; i += 2) {
String parameterName = String.valueOf(parameters[i]);
String parameterValue = String.valueOf(parameters[i + 1]);
portletURL.setParameter(parameterName, parameterValue);
}
return portletURL;
}
protected Throwable getRootCause(Throwable throwable) {
if (throwable.getCause() == null) {
return throwable;
}
return getRootCause(throwable.getCause());
}
protected String getSchedulerDestinationName() {
return "liferay/alloy/scheduler/".concat(getMessageListenerGroupName());
}
protected String getSchedulerJobName() {
return getMessageListenerGroupName();
}
protected Trigger getSchedulerTrigger() {
Calendar calendar = CalendarFactoryUtil.getCalendar();
return TriggerFactoryUtil.createTrigger(
getSchedulerJobName(), getMessageListenerGroupName(),
calendar.getTime(), 1, TimeUnit.DAY);
}
protected Map<String, Serializable> getSearchAttributes(
Object... attributes)
throws Exception {
Map<String, Serializable> attributesMap = new HashMap<>();
if ((attributes.length == 0) || ((attributes.length % 2) != 0)) {
throw new Exception("Arguments length is not an even number");
}
for (int i = 0; i < attributes.length; i += 2) {
String name = String.valueOf(attributes[i]);
Serializable value = (Serializable)attributes[i + 1];
attributesMap.put(name, value);
}
return attributesMap;
}
protected String getStackTrace(Exception e) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
return stringWriter.toString();
}
protected boolean hasPermission() {
if (permissioned &&
!AlloyPermission.contains(
themeDisplay, portlet.getRootPortletId(), controllerPath,
actionPath)) {
return false;
}
return true;
}
protected void include(String path) throws Exception {
PortletRequestDispatcher portletRequestDispatcher =
portletContext.getRequestDispatcher(path);
if (portletRequestDispatcher != null) {
portletRequestDispatcher.include(portletRequest, portletResponse);
}
else {
log.error(path + " is not a valid include");
}
}
protected long increment(String name) throws Exception {
return CounterLocalServiceUtil.increment(name);
}
protected void initClass() {
clazz = getClass();
classLoader = clazz.getClassLoader();
}
protected void initIndexer() {
indexer = buildIndexer();
if (indexer == null) {
return;
}
indexerClassName = indexer.getClassNames()[0];
Indexer existingIndexer = IndexerRegistryUtil.getIndexer(
indexerClassName);
if ((existingIndexer != null) && (existingIndexer == indexer)) {
BaseAlloyIndexer baseAlloyIndexer = (BaseAlloyIndexer)indexer;
alloyServiceInvoker = baseAlloyIndexer.getAlloyServiceInvoker();
return;
}
alloyServiceInvoker = new AlloyServiceInvoker(indexerClassName);
BaseAlloyIndexer baseAlloyIndexer = (BaseAlloyIndexer)indexer;
baseAlloyIndexer.setAlloyServiceInvoker(alloyServiceInvoker);
baseAlloyIndexer.setClassName(portlet.getModelClassName());
PortletBag portletBag = PortletBagPool.get(portlet.getPortletId());
List<Indexer<?>> indexerInstances = portletBag.getIndexerInstances();
if (existingIndexer != null) {
IndexerRegistryUtil.unregister(existingIndexer);
indexerInstances.remove(existingIndexer);
}
IndexerRegistryUtil.register(indexer);
indexerInstances.add(indexer);
}
protected void initMessageListener(
String destinationName, MessageListener messageListener,
boolean enableScheduler) {
MessageBus messageBus = MessageBusUtil.getMessageBus();
Destination destination = messageBus.getDestination(destinationName);
if (destination != null) {
Set<MessageListener> messageListeners =
destination.getMessageListeners();
for (MessageListener curMessageListener : messageListeners) {
if (!(curMessageListener instanceof InvokerMessageListener)) {
continue;
}
InvokerMessageListener invokerMessageListener =
(InvokerMessageListener)curMessageListener;
curMessageListener =
invokerMessageListener.getMessageListener();
if (messageListener == curMessageListener) {
return;
}
Class<?> messageListenerClass = messageListener.getClass();
String messageListenerClassName =
messageListenerClass.getName();
Class<?> curMessageListenerClass =
curMessageListener.getClass();
if (!messageListenerClassName.equals(
curMessageListenerClass.getName())) {
continue;
}
try {
if (enableScheduler) {
SchedulerEngineHelperUtil.unschedule(
getSchedulerJobName(),
getMessageListenerGroupName(),
StorageType.MEMORY_CLUSTERED);
}
MessageBusUtil.unregisterMessageListener(
destinationName, curMessageListener);
}
catch (Exception e) {
log.error(e, e);
}
break;
}
}
else {
SerialDestination serialDestination = new SerialDestination();
serialDestination.setName(destinationName);
serialDestination.afterPropertiesSet();
serialDestination.open();
MessageBusUtil.addDestination(serialDestination);
}
try {
MessageBusUtil.registerMessageListener(
destinationName, messageListener);
if (enableScheduler) {
SchedulerEngineHelperUtil.schedule(
getSchedulerTrigger(), StorageType.MEMORY_CLUSTERED, null,
destinationName, null, 0);
}
}
catch (Exception e) {
log.error(e, e);
}
}
protected void initMessageListeners() {
controllerMessageListener = buildControllerMessageListener();
if (controllerMessageListener != null) {
initMessageListener(
getControllerDestinationName(), controllerMessageListener,
false);
}
schedulerMessageListener = buildSchedulerMessageListener();
if (schedulerMessageListener != null) {
initMessageListener(
getSchedulerDestinationName(), schedulerMessageListener, true);
}
}
protected void initMethods() {
methodsMap = new HashMap<>();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
String methodKey = getMethodKey(
method.getName(), method.getParameterTypes());
methodsMap.put(methodKey, method);
}
}
protected void initPaths() {
controllerPath = ParamUtil.getString(request, "controller");
if (Validator.isNull(controllerPath)) {
Map<String, String> defaultRouteParameters =
alloyPortlet.getDefaultRouteParameters();
controllerPath = defaultRouteParameters.get("controller");
}
if (log.isDebugEnabled()) {
log.debug("Controller path " + controllerPath);
}
actionPath = ParamUtil.getString(request, "action");
if (Validator.isNull(actionPath)) {
Map<String, String> defaultRouteParameters =
alloyPortlet.getDefaultRouteParameters();
actionPath = defaultRouteParameters.get("action");
}
if (log.isDebugEnabled()) {
log.debug("Action path " + actionPath);
}
viewPath = GetterUtil.getString(
(String)request.getAttribute(VIEW_PATH));
request.removeAttribute(VIEW_PATH);
if (log.isDebugEnabled()) {
log.debug("View path " + viewPath);
}
format = ParamUtil.getString(request, "format");
if (Validator.isNull(format)) {
Map<String, String> defaultRouteParameters =
alloyPortlet.getDefaultRouteParameters();
format = defaultRouteParameters.get("format");
}
if (log.isDebugEnabled()) {
log.debug("Format " + format);
}
if (mimeResponse != null) {
portletURL = mimeResponse.createRenderURL();
portletURL.setParameter("action", actionPath);
portletURL.setParameter("controller", controllerPath);
if (Validator.isNotNull(format)) {
portletURL.setParameter("format", format);
}
if (log.isDebugEnabled()) {
log.debug("Portlet URL " + portletURL);
}
}
}
protected void initPortletVariables() {
liferayPortletConfig = (LiferayPortletConfig)request.getAttribute(
JavaConstants.JAVAX_PORTLET_CONFIG);
portletContext = liferayPortletConfig.getPortletContext();
portlet = liferayPortletConfig.getPortlet();
alloyPortlet = (AlloyPortlet)request.getAttribute(
JavaConstants.JAVAX_PORTLET_PORTLET);
portletRequest = (PortletRequest)request.getAttribute(
JavaConstants.JAVAX_PORTLET_REQUEST);
portletResponse = (PortletResponse)request.getAttribute(
JavaConstants.JAVAX_PORTLET_RESPONSE);
liferayPortletResponse = (LiferayPortletResponse)portletResponse;
lifecycle = GetterUtil.getString(
(String)request.getAttribute(PortletRequest.LIFECYCLE_PHASE));
if (log.isDebugEnabled()) {
log.debug("Lifecycle " + lifecycle);
}
if (lifecycle.equals(PortletRequest.ACTION_PHASE)) {
actionRequest = (ActionRequest)portletRequest;
actionResponse = (ActionResponse)portletResponse;
}
else if (lifecycle.equals(PortletRequest.EVENT_PHASE)) {
eventRequest = (EventRequest)portletRequest;
eventResponse = (EventResponse)portletResponse;
}
else if (lifecycle.equals(PortletRequest.RENDER_PHASE)) {
mimeResponse = (MimeResponse)portletResponse;
renderRequest = (RenderRequest)portletRequest;
renderResponse = (RenderResponse)portletResponse;
}
else if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
mimeResponse = (MimeResponse)portletResponse;
resourceRequest = (ResourceRequest)portletRequest;
resourceResponse = (ResourceResponse)portletResponse;
}
}
protected void initServletVariables() {
servletConfig = pageContext.getServletConfig();
servletContext = pageContext.getServletContext();
request = (HttpServletRequest)pageContext.getRequest();
response = (HttpServletResponse)pageContext.getResponse();
}
protected void initThemeDisplayVariables() {
themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
company = themeDisplay.getCompany();
locale = themeDisplay.getLocale();
user = themeDisplay.getUser();
}
@SuppressWarnings("unused")
@Transactional(
isolation = Isolation.PORTAL, propagation = Propagation.REQUIRES_NEW,
rollbackFor = {Exception.class}
)
protected void invoke(Method method) throws Exception {
method.invoke(this);
}
protected boolean isRespondingTo() {
return Validator.isNotNull(format);
}
protected boolean isRespondingTo(String format) {
return StringUtil.equalsIgnoreCase(this.format, format);
}
@SuppressWarnings("unused")
@Transactional(
isolation = Isolation.PORTAL, propagation = Propagation.REQUIRES_NEW,
rollbackFor = {Exception.class}
)
protected String processDataRequest(ActionRequest actionRequest)
throws Exception {
return null;
}
protected void redirectTo(PortletURL portletURL) {
redirectTo(portletURL.toString());
}
protected void redirectTo(String redirect) {
if (!lifecycle.equals(PortletRequest.ACTION_PHASE)) {
throw new IllegalArgumentException(
"redirectTo can only be called during the action phase");
}
if (Validator.isNotNull(viewPath)) {
throw new IllegalArgumentException(
"redirectTo cannot be called if render has been called");
}
this.redirect = redirect;
}
protected void registerAlloyController() {
alloyPortlet.registerAlloyController(this);
}
protected void render(String actionPath) {
if (Validator.isNotNull(redirect)) {
throw new IllegalArgumentException(
"render cannot be called if redirectTo has been called");
}
viewPath = actionPath;
}
protected void renderError(
int status, Exception e, String pattern, Object... arguments)
throws Exception {
Throwable rootCause = getRootCause(e);
if (isRespondingTo()) {
responseContent = buildResponseContent(
rootCause, translate(pattern, arguments), status);
return;
}
portletRequest.setAttribute("arguments", arguments);
String stackTrace = getStackTrace((Exception)rootCause);
portletRequest.setAttribute("data", stackTrace);
portletRequest.setAttribute("pattern", pattern);
portletRequest.setAttribute("status", status);
render(VIEW_PATH_ERROR);
}
protected void renderError(int status, String pattern, Object... arguments)
throws Exception {
AlloyException alloyException = new AlloyException(
translate("unspecified-cause"));
renderError(status, alloyException, pattern, arguments);
}
protected void renderError(String pattern, Object... arguments)
throws Exception {
renderError(HttpServletResponse.SC_BAD_REQUEST, pattern, arguments);
}
protected boolean respondWith(int status, String message, Object object)
throws Exception {
Object data = null;
if (isRespondingTo("json")) {
if (object instanceof AlloySearchResult) {
Hits hits = ((AlloySearchResult)object).getHits();
Document[] documents = hits.getDocs();
data = toJSONArray(documents);
}
else if (object instanceof Collection) {
Object[] objects =
((Collection)object).toArray(new BaseModel[0]);
data = toJSONArray(objects);
}
else if (object instanceof JSONArray) {
data = object;
}
else if (object != null) {
data = toJSONObject(object);
}
}
responseContent = buildResponseContent(data, message, status);
return true;
}
@SuppressWarnings("unused")
protected boolean respondWith(Object object) throws Exception {
return respondWith(HttpServletResponse.SC_OK, null, object);
}
protected boolean respondWith(String message) throws Exception {
return respondWith(message, null);
}
protected boolean respondWith(String message, Object object)
throws Exception {
return respondWith(HttpServletResponse.SC_OK, message, object);
}
protected AlloySearchResult search(
HttpServletRequest request, PortletRequest portletRequest,
Map<String, Serializable> attributes, String keywords, Sort[] sorts)
throws Exception {
return search(
request, portletRequest, null, attributes, keywords, sorts);
}
protected AlloySearchResult search(
HttpServletRequest request, PortletRequest portletRequest,
SearchContainer<? extends BaseModel<?>> searchContainer,
Map<String, Serializable> attributes, String keywords, Sort[] sorts)
throws Exception {
return search(
indexer, alloyServiceInvoker, request, portletRequest,
searchContainer, attributes, keywords, sorts);
}
protected AlloySearchResult search(
Indexer indexer, AlloyServiceInvoker alloyServiceInvoker,
HttpServletRequest request, PortletRequest portletRequest,
Map<String, Serializable> attributes, String keywords, Sort[] sorts)
throws Exception {
return search(
indexer, alloyServiceInvoker, request, portletRequest, null,
attributes, keywords, sorts);
}
protected AlloySearchResult search(
Indexer indexer, AlloyServiceInvoker alloyServiceInvoker,
HttpServletRequest request, PortletRequest portletRequest,
Map<String, Serializable> attributes, String keywords, Sort[] sorts,
int start, int end)
throws Exception {
if (indexer == null) {
throw new Exception("No indexer found for " + controllerPath);
}
AlloySearchResult alloySearchResult = new AlloySearchResult();
alloySearchResult.setAlloyServiceInvoker(alloyServiceInvoker);
SearchContext searchContext = SearchContextFactory.getInstance(request);
boolean andOperator = false;
boolean advancedSearch = ParamUtil.getBoolean(
request, "advancedSearch");
if (advancedSearch) {
andOperator = ParamUtil.getBoolean(request, "andOperator");
}
searchContext.setAndSearch(andOperator);
if ((attributes != null) && !attributes.isEmpty()) {
searchContext.setAttributes(attributes);
}
searchContext.setEnd(end);
Class<?> indexerClass = Class.forName(indexer.getClassNames()[0]);
if (!GroupedModel.class.isAssignableFrom(indexerClass)) {
searchContext.setGroupIds(null);
}
else if (searchContext.getAttribute(Field.GROUP_ID) != null) {
long groupId = GetterUtil.getLong(
searchContext.getAttribute(Field.GROUP_ID));
searchContext.setGroupIds(new long[] {groupId});
}
if (Validator.isNotNull(keywords)) {
searchContext.setKeywords(keywords);
}
if (ArrayUtil.isNotEmpty(sorts)) {
searchContext.setSorts(sorts);
}
searchContext.setStart(start);
Hits hits = indexer.search(searchContext);
alloySearchResult.setHits(hits);
if (portletURL != null) {
alloySearchResult.setPortletURL(
portletURL, searchContext.getAttributes());
}
alloySearchResult.afterPropertiesSet();
return alloySearchResult;
}
protected AlloySearchResult search(
Indexer indexer, AlloyServiceInvoker alloyServiceInvoker,
HttpServletRequest request, PortletRequest portletRequest,
SearchContainer<? extends BaseModel<?>> searchContainer,
Map<String, Serializable> attributes, String keywords, Sort[] sorts)
throws Exception {
if (searchContainer == null) {
searchContainer = new SearchContainer<>(
portletRequest, portletURL, null, null);
}
return search(
indexer, alloyServiceInvoker, request, portletRequest, attributes,
keywords, sorts, searchContainer.getStart(),
searchContainer.getEnd());
}
protected AlloySearchResult search(
Map<String, Serializable> attributes, String keywords, Sort sort)
throws Exception {
return search(attributes, keywords, new Sort[] {sort});
}
protected AlloySearchResult search(
Map<String, Serializable> attributes, String keywords, Sort[] sorts)
throws Exception {
return search(request, portletRequest, attributes, keywords, sorts);
}
protected AlloySearchResult search(
Map<String, Serializable> attributes, String keywords, Sort[] sorts,
int start, int end)
throws Exception {
return search(
indexer, alloyServiceInvoker, request, portletRequest, attributes,
keywords, sorts, start, end);
}
protected AlloySearchResult search(String keywords) throws Exception {
return search(keywords, (Sort[])null);
}
protected AlloySearchResult search(String keywords, Sort sort)
throws Exception {
return search(keywords, new Sort[] {sort});
}
protected AlloySearchResult search(String keywords, Sort[] sorts)
throws Exception {
return search(null, keywords, sorts);
}
protected void setAlloyNotificationEventHelper(
AlloyNotificationEventHelper alloyNotificationEventHelper) {
this.alloyNotificationEventHelper = alloyNotificationEventHelper;
alloyNotificationEventHelperPayloadJSONObject = null;
}
protected void setAlloyServiceInvokerClass(Class<?> clazz) {
alloyServiceInvoker = new AlloyServiceInvoker(clazz.getName());
}
protected void setAttachedModel(BaseModel<?> baseModel) throws Exception {
if (!(baseModel instanceof AttachedModel)) {
return;
}
AttachedModel attachedModel = (AttachedModel)baseModel;
long classNameId = 0;
String className = ParamUtil.getString(request, "className");
if (Validator.isNotNull(className)) {
classNameId = PortalUtil.getClassNameId(className);
}
if (classNameId > 0) {
attachedModel.setClassNameId(classNameId);
}
long classPK = ParamUtil.getLong(request, "classPK");
if (classPK > 0) {
attachedModel.setClassPK(classPK);
}
}
protected void setAuditedModel(BaseModel<?> baseModel) throws Exception {
setAuditedModel(baseModel, company, user);
}
protected void setGroupedModel(BaseModel<?> baseModel) throws Exception {
if (!(baseModel instanceof GroupedModel) || !baseModel.isNew()) {
return;
}
GroupedModel groupedModel = (GroupedModel)baseModel;
groupedModel.setGroupId(themeDisplay.getScopeGroupId());
}
protected void setLocalizedProperties(BaseModel<?> baseModel)
throws Exception {
setLocalizedProperties(baseModel, request, request.getLocale());
}
protected void setLocalizedProperties(BaseModel<?> baseModel, Locale locale)
throws Exception {
setLocalizedProperties(baseModel, request, locale);
}
protected void setOpenerSuccessMessage() {
SessionMessages.add(
portletRequest,
portlet.getPortletId() + SessionMessages.KEY_SUFFIX_REFRESH_PORTLET,
portlet.getPortletId());
Map<String, String> data = new HashMap<>();
data.put("addSuccessMessage", StringPool.TRUE);
SessionMessages.add(
request,
portlet.getPortletId() +
SessionMessages.KEY_SUFFIX_REFRESH_PORTLET_DATA,
data);
}
protected void setPermissioned(boolean permissioned) {
this.permissioned = permissioned;
}
protected JSONArray toJSONArray(Object[] objects) throws Exception {
JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
for (Object object : objects) {
jsonArray.put(toJSONObject(object));
}
return jsonArray;
}
protected JSONObject toJSONObject(BaseModel<?> baseModel) throws Exception {
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
Map<String, Object> modelAttributes = baseModel.getModelAttributes();
for (String key : modelAttributes.keySet()) {
Object value = modelAttributes.get(key);
if (value instanceof Boolean) {
jsonObject.put(String.valueOf(key), (Boolean)value);
}
else if (value instanceof Date) {
jsonObject.put(String.valueOf(key), (Date)value);
}
else if (value instanceof Double) {
jsonObject.put(String.valueOf(key), (Double)value);
}
else if (value instanceof Integer) {
jsonObject.put(String.valueOf(key), (Integer)value);
}
else if (value instanceof Long) {
jsonObject.put(String.valueOf(key), (Long)value);
}
else if (value instanceof Short) {
jsonObject.put(String.valueOf(key), (Short)value);
}
else {
jsonObject.put(String.valueOf(key), String.valueOf(value));
}
}
return jsonObject;
}
protected JSONObject toJSONObject(Document document) throws Exception {
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
Map<String, Field> fields = document.getFields();
for (String key : fields.keySet()) {
Field field = fields.get(key);
jsonObject.put(field.getName(), field.getValue());
}
return jsonObject;
}
protected JSONObject toJSONObject(Object object) throws Exception {
if (object instanceof BaseModel<?>) {
return toJSONObject((BaseModel<?>)object);
}
else if (object instanceof Document) {
return toJSONObject((Document)object);
}
else if (object instanceof JSONObject) {
return (JSONObject)object;
}
throw new AlloyException(
"Unable to convert " + object + " to a JSON object");
}
protected void touch() throws Exception {
Boolean touch = (Boolean)portletContext.getAttribute(
TOUCH + portlet.getRootPortletId());
if (touch != null) {
return;
}
String touchPath =
"/WEB-INF/jsp/" + portlet.getFriendlyURLMapping() +
"/views/touch.jsp";
if (log.isDebugEnabled()) {
log.debug(
"Touch " + portlet.getRootPortletId() + " by including " +
touchPath);
}
portletContext.setAttribute(
TOUCH + portlet.getRootPortletId(), Boolean.FALSE);
include(touchPath);
}
protected void writeResponse(Object content, String contentType)
throws Exception {
HttpServletResponse response = this.response;
if (!(response instanceof AlloyMockUtil.MockHttpServletResponse)) {
response = PortalUtil.getHttpServletResponse(portletResponse);
}
response.setContentType(contentType);
ServletResponseUtil.write(response, content.toString());
}
protected static final String CALLED_PROCESS_ACTION =
BaseAlloyControllerImpl.class.getName() + "#CALLED_PROCESS_ACTION";
protected static final String VIEW_PATH_ERROR = "VIEW_PATH_ERROR";
protected static Log log = LogFactoryUtil.getLog(
BaseAlloyControllerImpl.class);
protected String actionPath;
protected ActionRequest actionRequest;
protected ActionResponse actionResponse;
protected AlloyNotificationEventHelper alloyNotificationEventHelper;
protected JSONObject alloyNotificationEventHelperPayloadJSONObject;
protected AlloyPortlet alloyPortlet;
protected AlloyServiceInvoker alloyServiceInvoker;
protected ClassLoader classLoader;
protected Class<?> clazz;
protected Company company;
protected MessageListener controllerMessageListener;
protected String controllerPath;
protected EventRequest eventRequest;
protected EventResponse eventResponse;
protected String format;
protected Indexer<BaseModel<?>> indexer;
protected String indexerClassName;
protected String lifecycle;
protected LiferayPortletConfig liferayPortletConfig;
protected LiferayPortletResponse liferayPortletResponse;
protected Locale locale;
protected Map<String, Method> methodsMap;
protected MimeResponse mimeResponse;
protected PageContext pageContext;
protected boolean permissioned;
protected Portlet portlet;
protected PortletContext portletContext;
protected PortletRequest portletRequest;
protected PortletResponse portletResponse;
protected PortletURL portletURL;
protected String redirect;
protected RenderRequest renderRequest;
protected RenderResponse renderResponse;
protected HttpServletRequest request;
protected ResourceRequest resourceRequest;
protected ResourceResponse resourceResponse;
protected HttpServletResponse response;
protected String responseContent = StringPool.BLANK;
protected MessageListener schedulerMessageListener;
protected ServletConfig servletConfig;
protected ServletContext servletContext;
protected ThemeDisplay themeDisplay;
protected User user;
protected String viewPath;
}