org.tdar.struts.action.TdarActionSupport.java Source code

Java tutorial

Introduction

Here is the source code for org.tdar.struts.action.TdarActionSupport.java

Source

package org.tdar.struts.action;

import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.tdar.core.bean.FileProxy;
import org.tdar.core.bean.HasName;
import org.tdar.core.bean.HasStatus;
import org.tdar.core.bean.Persistable;
import org.tdar.core.bean.Slugable;
import org.tdar.core.bean.resource.VersionType;
import org.tdar.core.configuration.TdarConfiguration;
import org.tdar.core.exception.LocalizableException;
import org.tdar.core.exception.StatusCode;
import org.tdar.core.exception.TdarRecoverableRuntimeException;
import org.tdar.core.service.ActivityManager;
import org.tdar.core.service.BookmarkedResourceService;
import org.tdar.core.service.ErrorTransferObject;
import org.tdar.core.service.FileSystemResourceService;
import org.tdar.core.service.GenericService;
import org.tdar.core.service.UrlService;
import org.tdar.core.service.external.AuthorizationService;
import org.tdar.filestore.FileStoreFile;
import org.tdar.filestore.Filestore.ObjectType;
import org.tdar.search.query.SearchResultHandler;
import org.tdar.struts.ErrorListener;
import org.tdar.struts.action.AbstractPersistableController.RequestType;
import org.tdar.struts.action.resource.AbstractInformationResourceController;
import org.tdar.struts.interceptor.annotation.DoNotObfuscate;
import org.tdar.utils.ExceptionWrapper;
import org.tdar.utils.PersistableUtils;
import org.tdar.utils.activity.Activity;
import org.tdar.web.SessionData;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

/**
 * $Id$
 * <p>
 * Base action class that provides access to the service layer, SessionData, and constants for custom result names.
 * </p>
 * 
 * @author <a href='mailto:Allen.Lee@asu.edu'>Allen Lee</a>
 * @version $Revision$
 */
@Scope("prototype")
// @Controller
public abstract class TdarActionSupport extends ActionSupport implements ServletRequestAware, ServletResponseAware {

    private static final long serialVersionUID = 7084489869489013998L;

    // result name constants
    private boolean hideExceptionArea = false;
    private Date freemarkerProcessingTime = null;

    private static final String JS_ERRORLOG_NOSCRIPT = "NOSCRIPT";
    // FIXME: UTF-8 here is likely inviting encoding errors/challenges especially if it ends up in the console which is often the "ASCII" charset
    private static final String JS_ERRORLOG_DELIMITER = "??p";

    public static final String BAD_SLUG = "bad-slug";
    public static final String DRAFT = "draft";
    public static final String JAXBRESULT = "jaxbdocument";
    public static final String JSONRESULT = "jsonresult";
    public static final String HTTPHEADER = "httpheader";
    public static final String REDIRECT = "redirect";

    public static final String WAIT = "wait";
    public static final String THUMBNAIL = "thumbnail";
    public static final String SM = "sm";
    public static final String MD = "md";
    public static final String LG = "lg";
    public static final String SUCCESS_ASYNC = "SUCCESS_ASYNC";

    /**
     * The action could not execute because the request has invalid or insufficient information
     */
    public static final String UNKNOWN_ERROR = "exception"; // 500
    public static final String BAD_REQUEST = "badrequest"; // 400

    public static final String FORBIDDEN = "forbidden"; // 403
    public static final String NOT_FOUND = "not_found"; // 404
    /**
     * The action could not execute because the action requires an authenticated user.
     */
    public static final String UNAUTHORIZED = "unauthorized"; // 401
    public static final String UNAUTHORIZED_REDIRECT = "unauthorized_redirect";

    public static final String AUTHENTICATED = "authenticated";

    /**
     * The action could not execute because one or more resources referenced in the action are no longer
     * available (as opposed to a resource that is simply not found)
     */
    public static final String GONE = "gone";

    public static final String SAVE = "save";
    public static final String ADD = "add";
    public static final String VIEW = "view";
    public static final String EDIT = "edit";
    public static final String JSON = "json";
    public static final String BILLING = "billing";
    public static final String CONTRIBUTOR = "contributor";
    public static final String CONFIRM = "confirm";
    public static final String DELETE = "delete";
    public static final String NEW = "new";
    public static final String FREEMARKER = "freemarker";

