/*
* ConcourseConnect
* Copyright 2009 Concursive Corporation
* http://www.concursive.com
*
* This file is part of ConcourseConnect, an open source social business
* software and community platform.
*
* Concursive ConcourseConnect is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, version 3 of the License.
*
* Under the terms of the GNU Affero General Public License you must release the
* complete source code for any application that uses any part of ConcourseConnect
* (system header files and libraries used by the operating system are excluded).
* These terms must be included in any work that has ConcourseConnect components.
* If you are developing and distributing open source applications under the
* GNU Affero General Public License, then you are free to use ConcourseConnect
* under the GNU Affero General Public License.
*
* If you are deploying a web site in which users interact with any portion of
* ConcourseConnect over a network, the complete source code changes must be made
* available. For example, include a link to the source archive directly from
* your web site.
*
* For OEMs, ISVs, SIs and VARs who distribute ConcourseConnect with their
* products, and do not license and distribute their source code under the GNU
* Affero General Public License, Concursive provides a flexible commercial
* license.
*
* To anyone in doubt, we recommend the commercial license. Our commercial license
* is competitively priced and will eliminate any confusion about how
* ConcourseConnect can be used and distributed.
*
* ConcourseConnect 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 Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with ConcourseConnect. If not, see <http://www.gnu.org/licenses/>.
*
* Attribution Notice: ConcourseConnect is an Original Work of software created
* by Concursive Corporation
*/
package com.concursive.connect.web.controller.actions;
import com.concursive.commons.db.ConnectionElement;
import com.concursive.commons.db.ConnectionPool;
import com.concursive.commons.http.RequestUtils;
import com.concursive.commons.text.StringUtils;
import com.concursive.commons.web.mvc.actions.ActionContext;
import com.concursive.commons.workflow.ObjectHookAction;
import com.concursive.commons.workflow.ObjectHookManager;
import com.concursive.connect.Constants;
import com.concursive.connect.cache.utils.CacheUtils;
import com.concursive.connect.config.ApplicationPrefs;
import com.concursive.connect.indexer.IndexEvent;
import com.concursive.connect.scheduler.ScheduledJobs;
import com.concursive.connect.web.modules.login.dao.Instance;
import com.concursive.connect.web.modules.login.dao.User;
import com.concursive.connect.web.modules.login.utils.InstanceUtils;
import com.concursive.connect.web.modules.login.utils.UserUtils;
import com.concursive.connect.web.modules.members.dao.TeamMember;
import com.concursive.connect.web.modules.profile.dao.Project;
import com.concursive.connect.web.modules.profile.utils.ProjectUtils;
import com.concursive.connect.web.utils.ClientType;
import com.concursive.connect.web.utils.LookupList;
import com.concursive.connect.web.utils.PagedListInfo;
import com.concursive.connect.scheduler.JobEvent;
import freemarker.template.Configuration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Scheduler;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Vector;
/**
* This class is provided as a means to descend from, so that common generic
* methods and fields can be placed here and all other action classes (that
* descend from this one), inherit the common functionality. You may want to
* provide a simple logging mechanism, helper methods that action classes might
* find useful, and so on. note: If an action class you define will not be
* descended by other classes, you should make it final, for the performance
* gains a final class achieves.
*
* @author matt rajkowski
* @version $Id$
* @created January 8, 2002
*/
public class GenericAction implements java.io.Serializable {
protected static final Log LOG = LogFactory.getLog(GenericAction.class);
final static long serialVersionUID = -1388329390981035172L;
public final static String fs = System.getProperty("file.separator");
public final static String NOT_UPDATED_MESSAGE =
"<b>This record could not be updated because someone else updated it first.</b><p>" +
"You can hit the back button to review the changes that could not be committed, " +
"but you must reload the record and make the changes again.";
/**
* 0-arg constructor
*/
public GenericAction() {
}
/**
* This is the default call by all actions if a command= paramter is not
* passed along with the request. Descendant classes should override this
* method to carry out default behavior that should occure BEFORE the initial
* JSP page is displayed. This is most useful when the initial page needs to
* show a list of items that are populated from the database, such as a
* drop-down list of activity for a client, etc.
*
* @param context Description of Parameter
* @return Description of the Returned Value
*/
public String executeCommandDefault(ActionContext context) {
return "DefaultOK";
}
protected Connection getConnection(ActionContext context, ConnectionElement ce, boolean persistant) throws SQLException {
ConnectionPool sqlDriver = (ConnectionPool) context.getServletContext().getAttribute(Constants.CONNECTION_POOL);
return sqlDriver.getConnection(ce, persistant);
}
protected Connection getConnection(ActionContext context, ConnectionElement ce) throws SQLException {
return getConnection(context, ce, false);
}
protected Connection getConnection(ActionContext context, boolean persistant) throws SQLException {
ConnectionElement ce = (ConnectionElement) context.getSession().getAttribute(Constants.SESSION_CONNECTION_ELEMENT);
return getConnection(context, ce, persistant);
}
/**
* Gets the connection attribute of the GenericAction object
*
* @param context Description of the Parameter
* @return The connection value
* @throws SQLException Description of the Exception
*/
protected Connection getConnection(ActionContext context) throws SQLException {
return getConnection(context, false);
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param db Description of the Parameter
*/
protected void freeConnection(ActionContext context, Connection db) {
if (db != null) {
ConnectionPool sqlDriver = (ConnectionPool) context.getServletContext().getAttribute(Constants.CONNECTION_POOL);
sqlDriver.free(db);
}
}
/**
* Gets the user attribute of the GenericAction object
*
* @param context Description of the Parameter
* @return The user value
*/
protected static User getUser(ActionContext context) {
User user = (User) context.getRequest().getAttribute(Constants.REQUEST_CURRENT_USER);
if (user != null) {
return user;
}
return (User) context.getSession().getAttribute(Constants.SESSION_USER);
}
/**
* Gets the userId attribute of the GenericAction object
*
* @param context Description of the Parameter
* @return The userId value
*/
protected static int getUserId(ActionContext context) {
return getUser(context).getId();
}
/**
* Gets the groupId attribute of the GenericAction object
*
* @param context Description of the Parameter
* @return The groupId value
*/
protected int getGroupId(ActionContext context) {
return getUser(context).getGroupId();
}
/**
* Gets the userRange attribute of the GenericAction object
*
* @param context Description of the Parameter
* @return The userRange value
*/
protected String getUserRange(ActionContext context) {
return getUser(context).getIdRange();
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param errors Description of the Parameter
*/
protected void processErrors(ActionContext context, Map errors) {
for (Object o : errors.keySet()) {
String errorKey = (String) o;
String errorMsg = (String) errors.get(errorKey);
context.getRequest().setAttribute(errorKey, errorMsg);
}
context.getRequest().setAttribute("errors", errors);
if (errors.size() > 0) {
if (context.getRequest().getAttribute("actionError") == null) {
context.getRequest().setAttribute("actionError", "The form could not be submitted, please review the messages below.");
}
}
}
/**
* Gets the path attribute of the GenericAction object
*
* @param context Description of the Parameter
* @param moduleFolderName Description of the Parameter
* @return The path value
*/
protected String getPath(ActionContext context, String moduleFolderName) {
return (
getPref(context, "FILELIBRARY") +
getUser(context).getGroupId() + fs +
moduleFolderName + fs);
}
/**
* Gets the datePath attribute of the GenericAction object
*
* @param fileDate Description of the Parameter
* @return The datePath value
*/
public static String getDatePath(java.sql.Timestamp fileDate) {
SimpleDateFormat formatter1 = new SimpleDateFormat("yyyy");
String datePathToUse1 = formatter1.format(fileDate);
SimpleDateFormat formatter2 = new SimpleDateFormat("MMdd");
String datePathToUse2 = formatter2.format(fileDate);
return datePathToUse1 + fs + datePathToUse2 + fs;
}
/**
* Gets the pagedListInfo attribute of the GenericAction object
*
* @param context Description of the Parameter
* @param viewName Description of the Parameter
* @return The pagedListInfo value
*/
protected PagedListInfo getPagedListInfo(ActionContext context, String viewName) {
PagedListInfo tmpInfo = (PagedListInfo) context.getSession().getAttribute(viewName);
if (tmpInfo == null) {
tmpInfo = new PagedListInfo();
tmpInfo.setId(viewName);
tmpInfo.setInitializationLevel(PagedListInfo.LEVEL_INITIALIZED);
context.getSession().setAttribute(viewName, tmpInfo);
} else {
tmpInfo.setInitializationLevel(PagedListInfo.LEVEL_READY);
}
ActionContext actionContext = new ActionContext(
context.getServlet(), null, null, context.getRequest(), context.getResponse());
tmpInfo.setParameters(actionContext);
return tmpInfo;
}
/**
* Get the pagedListInfo, if it doesn't already exist then set the default items per page
*
* @param context
* @param viewName
* @param defaultItemsPerPage
* @return The pagedListInfo value
*/
protected PagedListInfo getPagedListInfo(ActionContext context, String viewName, int defaultItemsPerPage) {
PagedListInfo tmpInfo = (PagedListInfo) context.getSession().getAttribute(viewName);
if (tmpInfo == null) {
tmpInfo = new PagedListInfo();
tmpInfo.setId(viewName);
tmpInfo.setItemsPerPage(defaultItemsPerPage);
tmpInfo.setInitializationLevel(PagedListInfo.LEVEL_INITIALIZED);
context.getSession().setAttribute(viewName, tmpInfo);
} else {
tmpInfo.setInitializationLevel(PagedListInfo.LEVEL_READY);
}
ActionContext actionContext = new ActionContext(
context.getServlet(), null, null, context.getRequest(), context.getResponse());
tmpInfo.setParameters(actionContext);
return tmpInfo;
}
/**
* Gets the pagedListInfo attribute of the GenericAction object
*
* @param context Description of the Parameter
* @param viewName Description of the Parameter
* @param defaultColumn Description of the Parameter
* @param defaultOrder Description of the Parameter
* @return The pagedListInfo value
*/
protected PagedListInfo getPagedListInfo(ActionContext context, String viewName, String defaultColumn, String defaultOrder) {
PagedListInfo tmpInfo = (PagedListInfo) context.getSession().getAttribute(viewName);
if (tmpInfo == null) {
tmpInfo = new PagedListInfo();
tmpInfo.setId(viewName);
tmpInfo.setColumnToSortBy(defaultColumn);
tmpInfo.setSortOrder(defaultOrder);
tmpInfo.setInitializationLevel(PagedListInfo.LEVEL_INITIALIZED);
context.getSession().setAttribute(viewName, tmpInfo);
} else {
tmpInfo.setInitializationLevel(PagedListInfo.LEVEL_READY);
}
ActionContext actionContext = new ActionContext(
context.getServlet(), null, null, context.getRequest(), context.getResponse());
tmpInfo.setParameters(actionContext);
return tmpInfo;
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param viewName Description of the Parameter
*/
protected void deletePagedListInfo(ActionContext context, String viewName) {
PagedListInfo tmpInfo = (PagedListInfo) context.getSession().getAttribute(viewName);
if (tmpInfo != null) {
context.getSession().removeAttribute(viewName);
}
}
/**
* Gets the userLevel attribute of the GenericAction object
*
* @param roleLevel Description of the Parameter
* @return The userLevel value
*/
protected static int getUserLevel(int roleLevel) {
return UserUtils.getUserLevel(roleLevel);
}
/**
* Gets the level of the role from cache
*
* @param code The role id
* @return The level value
*/
protected static int getRoleId(int code) {
LookupList roleList = CacheUtils.getLookupList("lookup_project_role");
return roleList.getLevelFromId(code);
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param projectId Description of the Parameter
* @param permission Description of the Parameter
* @return Description of the Return Value
* @throws SQLException Description of the Exception
*/
protected static boolean hasProjectAccess(ActionContext context, int projectId, String permission) throws SQLException {
// Get the project from cache
Project thisProject = ProjectUtils.loadProject(projectId);
// Check access to the system first
User thisUser = getUser(context);
if (thisUser == null) {
thisUser = UserUtils.createGuestUser();
}
// See if the team member has access to perform a project action
TeamMember thisMember = (TeamMember) context.getRequest().getAttribute("currentMember");
if (thisMember == null || thisMember.getProjectId() != thisProject.getId()) {
try {
// Load from project
thisMember = thisProject.getTeam().getTeamMember(getUserId(context));
if (thisMember == null) {
throw new SQLException("Member record not found.");
}
} catch (Exception notValid) {
// Retrieve or generate a team member based on project settings
thisMember = ProjectUtils.retrieveTeamMember(thisProject.getId(), thisUser);
if (thisMember == null) {
return false;
}
}
context.getRequest().setAttribute("currentMember", thisMember);
}
// Return the status of the permission
if (thisMember.getRoleId() == TeamMember.PROJECT_ADMIN) {
return true;
}
// If this is an administrator of the system, give them upgraded access
if (thisUser.getAccessAdmin()) {
thisMember.setUserLevel(getUserLevel(TeamMember.PROJECT_ADMIN));
thisMember.setRoleId(TeamMember.PROJECT_ADMIN);
thisMember.setTemporaryAdmin(true);
}
// If this is a content editor of the system, give them upgraded access
if (thisUser.hasContentEditorAccess(thisProject.getLanguageId()) && thisProject.getPortal()) {
thisMember.setUserLevel(getUserLevel(TeamMember.PROJECT_ADMIN));
thisMember.setRoleId(TeamMember.PROJECT_ADMIN);
thisMember.setTemporaryAdmin(true);
}
// See what the minimum required is and see if user meets that
int accessLevel = thisProject.getAccessUserLevel(permission);
// The following returns a number... typically 10-100
int projectRoleId = getRoleId(accessLevel);
if (accessLevel == -1 || projectRoleId == -1) {
return false;
}
return (thisMember.getRoleId() <= projectRoleId);
}
/**
* Checks the request to see if the url was called as a popup window
*
* @param context Description of the Parameter
* @return The popup value
*/
protected static boolean isPopup(ActionContext context) {
return ("true".equals(context.getRequest().getParameter("popup")));
}
/**
* Gets the pref attribute of the GenericAction object
*
* @param context Description of the Parameter
* @param name Description of the Parameter
* @return The pref value
*/
protected String getPref(ActionContext context, String name) {
return getApplicationPrefs(context).get(name);
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param name Description of the Parameter
* @return Description of the Return Value
*/
protected boolean hasPref(ActionContext context, String name) {
return getApplicationPrefs(context).has(name);
}
public static ClientType getClientType(ActionContext context) {
ClientType clientType = (ClientType) context.getSession().getAttribute(Constants.SESSION_CLIENT_TYPE);
if (clientType == null) {
clientType = new ClientType(context.getRequest());
context.getSession().setAttribute(Constants.SESSION_CLIENT_TYPE, clientType);
} else if (clientType.getId() == -1) {
clientType.setParameters(context.getRequest());
}
return clientType;
}
/**
* Compares the form's token to the value in the session
*
* @param context
* @return
*/
protected static boolean hasMatchingFormToken(ActionContext context) {
ClientType clientType = getClientType(context);
String requestToken = context.getRequest().getParameter("token");
return (clientType != null && requestToken != null && StringUtils.hasText(clientType.getToken()) && requestToken.equals(clientType.getToken()));
}
/**
* Gets the applicationPrefs attribute of the GenericAction object
*
* @param context Description of the Parameter
* @return The applicationPrefs value
*/
protected static ApplicationPrefs getApplicationPrefs(ActionContext context) {
return ApplicationPrefs.getApplicationPrefs(context.getServletContext());
}
protected synchronized boolean triggerJob(ActionContext context, String name, Object item) {
Scheduler scheduler = (Scheduler) context.getServletContext().getAttribute(Constants.SCHEDULER);
try {
if (item != null){
JobEvent jobEvent = new JobEvent(item);
((Vector) scheduler.getContext().get(name + "EventArray")).add(jobEvent);
}
scheduler.triggerJob(name, (String) scheduler.getContext().get(ScheduledJobs.CONTEXT_SCHEDULER_GROUP));
} catch (Exception e) {
System.out.println("GenericAction-> Scheduler failed: " + e.getMessage());
}
return true;
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param item Description of the Parameter
* @return whether an item was added to the array
* @throws IOException Description of the Exception
*/
protected synchronized boolean indexAddItem(ActionContext context, Object item) {
if (item == null) {
return false;
}
Scheduler scheduler = (Scheduler) context.getServletContext().getAttribute(Constants.SCHEDULER);
try {
IndexEvent indexEvent = new IndexEvent(item, IndexEvent.ADD);
((Vector) scheduler.getContext().get("IndexArray")).add(indexEvent);
scheduler.triggerJob("indexer", (String) scheduler.getContext().get(ScheduledJobs.CONTEXT_SCHEDULER_GROUP));
} catch (Exception e) {
System.out.println("GenericAction-> Scheduler failed: " + e.getMessage());
}
return true;
}
/**
* Description of the Method
*
* @param context Description of the Parameter
* @param item Description of the Parameter
* @return whether an item was added to the array
* @throws IOException Description of the Exception
*/
protected synchronized boolean indexDeleteItem(ActionContext context, Object item) {
if (item == null) {
return false;
}
Scheduler scheduler = (Scheduler) context.getServletContext().getAttribute(Constants.SCHEDULER);
try {
IndexEvent indexEvent = new IndexEvent(item, IndexEvent.DELETE);
((Vector) scheduler.getContext().get("IndexArray")).add(indexEvent);
scheduler.triggerJob("indexer", (String) scheduler.getContext().get(ScheduledJobs.CONTEXT_SCHEDULER_GROUP));
} catch (Exception e) {
System.out.println("GenericAction-> Scheduler failed: " + e.getMessage());
}
return true;
}
/**
* Sets the maximized attribute of the ProjectManagement object
*
* @param context The new maximized value
*/
protected void setMaximized(ActionContext context) {
context.getRequest().getSession(false).removeAttribute("projectView");
}
/**
* Used for sending inserted objects to the rules engine for possible further processing
*
* @param context Description of the Parameter
* @param object Description of the Parameter
*/
protected void processInsertHook(ActionContext context, Object object) {
processInsertHook(context, object, null);
}
protected void processInsertHook(ActionContext context, Object object, String processName) {
int userId = -1;
User user = getUser(context);
if (user != null) {
userId = user.getId();
}
ObjectHookManager hookManager = (ObjectHookManager) context.getServletContext().getAttribute(Constants.OBJECT_HOOK_MANAGER);
hookManager.process(ObjectHookAction.INSERT, null, object, userId, getServerUrl(context), getServerUrl(context), processName);
}
protected void processUpdateHook(ActionContext context, Object previousObject, Object object) {
processUpdateHook(context, previousObject, object, null);
}
protected void processUpdateHook(ActionContext context, Object previousObject, Object object, String processName) {
int userId = -1;
User user = getUser(context);
if (user != null) {
userId = user.getId();
}
ObjectHookManager hookManager = (ObjectHookManager) context.getServletContext().getAttribute(Constants.OBJECT_HOOK_MANAGER);
hookManager.process(ObjectHookAction.UPDATE, previousObject, object, userId, getServerUrl(context), getServerUrl(context), processName);
}
protected void processSelectHook(ActionContext context, Object object) {
processSelectHook(context, object, null);
}
protected void processSelectHook(ActionContext context, Object object, String processName) {
if (object != null) {
int userId = -1;
User user = getUser(context);
if (user != null) {
userId = user.getId();
}
ObjectHookManager hookManager = (ObjectHookManager) context.getServletContext().getAttribute(Constants.OBJECT_HOOK_MANAGER);
hookManager.process(ObjectHookAction.SELECT, null, object, userId, getServerUrl(context), getServerUrl(context), processName);
}
}
protected void processDeleteHook(ActionContext context, Object previousObject) {
processDeleteHook(context, previousObject, null);
}
protected void processDeleteHook(ActionContext context, Object previousObject, String processName) {
int userId = -1;
User user = getUser(context);
if (user != null) {
userId = user.getId();
}
ObjectHookManager hookManager = (ObjectHookManager) context.getServletContext().getAttribute(Constants.OBJECT_HOOK_MANAGER);
hookManager.process(ObjectHookAction.DELETE, previousObject, null, userId, getServerUrl(context), getServerUrl(context), processName);
}
/**
* Gets the link attribute of the GenericAction object
*
* @param context Description of the Parameter
* @return The link value
*/
protected static String getServerUrl(ActionContext context) {
ApplicationPrefs prefs = (ApplicationPrefs) context.getServletContext().getAttribute(Constants.APPLICATION_PREFS);
boolean sslEnabled = "true".equals(prefs.get("SSL"));
return ("http" + (sslEnabled ? "s" : "") + "://" + RequestUtils.getServerUrl(context.getRequest()));
}
protected String getLink(ActionContext context, String url) {
return getServerUrl(context) + "/" + url;
}
protected Project retrieveAuthorizedProject(int projectId, ActionContext context) throws SQLException {
// Get the project from cache
Project project = ProjectUtils.loadProject(projectId);
// Check the user's permission
User thisUser = getUser(context);
if (thisUser != null && thisUser.getAccessAdmin()) {
return project;
}
// Allowed reasons to retrieve a project (permissions will be validated elsewhere)
if (thisUser != null && project.getTeam().hasUserId(thisUser.getId()) ||
project.getFeatures().getAllowGuests() ||
(thisUser != null && thisUser.isLoggedIn() && project.getFeatures().getAllowParticipants()) ||
project.getPortal()) {
return project;
}
project = new Project();
project.setId(projectId);
return project;
}
protected void executeJob(ActionContext context, String jobName) {
Scheduler scheduler = (Scheduler) context.getServletContext().getAttribute(Constants.SCHEDULER);
try {
scheduler.triggerJob(jobName, (String) scheduler.getContext().get(ScheduledJobs.CONTEXT_SCHEDULER_GROUP));
} catch (Exception e) {
System.out.println("GenericAction-> Scheduler failed: " + e.getMessage());
}
}
public static String ctx(ActionContext context) {
return context.getRequest().getContextPath();
}
protected Configuration getFreemarkerConfiguration(ActionContext context) {
return ApplicationPrefs.getFreemarkerConfiguration(context.getServletContext());
}
protected static Instance getInstance(ActionContext context) {
return InstanceUtils.getInstance(getServerUrl(context));
}
}