    /**
     * The system has authenticated the user and the user is authorized to perform the requested action, but
     * the action could not execute because the user must explicitly acknowledge/accept certain items (e.g.
     * updated Terms Of Service)
     */
    public static final String USER_AGREEMENT = "user_agreement";
    public static final String RESULT_REDIRECT_START = "redirect-start";

    private String javascriptErrorLog;

    /**
     * The view layer ftl primes the js error log with "NOSCRIPT", and the js init tries to clear the log. This way
     * the validate() method can roughly determine if
     * a) (if errorlog == 'NOSCRIPT' ) javascript was disabled on the client
     * b) (errorlog is blank) no js errors were captured (still plenty of ways js errors could have happened though)
     * c) (errorlog has junk in it) You've Got JS Errors!!
     * 
     */

    private String moreInfoUrlKey;
    private final transient Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private transient FileSystemResourceService filesystemResourceService;
    @Autowired
    private transient BookmarkedResourceService bookmarkedResourceService;
    @Autowired
    private transient AuthorizationService authorizationService;

    @Autowired
    private transient GenericService genericService;

    private transient List<String> stackTraces = new ArrayList<String>();

    private SessionData sessionData;

    private HttpServletRequest servletRequest;

    private HttpServletResponse servletResponse;

    private Map<String, String> clientValidationInfo = new LinkedHashMap<>();

    private ErrorListener errorListener;

    public TdarConfiguration getTdarConfiguration() {
        return TdarConfiguration.getInstance();
    }

    public String getNamespace() {
        return ServletActionContext.getActionMapping().getNamespace();
    }

    public String getActionName() {
        if (ActionContext.getContext() == null) {
            return null;
        }
        return ActionContext.getContext().getName();
    }

    @DoNotObfuscate(reason = "Session Object")
    public SessionData getSessionData() {
        if (sessionData == null) {
            getLogger().error("Session data was null, should be managed by Spring.");
            throw new IllegalStateException(getText("tdarActionSupport.no_sesion_data"));
        }
        return sessionData;
    }

    public void setSessionData(SessionData sessionData) {
        this.sessionData = sessionData;
    }

    public String getThemeDir() {
        return getTdarConfiguration().getThemeDir();
    }

    public String getCulturalTermsHelpUrl() {
        return getTdarConfiguration().getCulturalTermsHelpURL();
    }

    public String getInvestigationTypesHelpUrl() {
        return getTdarConfiguration().getInvestigationTypesHelpURL();
    }

    public String getMaterialTypesHelpUrl() {
        return getTdarConfiguration().getMaterialTypesHelpURL();
    }

    public String getSiteTypesHelpUrl() {
        return getTdarConfiguration().getSiteTypesHelpURL();
    }

    public String getGoogleMapsApiKey() {
        return getTdarConfiguration().getGoogleMapsApiKey();
    }

    public String getGoogleAnalyticsId() {
        return getTdarConfiguration().getGoogleAnalyticsId();
    }

    public boolean getPrivacyControlsEnabled() {
        return getTdarConfiguration().getPrivacyControlsEnabled();
    }

    public boolean isCopyrightMandatory() {
        return getTdarConfiguration().getCopyrightMandatory();
    }

    public boolean isArchiveFileEnabled() {
        return getTdarConfiguration().isArchiveFileEnabled();
    }

    public boolean isVideoEnabled() {
        return getTdarConfiguration().isVideoEnabled();
    }

    public boolean isLicensesEnabled() {
        return getTdarConfiguration().getLicenseEnabled();
    }

    public String getServerEnvironmentStatus() {
        return getTdarConfiguration().getServerEnvironmentStatus();
    }

    public String getHostName() {
        return getTdarConfiguration().getHostName();
    }

    public int getHostPort() {
        return getTdarConfiguration().getPort();
    }

    public String getBaseUrl() {
        return getTdarConfiguration().getBaseUrl();
    }

    public String getContactEmail() {
        return getTdarConfiguration().getContactEmail();
    }

    public String getSiteAcronym() {
        return getTdarConfiguration().getSiteAcronym();
    }

    public String getServiceProvider() {
        return getTdarConfiguration().getServiceProvider();
    }

    public String getSiteName() {
        return getTdarConfiguration().getSiteName();
    }

    public String getCommentUrl() {
        return getTdarConfiguration().getCommentUrl();
    }

    public String getCommentUrlEscaped() {
        String input = getTdarConfiguration().getCommentUrl();
        int length = input.length();
        StringBuffer output = new StringBuffer(length * 6);
        for (int i = 0; i < input.length(); i++) {
            output.append("&#");
            output.append((int) input.charAt(i));
            output.append(";");
        }
        return output.toString();
    }

    public String getBugReportUrl() {
        return getTdarConfiguration().getBugReportUrl();
    }

    public String getDocumentationUrl() {
        return getTdarConfiguration().getDocumentationUrl();
    }

    public boolean isProduction() {
        return getTdarConfiguration().getServerEnvironmentStatus().equalsIgnoreCase(TdarConfiguration.PRODUCTION);
    }

    public String getHelpUrl() {
        return getTdarConfiguration().getHelpUrl();
    }

    public String getAboutUrl() {
        return getTdarConfiguration().getAboutUrl();
    }

    public String getCommentsUrl() {
        return getTdarConfiguration().getAboutUrl();
    }

    public Boolean isRPAEnabled() {
        return getTdarConfiguration().isRPAEnabled();
    }

    public String getMapDefaultLat() {
        DecimalFormat latlong = new DecimalFormat("0.00");
        latlong.setGroupingUsed(false);
        return latlong.format(getTdarConfiguration().getMapDefaultLat());
    }

    public String getMapDefaultLng() {
        DecimalFormat latlong = new DecimalFormat("0.00");
        latlong.setGroupingUsed(false);
        return latlong.format(getTdarConfiguration().getMapDefaultLng());
    }

    public boolean isGeoLocationToBeUsed() {
        return getTdarConfiguration().isGeoLocationToBeUsed();
    }

    protected Logger getLogger() {
        return logger;
    }

    public GenericService getGenericService() {
        return genericService;
    }

    protected void addActionErrorWithException(String message, Throwable exception) {
        String trace = ExceptionUtils.getStackTrace(exception);

        getLogger().error("{} [code: {}]: {} -- {}",
                new Object[] { message, ExceptionWrapper.convertExceptionToCode(exception), exception, trace });
        if (exception instanceof TdarActionException) {
            setHideExceptionArea(true);
        }
        if (exception instanceof TdarRecoverableRuntimeException) {
            int maxDepth = 4;
            Throwable thrw = exception;
            if (exception instanceof LocalizableException) {
                ((LocalizableException) exception).setLocale(getLocale());
            }
            StringBuilder sb = new StringBuilder(exception.getLocalizedMessage());

            while ((thrw.getCause() != null) && (maxDepth > -1)) {
                thrw = thrw.getCause();
                if (StringUtils.isNotBlank(thrw.getMessage())) {
                    sb.append(": ").append(thrw.getMessage());
                }
                maxDepth--;
            }

            addActionError(sb.toString());
        } else if (StringUtils.isNotBlank(message)) {
            addActionError(message);
        }
        stackTraces.add(ExceptionWrapper.convertExceptionToCode(exception));
    }

    @Override
    public void addFieldError(String fieldName, String errorMessage) {
        if (errorListener != null) {
            errorListener.addError(String.format("%s:%s", fieldName, errorMessage));
        }
        super.addFieldError(fieldName, errorMessage);
    }

    // FIXME: shouldn't we just getText() every message here or add addActionErrorMessageKey(String messageKey)
    @Override
    public void addActionError(String message) {
        getLogger().debug("ACTIONERROR:: {}", message);
        if (errorListener != null) {
            errorListener.addError(message);
        }
        super.addActionError(message);
    }

    // FIXME: when replacing ActionErrors above, this will not need the getText calls
    protected void processErrorObject(ErrorTransferObject errors) {
        getLogger().trace("found errors {}", errors);
        if (errors == null) {
            return;
        }
        for (String error : errors.getActionErrors()) {
            this.addActionError(getText(error));
        }

        Map<String, List<String>> fieldErrors = errors.getFieldErrors();
        for (String field : fieldErrors.keySet()) {
            for (String error : fieldErrors.get(field)) {
                this.addFieldError(field, getText(error));
            }
        }

        for (String msg : errors.getActionMessages()) {
            this.addActionMessage(getText(msg));
        }

        for (String msg : errors.getStackTraces()) {
            getStackTraces().add(msg);
        }

        setMoreInfoUrlKey(errors.getMoreInfoUrlKey());
    }

    public List<String> getStackTraces() {
        return stackTraces;
    }

    public HttpServletRequest getServletRequest() {
        return servletRequest;
    }

    @Override
    public void setServletRequest(HttpServletRequest servletRequest) {
        this.servletRequest = servletRequest;
    }

    public HttpServletResponse getServletResponse() {
        return servletResponse;
    }

    @Override
    public void setServletResponse(HttpServletResponse servletResponse) {
        this.servletResponse = servletResponse;
    }

    protected final boolean isPostRequest() {
        return "POST".equals(servletRequest.getMethod());
    }

    protected final boolean isGetRequest() {
        return "GET".equals(servletRequest.getMethod());
    }

    public boolean isHttpsEnabled() {
        return getTdarConfiguration().isHttpsEnabled();
    }

    public Integer getHttpsPort() {
        return getTdarConfiguration().getHttpsPort();
    }

    public String getNewsUrl() {
        return getTdarConfiguration().getNewsUrl();
    }

    public boolean isPayPerIngestEnabled() {
        return getTdarConfiguration().isPayPerIngestEnabled();
    }

    public Integer getMaxUploadFilesPerRecord() {
        return getTdarConfiguration().getMaxUploadFilesPerRecord();
    }

    public boolean isSecure() {
        return servletRequest.isSecure();
    }

    public String getProtocol() {
        if (isSecure()) {
            return "https:";
        }
        return "http:";
    }

    public String getStaticHost() {
        if (!getTdarConfiguration().isStaticContentEnabled()) {
            // expecting that default requests are relative to root; so / becomes //
            return "";
        }

        String port = "";
        if (isSecure() && (getTdarConfiguration().getStaticContentSSLPort() != 443)) {
            port = ":" + getTdarConfiguration().getStaticContentSSLPort();
        }

        if (!isSecure() && (getTdarConfiguration().getStaticContentPort() != 80)) {
            port = ":" + getTdarConfiguration().getStaticContentPort();
        }

        return String.format("%s//%s%s", getProtocol(), getTdarConfiguration().getStaticContentHost(), port);
    }

    public boolean getShowJiraLink() {
        return getTdarConfiguration().getShowJiraLink();
    }

    public String getJiraScriptLink() {
        return getTdarConfiguration().getJiraScriptLink();
    }

    public boolean isReindexing() {
        Activity indexingTask = ActivityManager.getInstance().getIndexingTask();
        if ((indexingTask != null) && !indexingTask.hasEnded()) {
            return true;
        }
        return false;
    }

    public String getCurrentUrl() {
        return UrlService.getOriginalUrlPath(servletRequest);
    }

    public boolean isViewRowSupported() {
        return getTdarConfiguration().isViewRowSupported();
    }

    public Long getGuestUserId() {
        return getTdarConfiguration().getGuestUserId();
    }

    public String getCulturalTermsLabel() {
        return getTdarConfiguration().getCulturalTermsLabel();
    }

    public String getJavascriptErrorLogDefault() {
        return JS_ERRORLOG_NOSCRIPT;
    }

    public String getJavascriptErrorLogDelimiter() {
        return JS_ERRORLOG_DELIMITER;
    }

    /**
     * Check the js error log and js validation error log. If we detect any js errors, log them at ERROR. Validation
     * errors are an expected part of the workflow and are only logged at INFO.
     */
    public void reportAnyJavascriptErrors() {
        if (StringUtils.isBlank(javascriptErrorLog)) {
            getLogger().trace("No javascript errors reported by the client");
        } else {
            String[] errors = javascriptErrorLog.split("\\Q" + getJavascriptErrorLogDelimiter() + "\\E");
            if (getLogger().isErrorEnabled()) {
                getLogger().error("Client {} reported {} javascript errors. \n <<{}>>",
                        ServletActionContext.getRequest().getHeader("User-Agent"), errors.length,
                        StringUtils.join(errors, "\n\t - "));
            }
        }

        List<String> lines = new ArrayList<>(clientValidationInfo.size());
        for (Map.Entry<String, String> entry : getClientValidationInfo().entrySet()) {
            String line = String.format("%s\t %s", entry.getKey(), entry.getValue());
            lines.add(line);
        }
        if (!lines.isEmpty()) {
            getLogger().info("the client reported validation errors: \n {}", StringUtils.join(lines, "\n\t"));
        }
    }

    public void setJavascriptErrorLog(String errorLog) {
        javascriptErrorLog = errorLog;
    }

    public String getJavascriptErrorLog() {
        return javascriptErrorLog;
    }

    /**
     * @see TdarConfiguration#isSwitchableMapObfuscation()
     * @return whatever value the tdar configuration isSwitchableMapObfuscation returns.
     */
    public boolean isSwitchableMapObfuscation() {
        return getTdarConfiguration().isSwitchableMapObfuscation();
    }

    public Map<String, String> getClientValidationInfo() {
        return clientValidationInfo;
    }

    public void setClientValidationInfo(LinkedHashMap<String, String> clientValidationInfo) {
        this.clientValidationInfo = clientValidationInfo;
    }

    public String getText(String aTextName, Object... args) {
        return super.getText(aTextName, Arrays.asList(args));
    }

    public List<String> getJavascriptFiles() {
        return filesystemResourceService.parseWroXML("js");
    }

    public List<String> getCssFiles() {
        return filesystemResourceService.parseWroXML("css");
    }

    public boolean isWebFilePreprocessingEnabled() {
        return filesystemResourceService.testWRO();
    }

    public String getMoreInfoUrlKey() {
        return moreInfoUrlKey;
    }

    public void setMoreInfoUrlKey(String moreInfoUrl) {
        this.moreInfoUrlKey = moreInfoUrl;
    }

    public boolean isHideExceptionArea() {
        return hideExceptionArea;
    }

    public void setHideExceptionArea(boolean hideExceptionArea) {
        this.hideExceptionArea = hideExceptionArea;
    }

    public boolean isErrorWarningSectionVisible() {
        if (hideExceptionArea) {
            return false;
        }

        if (CollectionUtils.isNotEmpty(getActionErrors())) {
            return true;
        }
        if (MapUtils.isNotEmpty(getFieldErrors())) {
            return true;
        }
        if (this instanceof AbstractInformationResourceController) {
            AbstractInformationResourceController<?> cast = (AbstractInformationResourceController<?>) this;
            if (cast.authorize() && CollectionUtils.isNotEmpty(cast.getHistoricalFileErrors())) {
                return true;
            }

        }
        return false;
    }

    public void addActionErrors(List<String> errors) {
        if (CollectionUtils.isEmpty(errors)) {
            return;
        }
        for (String error : errors) {
            addActionError(error);
        }
    }

    public String getWroTempDirName() {
        return filesystemResourceService.getWroDir();
    }

    public boolean isUseCDN() {
        return getTdarConfiguration().shouldUseCDN();
    }

    public boolean isShouldAutoDownload() {
        return getTdarConfiguration().shouldAutoDownload();
    }

    public void registerErrorListener(ErrorListener listener) {
        this.errorListener = listener;
    }

    public Date getFreemarkerProcessingTime() {
        return freemarkerProcessingTime;
    }

    public void setFreemarkerProcessingTime(Date freemarkerProcessingTime) {
        this.freemarkerProcessingTime = freemarkerProcessingTime;
    }

    public String getTosUrl() {
        return getTdarConfiguration().getTosUrl();
    }

    public String getContributorAgreementUrl() {
        return getTdarConfiguration().getContributorAgreementUrl();
    }

    public boolean isAuthenticationAllowed() {
        return getTdarConfiguration().allowAuthentication();
    }

    public FileProxy generateFileProxy(String filename, File file) {
        FileProxy fileProxy = null;
        if (filename != null && file != null) {
            fileProxy = new FileProxy(filename, file, VersionType.UPLOADED);
        }
        return fileProxy;

    }

    public boolean handleSlugRedirect(Persistable p, TdarActionSupport action) {
        if (p instanceof Slugable && action instanceof SlugViewAction) {
            Slugable s = (Slugable) p;
            SlugViewAction a = (SlugViewAction) action;
            if (!Objects.equals(s.getSlug(), a.getSlug())) {
                getLogger().trace("slug mismatch - wanted:{}   got:{}", s.getSlug(), a.getSlug());
                if (action instanceof SearchResultHandler<?>) {
                    SearchResultHandler<?> r = (SearchResultHandler<?>) action;
                    if (r.getStartRecord() != SearchResultHandler.DEFAULT_START
                            || r.getRecordsPerPage() != r.getDefaultRecordsPerPage()) {
                        a.setSlugSuffix(String.format("?startRecord=%s&recordsPerPage=%s", r.getStartRecord(),
                                r.getRecordsPerPage()));
                    }
                }
                return false;
            }

        }
        return true;
    }

    /**
     * Load up controller and then check that the user can execute function prior to calling action (used in prepare)
     * 
     * @param pc
     * @param type
     * @throws TdarActionException
     */
    public <P extends Persistable> void prepareAndLoad(PersistableLoadingAction<P> pc, RequestType type)
            throws TdarActionException {
        P p = null;
        Class<P> persistableClass = pc.getPersistableClass();

        // get the ID
        Long id = pc.getId();
        // if we're not null or transient, somehow we've been initialized wrongly
        if (PersistableUtils.isNotNullOrTransient(pc.getPersistable())) {
            getLogger().error("item id should not be set yet -- persistable.id:{}\t controller.id:{}",
                    pc.getPersistable().getId(), id);
        }
        // if the ID is not set, don't try and load/set it
        else if (PersistableUtils.isNotNullOrTransient(id)) {
            p = genericService.find(persistableClass, id);
            pc.setPersistable(p);
        }

        logRequest(pc, type, p);
        checkValidRequest(pc);
    }

    private <P extends Persistable> void logRequest(PersistableLoadingAction<P> pc, RequestType type, P p) {
        String status = "";
        String name = "";
        if (p instanceof HasStatus) {
            status = ((HasStatus) p).getStatus().toString();
        }

        if (pc.getAuthenticatedUser() != null) {
            // don't log anonymous users
            name = pc.getAuthenticatedUser().getUsername();
        } else {
            return;
        }

        if (StringUtils.isBlank(name)) {
            name = "anonymous";
        }
        String title = "";
        if (p != null && p instanceof HasName) {
            title = ((HasName) pc.getPersistable()).getName();
        }
        getLogger().info(String.format("%s is %s %s (%s): %s - %s", name, type.getLabel(),
                pc.getClass().getSimpleName(), pc.getId(), status, title));
    }

    /**
     * Check that the request is valid. In general, this should be able to used as is, though, it's possible to either (a) override the entire method or (b)
     * implement authorize() differently.
     * 
     * @param pc
     * @throws TdarActionException
     */
    protected <P extends Persistable> void checkValidRequest(PersistableLoadingAction<P> pc)
            throws TdarActionException {

        Persistable persistable = pc.getPersistable();
        // if the persistable is NULL and the ID is not null, then we have a "load" issue; if the ID is not numeric, thwn we wouldn't have even gotten here
        if (PersistableUtils.isNullOrTransient(persistable) && PersistableUtils.isNotNullOrTransient(pc.getId())) {
            // deal with the case that we have a new or not found resource
            getLogger().debug("Dealing with transient persistable {}", persistable);
            // ID specified
            if (persistable == null) {
                // persistable is null, so the lookup failed (aka not found)
                abort(StatusCode.NOT_FOUND, getText("abstractPersistableController.not_found"));
            }
            // ID is NULL or -1 too, so bad request
            else if (PersistableUtils.isNullOrTransient(persistable.getId())) {
                // id not specified or not a number, so this is an invalid request
                abort(StatusCode.BAD_REQUEST, getText("abstractPersistableController.cannot_recognize_request",
                        persistable.getClass().getSimpleName()));
            }
        }

        // the admin rights check -- on second thought should be the fastest way to execute as it pulls from cached values
        if (authorizationService.can(pc.getAdminRights(), pc.getAuthenticatedUser())) {
            return;
        }

        // call the locally defined "authorize" method for more specific checks
        if (pc.authorize()) {
            return;
        }

        // default is to be an error
        String errorMessage = getText("abstractPersistableController.no_permissions");
        addActionError(errorMessage);
        abort(StatusCode.FORBIDDEN, FORBIDDEN, errorMessage);
    }

    /**
     * Throw an exception with a status code
     * 
     * @param statusCode
     * @param errorMessage
     * @throws TdarActionException
     */
    protected void abort(StatusCode statusCode, String errorMessage) throws TdarActionException {
        throw new TdarActionException(statusCode, errorMessage);
    }

    protected void abort(StatusCode statusCode, String response, String errorMessage) throws TdarActionException {
        throw new TdarActionException(statusCode, response, errorMessage);
    }

    protected boolean checkLogoAvailable(ObjectType type, Long id, VersionType version) {
        try {
            FileStoreFile proxy = new FileStoreFile(type, version, id, "logo" + version.toPath() + ".jpg");
            File file = TdarConfiguration.getInstance().getFilestore().retrieveFile(type, proxy);
            if (file.exists()) {
                return true;
            }
        } catch (Exception e) {

        }
        return false;
    }

    public boolean isTest() {
        return getTdarConfiguration().isTest();
    }
}