Merged 5.1.N (5.1.2) to 5.2.N (5.2.1)

125605 rmunteanu: Merged 5.1.1 (5.1.1) to 5.1.N (5.1.2)
      125498 slanglois: MNT-16155 Update source headers - remove svn:eol-style property on Java and JSP source files


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@125783 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Raluca Munteanu
2016-04-26 13:03:25 +00:00
parent d6f9f50c39
commit dead3c3825
265 changed files with 44099 additions and 44099 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,152 +1,152 @@
package org.alfresco.web.app;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
import org.springframework.extensions.config.Config;
import org.springframework.extensions.config.ConfigService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.jsf.DelegatingVariableResolver;
/**
* JSF VariableResolver that first delegates to the Spring JSF variable
* resolver. The sole purpose of this variable resolver is to look out
* for the <code>Container</code> variable. If this variable is encountered
* the current viewId is examined. If the current viewId matches a
* configured dialog or wizard container the appropriate manager object is
* returned i.e. DialogManager or WizardManager.
*
* <p>Configure this resolver in your <code>faces-config.xml</code> file as follows:
*
* <pre>
* &lt;application&gt;
* ...
* &lt;variable-resolver&gt;org.alfresco.web.app.AlfrescoVariableResolver&lt;/variable-resolver&gt;
* &lt;/application&gt;</pre>
*
* @see org.alfresco.web.bean.dialog.DialogManager
* @see org.alfresco.web.bean.wizard.WizardManager
* @author gavinc
*/
public class AlfrescoVariableResolver extends DelegatingVariableResolver
{
protected List<String> dialogContainers = null;
protected List<String> wizardContainers = null;
private static final String CONTAINER = "Container";
private static final Log logger = LogFactory.getLog(AlfrescoVariableResolver.class);
/**
* Creates a new VariableResolver.
*
* @param originalVariableResolver The original variable resolver
*/
public AlfrescoVariableResolver(VariableResolver originalVariableResolver)
{
super(originalVariableResolver);
}
/**
* Resolves the variable with the given name.
* <p>
* This implementation will first delegate to the Spring variable resolver.
* If the variable is not found by the Spring resolver and the variable name
* is <code>Container</code> the current viewId is examined.
* If the current viewId matches a configured dialog or wizard container
* the appropriate manager object is returned i.e. DialogManager or WizardManager.
*
* @param context FacesContext
* @param name The name of the variable to resolve
*/
public Object resolveVariable(FacesContext context, String name)
throws EvaluationException
{
Object variable = super.resolveVariable(context, name);
if (variable == null)
{
// if the variable was not resolved see if the name is "Container"
if (name.equals(CONTAINER))
{
// get the current view id and the configured dialog and wizard
// container pages
String viewId = context.getViewRoot().getViewId();
List<String> dialogContainers = getDialogContainers(context);
List<String> wizardContainers = getWizardContainers(context);
// see if we are currently in a wizard or a dialog
if (dialogContainers.contains(viewId))
{
variable = Application.getDialogManager();
}
else if (wizardContainers.contains(viewId))
{
variable = Application.getWizardManager();
}
if (variable != null && logger.isDebugEnabled())
{
logger.debug("Resolved 'Container' variable to: " + variable);
}
}
}
return variable;
}
/**
* Retrieves the list of configured dialog container pages
*
* @param context FacesContext
* @return The container pages
*/
protected List<String> getDialogContainers(FacesContext context)
{
if ((this.dialogContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
{
this.dialogContainers = new ArrayList<String>(2);
ConfigService configSvc = Application.getConfigService(context);
Config globalConfig = configSvc.getGlobalConfig();
if (globalConfig != null)
{
this.dialogContainers.add(globalConfig.getConfigElement("dialog-container").getValue());
this.dialogContainers.add(globalConfig.getConfigElement("plain-dialog-container").getValue());
}
}
return this.dialogContainers;
}
/**
* Retrieves the list of configured wizard container pages
*
* @param context FacesContext
* @return The container page
*/
protected List<String> getWizardContainers(FacesContext context)
{
if ((this.wizardContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
{
this.wizardContainers = new ArrayList<String>(2);
ConfigService configSvc = Application.getConfigService(context);
Config globalConfig = configSvc.getGlobalConfig();
if (globalConfig != null)
{
this.wizardContainers.add(globalConfig.getConfigElement("wizard-container").getValue());
this.wizardContainers.add(globalConfig.getConfigElement("plain-wizard-container").getValue());
}
}
return this.wizardContainers;
}
}
package org.alfresco.web.app;
import java.util.ArrayList;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
import org.springframework.extensions.config.Config;
import org.springframework.extensions.config.ConfigService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.jsf.DelegatingVariableResolver;
/**
* JSF VariableResolver that first delegates to the Spring JSF variable
* resolver. The sole purpose of this variable resolver is to look out
* for the <code>Container</code> variable. If this variable is encountered
* the current viewId is examined. If the current viewId matches a
* configured dialog or wizard container the appropriate manager object is
* returned i.e. DialogManager or WizardManager.
*
* <p>Configure this resolver in your <code>faces-config.xml</code> file as follows:
*
* <pre>
* &lt;application&gt;
* ...
* &lt;variable-resolver&gt;org.alfresco.web.app.AlfrescoVariableResolver&lt;/variable-resolver&gt;
* &lt;/application&gt;</pre>
*
* @see org.alfresco.web.bean.dialog.DialogManager
* @see org.alfresco.web.bean.wizard.WizardManager
* @author gavinc
*/
public class AlfrescoVariableResolver extends DelegatingVariableResolver
{
protected List<String> dialogContainers = null;
protected List<String> wizardContainers = null;
private static final String CONTAINER = "Container";
private static final Log logger = LogFactory.getLog(AlfrescoVariableResolver.class);
/**
* Creates a new VariableResolver.
*
* @param originalVariableResolver The original variable resolver
*/
public AlfrescoVariableResolver(VariableResolver originalVariableResolver)
{
super(originalVariableResolver);
}
/**
* Resolves the variable with the given name.
* <p>
* This implementation will first delegate to the Spring variable resolver.
* If the variable is not found by the Spring resolver and the variable name
* is <code>Container</code> the current viewId is examined.
* If the current viewId matches a configured dialog or wizard container
* the appropriate manager object is returned i.e. DialogManager or WizardManager.
*
* @param context FacesContext
* @param name The name of the variable to resolve
*/
public Object resolveVariable(FacesContext context, String name)
throws EvaluationException
{
Object variable = super.resolveVariable(context, name);
if (variable == null)
{
// if the variable was not resolved see if the name is "Container"
if (name.equals(CONTAINER))
{
// get the current view id and the configured dialog and wizard
// container pages
String viewId = context.getViewRoot().getViewId();
List<String> dialogContainers = getDialogContainers(context);
List<String> wizardContainers = getWizardContainers(context);
// see if we are currently in a wizard or a dialog
if (dialogContainers.contains(viewId))
{
variable = Application.getDialogManager();
}
else if (wizardContainers.contains(viewId))
{
variable = Application.getWizardManager();
}
if (variable != null && logger.isDebugEnabled())
{
logger.debug("Resolved 'Container' variable to: " + variable);
}
}
}
return variable;
}
/**
* Retrieves the list of configured dialog container pages
*
* @param context FacesContext
* @return The container pages
*/
protected List<String> getDialogContainers(FacesContext context)
{
if ((this.dialogContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
{
this.dialogContainers = new ArrayList<String>(2);
ConfigService configSvc = Application.getConfigService(context);
Config globalConfig = configSvc.getGlobalConfig();
if (globalConfig != null)
{
this.dialogContainers.add(globalConfig.getConfigElement("dialog-container").getValue());
this.dialogContainers.add(globalConfig.getConfigElement("plain-dialog-container").getValue());
}
}
return this.dialogContainers;
}
/**
* Retrieves the list of configured wizard container pages
*
* @param context FacesContext
* @return The container page
*/
protected List<String> getWizardContainers(FacesContext context)
{
if ((this.wizardContainers == null) || (Application.isDynamicConfig(FacesContext.getCurrentInstance())))
{
this.wizardContainers = new ArrayList<String>(2);
ConfigService configSvc = Application.getConfigService(context);
Config globalConfig = configSvc.getGlobalConfig();
if (globalConfig != null)
{
this.wizardContainers.add(globalConfig.getConfigElement("wizard-container").getValue());
this.wizardContainers.add(globalConfig.getConfigElement("plain-wizard-container").getValue());
}
}
return this.wizardContainers;
}
}

View File

@@ -1,99 +1,99 @@
package org.alfresco.web.app;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Debug phase listener that simply logs when each phase is entered and exited.
*
* @author gavinc
*/
public class DebugPhaseListener implements PhaseListener
{
private static final Log logger = LogFactory.getLog(DebugPhaseListener.class);
public int indent = 0;
public static final String INDENT = " ";
/**
* @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
*/
public void afterPhase(PhaseEvent event)
{
if (logger.isDebugEnabled())
{
if (event.getPhaseId() == PhaseId.RENDER_RESPONSE)
{
printComponentTree(FacesContext.getCurrentInstance().getViewRoot());
}
logger.debug("********** Exiting phase: " + event.getPhaseId().toString());
}
}
/**
* @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
*/
public void beforePhase(PhaseEvent event)
{
if (logger.isDebugEnabled())
logger.debug("********** Entering phase: " + event.getPhaseId().toString());
}
/**
* @see javax.faces.event.PhaseListener#getPhaseId()
*/
public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}
public void printComponentTree(UIComponent comp)
{
printComponentInfo(comp);
List complist = comp.getChildren();
if (complist.size()>0)
indent++;
for (int i = 0; i < complist.size(); i++)
{
UIComponent uicom = (UIComponent) complist.get(i);
printComponentTree(uicom);
if (i+1 == complist.size())
indent--;
}
}
public void printComponentInfo(UIComponent comp)
{
if (comp.getId() == null)
{
logger.debug("UIViewRoot" + " " + "(" + comp.getClass().getName() + ")");
}
else
{
logger.debug(getIndent() + "|");
logger.debug(getIndent() + comp.getId() + " " + "(" + comp.getClass().getName() + ")");
}
}
public String getIndent()
{
String indent = "";
for (int i=0; i<this.indent; i++)
{
indent += INDENT;
}
return indent;
}
}
package org.alfresco.web.app;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Debug phase listener that simply logs when each phase is entered and exited.
*
* @author gavinc
*/
public class DebugPhaseListener implements PhaseListener
{
private static final Log logger = LogFactory.getLog(DebugPhaseListener.class);
public int indent = 0;
public static final String INDENT = " ";
/**
* @see javax.faces.event.PhaseListener#afterPhase(javax.faces.event.PhaseEvent)
*/
public void afterPhase(PhaseEvent event)
{
if (logger.isDebugEnabled())
{
if (event.getPhaseId() == PhaseId.RENDER_RESPONSE)
{
printComponentTree(FacesContext.getCurrentInstance().getViewRoot());
}
logger.debug("********** Exiting phase: " + event.getPhaseId().toString());
}
}
/**
* @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
*/
public void beforePhase(PhaseEvent event)
{
if (logger.isDebugEnabled())
logger.debug("********** Entering phase: " + event.getPhaseId().toString());
}
/**
* @see javax.faces.event.PhaseListener#getPhaseId()
*/
public PhaseId getPhaseId()
{
return PhaseId.ANY_PHASE;
}
public void printComponentTree(UIComponent comp)
{
printComponentInfo(comp);
List complist = comp.getChildren();
if (complist.size()>0)
indent++;
for (int i = 0; i < complist.size(); i++)
{
UIComponent uicom = (UIComponent) complist.get(i);
printComponentTree(uicom);
if (i+1 == complist.size())
indent--;
}
}
public void printComponentInfo(UIComponent comp)
{
if (comp.getId() == null)
{
logger.debug("UIViewRoot" + " " + "(" + comp.getClass().getName() + ")");
}
else
{
logger.debug(getIndent() + "|");
logger.debug(getIndent() + comp.getId() + " " + "(" + comp.getClass().getName() + ")");
}
}
public String getIndent()
{
String indent = "";
for (int i=0; i<this.indent; i++)
{
indent += INDENT;
}
return indent;
}
}

View File

@@ -1,43 +1,43 @@
package org.alfresco.web.app.portlet;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.repository.User;
import org.apache.myfaces.portlet.DefaultViewSelector;
/**
* @author Kevin Roast
*/
public class AlfrescoDefaultViewSelector implements DefaultViewSelector
{
/**
* Select the appropriate view ID
*/
public String selectViewId(RenderRequest request, RenderResponse response) throws PortletException
{
User user = (User) request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER,
PortletSession.APPLICATION_SCOPE);
if (user != null && user.getUserName().equals(AuthenticationUtil.getGuestUserName()))
{
return FacesHelper.BROWSE_VIEW_ID;
}
else
{
return null;
}
}
/**
* @see org.apache.myfaces.portlet.DefaultViewSelector#setPortletContext(javax.portlet.PortletContext)
*/
public void setPortletContext(PortletContext portletContext)
{
}
}
package org.alfresco.web.app.portlet;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.repository.User;
import org.apache.myfaces.portlet.DefaultViewSelector;
/**
* @author Kevin Roast
*/
public class AlfrescoDefaultViewSelector implements DefaultViewSelector
{
/**
* Select the appropriate view ID
*/
public String selectViewId(RenderRequest request, RenderResponse response) throws PortletException
{
User user = (User) request.getPortletSession().getAttribute(AuthenticationHelper.AUTHENTICATION_USER,
PortletSession.APPLICATION_SCOPE);
if (user != null && user.getUserName().equals(AuthenticationUtil.getGuestUserName()))
{
return FacesHelper.BROWSE_VIEW_ID;
}
else
{
return null;
}
}
/**
* @see org.apache.myfaces.portlet.DefaultViewSelector#setPortletContext(javax.portlet.PortletContext)
*/
public void setPortletContext(PortletContext portletContext)
{
}
}

View File

@@ -1,97 +1,97 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.web.bean.repository.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This servlet filter is used to restrict direct URL access to administration
* resource in the web client, for example the admin and jBPM consoles.
*
* @author gavinc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class AdminAuthenticationFilter implements Filter
{
private static final Log logger = LogFactory.getLog(AdminAuthenticationFilter.class);
private FilterConfig config;
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest httpRequest = (HttpServletRequest)req;
HttpServletResponse httpResponse = (HttpServletResponse)res;
// The fact that this filter is being called means a request for a protected
// resource has taken place, check that the current user is in fact an
// administrator.
if (logger.isDebugEnabled())
logger.debug("Authorising request for protected resource: " + httpRequest.getRequestURI());
// there should be a user at this point so retrieve it
User user = AuthenticationHelper.getUser(this.config.getServletContext(), httpRequest, httpResponse);
// if the user is present check to see whether it is an admin user
boolean isAdmin = (user != null && user.isAdmin());
if (isAdmin)
{
if (logger.isDebugEnabled())
logger.debug("Current user has admin authority, allowing access.");
// continue filter chaining if current user is admin user
chain.doFilter(req, res);
}
else
{
// return the 401 Forbidden error as the current user is not an administrator
// if the response has already been committed there's nothing we can do but
// print out a warning
if (httpResponse.isCommitted() == false)
{
if (logger.isDebugEnabled())
logger.debug("Current user does not have admin authority, returning 401 Forbidden error...");
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
}
else
{
if (logger.isWarnEnabled())
logger.warn("Access denied to '" + httpRequest.getRequestURI() +
"'. The response has already been committed so a 401 Forbidden error could not be sent!");
}
}
}
/**
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig config) throws ServletException
{
this.config = config;
}
/**
* @see javax.servlet.Filter#destroy()
*/
public void destroy()
{
// nothing to do
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.web.bean.repository.User;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This servlet filter is used to restrict direct URL access to administration
* resource in the web client, for example the admin and jBPM consoles.
*
* @author gavinc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class AdminAuthenticationFilter implements Filter
{
private static final Log logger = LogFactory.getLog(AdminAuthenticationFilter.class);
private FilterConfig config;
/**
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest httpRequest = (HttpServletRequest)req;
HttpServletResponse httpResponse = (HttpServletResponse)res;
// The fact that this filter is being called means a request for a protected
// resource has taken place, check that the current user is in fact an
// administrator.
if (logger.isDebugEnabled())
logger.debug("Authorising request for protected resource: " + httpRequest.getRequestURI());
// there should be a user at this point so retrieve it
User user = AuthenticationHelper.getUser(this.config.getServletContext(), httpRequest, httpResponse);
// if the user is present check to see whether it is an admin user
boolean isAdmin = (user != null && user.isAdmin());
if (isAdmin)
{
if (logger.isDebugEnabled())
logger.debug("Current user has admin authority, allowing access.");
// continue filter chaining if current user is admin user
chain.doFilter(req, res);
}
else
{
// return the 401 Forbidden error as the current user is not an administrator
// if the response has already been committed there's nothing we can do but
// print out a warning
if (httpResponse.isCommitted() == false)
{
if (logger.isDebugEnabled())
logger.debug("Current user does not have admin authority, returning 401 Forbidden error...");
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
}
else
{
if (logger.isWarnEnabled())
logger.warn("Access denied to '" + httpRequest.getRequestURI() +
"'. The response has already been committed so a 401 Forbidden error could not be sent!");
}
}
}
/**
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig config) throws ServletException
{
this.config = config;
}
/**
* @see javax.servlet.Filter#destroy()
*/
public void destroy()
{
// nothing to do
}
}

View File

@@ -1,56 +1,56 @@
package org.alfresco.web.app.servlet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.alfresco.web.scripts.servlet.X509ServletFilterBase;
import javax.servlet.*;
import java.io.IOException;
import java.util.Properties;
/**
* The AlfrescoX509ServletFilter implements the checkEnforce method of the X509ServletFilterBase.
* This allows the configuration of X509 authentication to be toggled on/off through a
* configuration outside of the web.xml.
**/
public class AlfrescoX509ServletFilter extends X509ServletFilterBase
{
private static final String BEAN_GLOBAL_PROPERTIES = "global-properties";
private static final String SECURE_COMMS = "solr.secureComms";
private static Log logger = LogFactory.getLog(AlfrescoX509ServletFilter.class);
@Override
protected boolean checkEnforce(ServletContext servletContext) throws IOException
{
/*
* Get the secureComms setting from the global properties bean.
*/
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
Properties globalProperties = (Properties) wc.getBean(BEAN_GLOBAL_PROPERTIES);
String prop = globalProperties.getProperty(SECURE_COMMS);
if(logger.isDebugEnabled())
{
logger.debug("secureComms:"+prop);
}
/*
* Return true or false based on the property. This will switch on/off X509 enforcement in the X509ServletFilterBase.
*/
if (prop == null || "none".equals(prop))
{
return false;
}
else
{
return true;
}
}
package org.alfresco.web.app.servlet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.alfresco.web.scripts.servlet.X509ServletFilterBase;
import javax.servlet.*;
import java.io.IOException;
import java.util.Properties;
/**
* The AlfrescoX509ServletFilter implements the checkEnforce method of the X509ServletFilterBase.
* This allows the configuration of X509 authentication to be toggled on/off through a
* configuration outside of the web.xml.
**/
public class AlfrescoX509ServletFilter extends X509ServletFilterBase
{
private static final String BEAN_GLOBAL_PROPERTIES = "global-properties";
private static final String SECURE_COMMS = "solr.secureComms";
private static Log logger = LogFactory.getLog(AlfrescoX509ServletFilter.class);
@Override
protected boolean checkEnforce(ServletContext servletContext) throws IOException
{
/*
* Get the secureComms setting from the global properties bean.
*/
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
Properties globalProperties = (Properties) wc.getBean(BEAN_GLOBAL_PROPERTIES);
String prop = globalProperties.getProperty(SECURE_COMMS);
if(logger.isDebugEnabled())
{
logger.debug("secureComms:"+prop);
}
/*
* Return true or false based on the property. This will switch on/off X509 enforcement in the X509ServletFilterBase.
*/
if (prop == null || "none".equals(prop))
{
return false;
}
else
{
return true;
}
}
}

View File

@@ -1,9 +1,9 @@
package org.alfresco.web.app.servlet;
/**
* @author Kevin Roast
*/
public enum AuthenticationStatus
{
Success, Failure, Guest;
}
package org.alfresco.web.app.servlet;
/**
* @author Kevin Roast
*/
public enum AuthenticationStatus
{
Success, Failure, Guest;
}

View File

@@ -1,430 +1,430 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.net.SocketException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.repo.web.util.HttpRangeProcessor;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.apache.commons.logging.Log;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.surf.util.URLEncoder;
import org.springframework.extensions.webscripts.ui.common.StringUtils;
/**
* Base class for the download content servlets. Provides common
* processing for the request.
*
* @see org.alfresco.web.app.servlet.DownloadContentServlet
* @see org.alfresco.web.app.servlet.GuestDownloadContentServlet
*
* @author Kevin Roast
* @author gavinc
*/
public abstract class BaseDownloadContentServlet extends BaseServlet
{
private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
private static final long serialVersionUID = -4558907921887235967L;
private static final String POWER_POINT_DOCUMENT_MIMETYPE = "application/vnd.ms-powerpoint";
private static final String POWER_POINT_2007_DOCUMENT_MIMETYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
private static final String HEADER_CONTENT_RANGE = "Content-Range";
private static final String HEADER_CONTENT_LENGTH = "Content-Length";
private static final String HEADER_ACCEPT_RANGES = "Accept-Ranges";
private static final String HEADER_RANGE = "Range";
private static final String HEADER_ETAG = "ETag";
private static final String HEADER_CACHE_CONTROL = "Cache-Control";
private static final String HEADER_LAST_MODIFIED = "Last-Modified";
private static final String HEADER_USER_AGENT = "User-Agent";
private static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";
protected static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing";
protected static final String MSG_ERROR_NOT_FOUND = "error_not_found";
protected static final String URL_DIRECT = "d";
protected static final String URL_DIRECT_LONG = "direct";
protected static final String URL_ATTACH = "a";
protected static final String URL_ATTACH_LONG = "attach";
protected static final String ARG_PROPERTY = "property";
protected static final String ARG_PATH = "path";
/**
* Gets the logger to use for this request.
* <p>
* This will show all debug entries from this class as though they
* came from the subclass.
*
* @return The logger
*/
protected abstract Log getLogger();
/**
* Processes the download request using the current context i.e. no authentication checks are made, it is presumed
* they have already been done.
*
* @param req
* The HTTP request
* @param res
* The HTTP response
* @param allowLogIn
* Indicates whether guest users without access to the content should be redirected to the log in page. If
* <code>false</code>, a status 403 forbidden page is displayed instead.
*/
protected void processDownloadRequest(HttpServletRequest req, HttpServletResponse res,
boolean allowLogIn, boolean transmitContent)
throws ServletException, IOException
{
Log logger = getLogger();
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Processing URL: " + uri +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
t.nextToken(); // skip servlet name
// attachment mode (either 'attach' or 'direct')
String attachToken = t.nextToken();
boolean attachment = URL_ATTACH.equals(attachToken) || URL_ATTACH_LONG.equals(attachToken);
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
// get or calculate the noderef and filename to download as
NodeRef nodeRef;
String filename;
// do we have a path parameter instead of a NodeRef?
String path = req.getParameter(ARG_PATH);
if (path != null && path.length() != 0)
{
// process the name based path to resolve the NodeRef and the Filename element
try
{
PathRefInfo pathInfo = resolveNamePath(getServletContext(), path);
nodeRef = pathInfo.NodeRef;
filename = pathInfo.Filename;
}
catch (IllegalArgumentException e)
{
Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
HttpServletResponse.SC_NOT_FOUND, logger);
return;
}
}
else
{
// a NodeRef must have been specified if no path has been found
if (tokenCount < 6)
{
throw new IllegalArgumentException("Download URL did not contain all required args: " + uri);
}
// assume 'workspace' or other NodeRef based protocol for remaining URL elements
StoreRef storeRef = new StoreRef(URLDecoder.decode(t.nextToken()), URLDecoder.decode(t.nextToken()));
String id = URLDecoder.decode(t.nextToken());
// build noderef from the appropriate URL elements
nodeRef = new NodeRef(storeRef, id);
if (tokenCount > 6)
{
// found additional relative path elements i.e. noderefid/images/file.txt
// this allows a url to reference siblings nodes via a cm:name based relative path
// solves the issue with opening HTML content containing relative URLs in HREF or IMG tags etc.
List<String> paths = new ArrayList<String>(tokenCount - 5);
while (t.hasMoreTokens())
{
paths.add(URLDecoder.decode(t.nextToken()));
}
filename = paths.get(paths.size() - 1);
try
{
NodeRef parentRef = serviceRegistry.getNodeService().getPrimaryParent(nodeRef).getParentRef();
FileInfo fileInfo = serviceRegistry.getFileFolderService().resolveNamePath(parentRef, paths);
nodeRef = fileInfo.getNodeRef();
}
catch (FileNotFoundException e)
{
Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
HttpServletResponse.SC_NOT_FOUND, logger);
return;
}
}
else
{
// filename is last remaining token
filename = t.nextToken();
}
}
// get qualified of the property to get content from - default to ContentModel.PROP_CONTENT
QName propertyQName = ContentModel.PROP_CONTENT;
String property = req.getParameter(ARG_PROPERTY);
if (property != null && property.length() != 0)
{
propertyQName = QName.createQName(property);
}
if (logger.isDebugEnabled())
{
logger.debug("Found NodeRef: " + nodeRef);
logger.debug("Will use filename: " + filename);
logger.debug("For property: " + propertyQName);
logger.debug("With attachment mode: " + attachment);
}
// get the services we need to retrieve the content
NodeService nodeService = serviceRegistry.getNodeService();
ContentService contentService = serviceRegistry.getContentService();
// Check that the node still exists
if (!nodeService.exists(nodeRef))
{
Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
HttpServletResponse.SC_NOT_FOUND, logger);
return;
}
try
{
// check that the user has at least READ_CONTENT access - else redirect to an error or login page
if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, allowLogIn))
{
return;
}
// check If-Modified-Since header and set Last-Modified header as appropriate
Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
if (modified != null)
{
long modifiedSince = req.getDateHeader(HEADER_IF_MODIFIED_SINCE);
if (modifiedSince > 0L)
{
// round the date to the ignore millisecond value which is not supplied by header
long modDate = (modified.getTime() / 1000L) * 1000L;
if (modDate <= modifiedSince)
{
if (logger.isDebugEnabled())
logger.debug("Returning 304 Not Modified.");
res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
}
res.setDateHeader(HEADER_LAST_MODIFIED, modified.getTime());
res.setHeader(HEADER_CACHE_CONTROL, "must-revalidate, max-age=0");
res.setHeader(HEADER_ETAG, "\"" + Long.toString(modified.getTime()) + "\"");
}
if (attachment == true)
{
setHeaderContentDisposition(req, res, filename);
}
// get the content reader
ContentReader reader = contentService.getReader(nodeRef, propertyQName);
// ensure that it is safe to use
reader = FileContentReader.getSafeContentReader(
reader,
Application.getMessage(req.getSession(), MSG_ERROR_CONTENT_MISSING),
nodeRef, reader);
String mimetype = reader.getMimetype();
// fall back if unable to resolve mimetype property
if (mimetype == null || mimetype.length() == 0)
{
MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
mimetype = MIMETYPE_OCTET_STREAM;
int extIndex = filename.lastIndexOf('.');
if (extIndex != -1)
{
String ext = filename.substring(extIndex + 1);
mimetype = mimetypeMap.getMimetype(ext);
}
}
// explicitly set the content disposition header if the content is powerpoint
if (!attachment && (mimetype.equals(POWER_POINT_2007_DOCUMENT_MIMETYPE) ||
mimetype.equals(POWER_POINT_DOCUMENT_MIMETYPE)))
{
setHeaderContentDisposition(req, res, filename);
}
// get the content and stream directly to the response output stream
// assuming the repo is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
res.setHeader(HEADER_ACCEPT_RANGES, "bytes");
// for a GET request, transmit the content else just the headers are sent
if (transmitContent)
{
try
{
boolean processedRange = false;
String range = req.getHeader(HEADER_CONTENT_RANGE);
if (range == null)
{
range = req.getHeader(HEADER_RANGE);
}
if (range != null)
{
if (logger.isDebugEnabled())
logger.debug("Found content range header: " + range);
// ensure the range header is starts with "bytes=" and process the range(s)
if (range.length() > 6)
{
HttpRangeProcessor rangeProcessor = new HttpRangeProcessor(contentService);
processedRange = rangeProcessor.processRange(
res, reader, range.substring(6), nodeRef, propertyQName,
mimetype, req.getHeader(HEADER_USER_AGENT));
}
}
if (processedRange == false)
{
if (logger.isDebugEnabled())
logger.debug("Sending complete file content...");
// set mimetype for the content and the character encoding for the stream
res.setContentType(mimetype);
res.setCharacterEncoding(reader.getEncoding());
// MNT-10642 Alfresco Explorer has javascript vulnerability opening HTML files
if (req.getRequestURI().contains("/d/d/") && (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml") || mimetype.equals("text/xml")))
{
String content = reader.getContentString();
if (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml"))
{
// process with HTML stripper
content = StringUtils.stripUnsafeHTMLTags(content, false);
}
else if (mimetype.equals("text/xml") && mimetype.equals("text/x-component"))
{
// IE supports "behaviour" which means that css can load a .htc file that could
// contain XSS code in the form of jscript, vbscript etc, to stop it form being
// evaluated we set the contient type to text/plain
res.setContentType("text/plain");
}
String encoding = reader.getEncoding();
byte[] bytes = encoding != null ? content.getBytes(encoding) : content.getBytes();
res.setContentLength(bytes.length);
res.getOutputStream().write(bytes);
return;
}
// return the complete entity range
long size = reader.getSize();
res.setHeader(HEADER_CONTENT_RANGE, "bytes 0-" + Long.toString(size-1L) + "/" + Long.toString(size));
res.setHeader(HEADER_CONTENT_LENGTH, Long.toString(size));
reader.getContent( res.getOutputStream() );
}
}
catch (SocketException e1)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isDebugEnabled())
logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
catch (ContentIOException e2)
{
if (logger.isInfoEnabled())
logger.info("Failed stream read:\n\tnode: " + nodeRef + " due to: " + e2.getMessage());
}
catch (Throwable err)
{
if (err.getCause() instanceof SocketException)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isDebugEnabled())
logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
else throw err;
}
}
else
{
if (logger.isDebugEnabled())
logger.debug("HEAD request processed - no content sent.");
res.getOutputStream().close();
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during download content servlet processing: " + err.getMessage(), err);
}
}
private void setHeaderContentDisposition(HttpServletRequest req, HttpServletResponse res, String filename)
{
// set header based on filename - will force a Save As from the browse if it doesn't recognise it
// this is better than the default response of the browser trying to display the contents
// IE requires that "Content-Disposition" header in case of "attachment" type should include
// "filename" part. See MNT-9900
String userAgent = req.getHeader(HEADER_USER_AGENT);
if (userAgent != null && (userAgent.toLowerCase().contains("firefox") || userAgent.toLowerCase().contains("safari")))
{
res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + URLDecoder.decode(filename) + "\"");
}
else
{
res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"");
}
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
*
* @param pattern The pattern to use for the URL
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
protected final static String generateUrl(String pattern, NodeRef ref, String name)
{
return MessageFormat.format(pattern, new Object[] {
ref.getStoreRef().getProtocol(),
ref.getStoreRef().getIdentifier(),
ref.getId(),
URLEncoder.encode(name) } );
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.net.SocketException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.repo.web.util.HttpRangeProcessor;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application;
import org.apache.commons.logging.Log;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.surf.util.URLEncoder;
import org.springframework.extensions.webscripts.ui.common.StringUtils;
/**
* Base class for the download content servlets. Provides common
* processing for the request.
*
* @see org.alfresco.web.app.servlet.DownloadContentServlet
* @see org.alfresco.web.app.servlet.GuestDownloadContentServlet
*
* @author Kevin Roast
* @author gavinc
*/
public abstract class BaseDownloadContentServlet extends BaseServlet
{
private static final String HEADER_IF_MODIFIED_SINCE = "If-Modified-Since";
private static final long serialVersionUID = -4558907921887235967L;
private static final String POWER_POINT_DOCUMENT_MIMETYPE = "application/vnd.ms-powerpoint";
private static final String POWER_POINT_2007_DOCUMENT_MIMETYPE = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
private static final String HEADER_CONTENT_RANGE = "Content-Range";
private static final String HEADER_CONTENT_LENGTH = "Content-Length";
private static final String HEADER_ACCEPT_RANGES = "Accept-Ranges";
private static final String HEADER_RANGE = "Range";
private static final String HEADER_ETAG = "ETag";
private static final String HEADER_CACHE_CONTROL = "Cache-Control";
private static final String HEADER_LAST_MODIFIED = "Last-Modified";
private static final String HEADER_USER_AGENT = "User-Agent";
private static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";
protected static final String MSG_ERROR_CONTENT_MISSING = "error_content_missing";
protected static final String MSG_ERROR_NOT_FOUND = "error_not_found";
protected static final String URL_DIRECT = "d";
protected static final String URL_DIRECT_LONG = "direct";
protected static final String URL_ATTACH = "a";
protected static final String URL_ATTACH_LONG = "attach";
protected static final String ARG_PROPERTY = "property";
protected static final String ARG_PATH = "path";
/**
* Gets the logger to use for this request.
* <p>
* This will show all debug entries from this class as though they
* came from the subclass.
*
* @return The logger
*/
protected abstract Log getLogger();
/**
* Processes the download request using the current context i.e. no authentication checks are made, it is presumed
* they have already been done.
*
* @param req
* The HTTP request
* @param res
* The HTTP response
* @param allowLogIn
* Indicates whether guest users without access to the content should be redirected to the log in page. If
* <code>false</code>, a status 403 forbidden page is displayed instead.
*/
protected void processDownloadRequest(HttpServletRequest req, HttpServletResponse res,
boolean allowLogIn, boolean transmitContent)
throws ServletException, IOException
{
Log logger = getLogger();
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Processing URL: " + uri +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
t.nextToken(); // skip servlet name
// attachment mode (either 'attach' or 'direct')
String attachToken = t.nextToken();
boolean attachment = URL_ATTACH.equals(attachToken) || URL_ATTACH_LONG.equals(attachToken);
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
// get or calculate the noderef and filename to download as
NodeRef nodeRef;
String filename;
// do we have a path parameter instead of a NodeRef?
String path = req.getParameter(ARG_PATH);
if (path != null && path.length() != 0)
{
// process the name based path to resolve the NodeRef and the Filename element
try
{
PathRefInfo pathInfo = resolveNamePath(getServletContext(), path);
nodeRef = pathInfo.NodeRef;
filename = pathInfo.Filename;
}
catch (IllegalArgumentException e)
{
Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
HttpServletResponse.SC_NOT_FOUND, logger);
return;
}
}
else
{
// a NodeRef must have been specified if no path has been found
if (tokenCount < 6)
{
throw new IllegalArgumentException("Download URL did not contain all required args: " + uri);
}
// assume 'workspace' or other NodeRef based protocol for remaining URL elements
StoreRef storeRef = new StoreRef(URLDecoder.decode(t.nextToken()), URLDecoder.decode(t.nextToken()));
String id = URLDecoder.decode(t.nextToken());
// build noderef from the appropriate URL elements
nodeRef = new NodeRef(storeRef, id);
if (tokenCount > 6)
{
// found additional relative path elements i.e. noderefid/images/file.txt
// this allows a url to reference siblings nodes via a cm:name based relative path
// solves the issue with opening HTML content containing relative URLs in HREF or IMG tags etc.
List<String> paths = new ArrayList<String>(tokenCount - 5);
while (t.hasMoreTokens())
{
paths.add(URLDecoder.decode(t.nextToken()));
}
filename = paths.get(paths.size() - 1);
try
{
NodeRef parentRef = serviceRegistry.getNodeService().getPrimaryParent(nodeRef).getParentRef();
FileInfo fileInfo = serviceRegistry.getFileFolderService().resolveNamePath(parentRef, paths);
nodeRef = fileInfo.getNodeRef();
}
catch (FileNotFoundException e)
{
Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
HttpServletResponse.SC_NOT_FOUND, logger);
return;
}
}
else
{
// filename is last remaining token
filename = t.nextToken();
}
}
// get qualified of the property to get content from - default to ContentModel.PROP_CONTENT
QName propertyQName = ContentModel.PROP_CONTENT;
String property = req.getParameter(ARG_PROPERTY);
if (property != null && property.length() != 0)
{
propertyQName = QName.createQName(property);
}
if (logger.isDebugEnabled())
{
logger.debug("Found NodeRef: " + nodeRef);
logger.debug("Will use filename: " + filename);
logger.debug("For property: " + propertyQName);
logger.debug("With attachment mode: " + attachment);
}
// get the services we need to retrieve the content
NodeService nodeService = serviceRegistry.getNodeService();
ContentService contentService = serviceRegistry.getContentService();
// Check that the node still exists
if (!nodeService.exists(nodeRef))
{
Application.handleSystemError(getServletContext(), req, res, MSG_ERROR_NOT_FOUND,
HttpServletResponse.SC_NOT_FOUND, logger);
return;
}
try
{
// check that the user has at least READ_CONTENT access - else redirect to an error or login page
if (!checkAccess(req, res, nodeRef, PermissionService.READ_CONTENT, allowLogIn))
{
return;
}
// check If-Modified-Since header and set Last-Modified header as appropriate
Date modified = (Date)nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIED);
if (modified != null)
{
long modifiedSince = req.getDateHeader(HEADER_IF_MODIFIED_SINCE);
if (modifiedSince > 0L)
{
// round the date to the ignore millisecond value which is not supplied by header
long modDate = (modified.getTime() / 1000L) * 1000L;
if (modDate <= modifiedSince)
{
if (logger.isDebugEnabled())
logger.debug("Returning 304 Not Modified.");
res.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
}
res.setDateHeader(HEADER_LAST_MODIFIED, modified.getTime());
res.setHeader(HEADER_CACHE_CONTROL, "must-revalidate, max-age=0");
res.setHeader(HEADER_ETAG, "\"" + Long.toString(modified.getTime()) + "\"");
}
if (attachment == true)
{
setHeaderContentDisposition(req, res, filename);
}
// get the content reader
ContentReader reader = contentService.getReader(nodeRef, propertyQName);
// ensure that it is safe to use
reader = FileContentReader.getSafeContentReader(
reader,
Application.getMessage(req.getSession(), MSG_ERROR_CONTENT_MISSING),
nodeRef, reader);
String mimetype = reader.getMimetype();
// fall back if unable to resolve mimetype property
if (mimetype == null || mimetype.length() == 0)
{
MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
mimetype = MIMETYPE_OCTET_STREAM;
int extIndex = filename.lastIndexOf('.');
if (extIndex != -1)
{
String ext = filename.substring(extIndex + 1);
mimetype = mimetypeMap.getMimetype(ext);
}
}
// explicitly set the content disposition header if the content is powerpoint
if (!attachment && (mimetype.equals(POWER_POINT_2007_DOCUMENT_MIMETYPE) ||
mimetype.equals(POWER_POINT_DOCUMENT_MIMETYPE)))
{
setHeaderContentDisposition(req, res, filename);
}
// get the content and stream directly to the response output stream
// assuming the repo is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
res.setHeader(HEADER_ACCEPT_RANGES, "bytes");
// for a GET request, transmit the content else just the headers are sent
if (transmitContent)
{
try
{
boolean processedRange = false;
String range = req.getHeader(HEADER_CONTENT_RANGE);
if (range == null)
{
range = req.getHeader(HEADER_RANGE);
}
if (range != null)
{
if (logger.isDebugEnabled())
logger.debug("Found content range header: " + range);
// ensure the range header is starts with "bytes=" and process the range(s)
if (range.length() > 6)
{
HttpRangeProcessor rangeProcessor = new HttpRangeProcessor(contentService);
processedRange = rangeProcessor.processRange(
res, reader, range.substring(6), nodeRef, propertyQName,
mimetype, req.getHeader(HEADER_USER_AGENT));
}
}
if (processedRange == false)
{
if (logger.isDebugEnabled())
logger.debug("Sending complete file content...");
// set mimetype for the content and the character encoding for the stream
res.setContentType(mimetype);
res.setCharacterEncoding(reader.getEncoding());
// MNT-10642 Alfresco Explorer has javascript vulnerability opening HTML files
if (req.getRequestURI().contains("/d/d/") && (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml") || mimetype.equals("text/xml")))
{
String content = reader.getContentString();
if (mimetype.equals("text/html") || mimetype.equals("application/xhtml+xml"))
{
// process with HTML stripper
content = StringUtils.stripUnsafeHTMLTags(content, false);
}
else if (mimetype.equals("text/xml") && mimetype.equals("text/x-component"))
{
// IE supports "behaviour" which means that css can load a .htc file that could
// contain XSS code in the form of jscript, vbscript etc, to stop it form being
// evaluated we set the contient type to text/plain
res.setContentType("text/plain");
}
String encoding = reader.getEncoding();
byte[] bytes = encoding != null ? content.getBytes(encoding) : content.getBytes();
res.setContentLength(bytes.length);
res.getOutputStream().write(bytes);
return;
}
// return the complete entity range
long size = reader.getSize();
res.setHeader(HEADER_CONTENT_RANGE, "bytes 0-" + Long.toString(size-1L) + "/" + Long.toString(size));
res.setHeader(HEADER_CONTENT_LENGTH, Long.toString(size));
reader.getContent( res.getOutputStream() );
}
}
catch (SocketException e1)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isDebugEnabled())
logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
catch (ContentIOException e2)
{
if (logger.isInfoEnabled())
logger.info("Failed stream read:\n\tnode: " + nodeRef + " due to: " + e2.getMessage());
}
catch (Throwable err)
{
if (err.getCause() instanceof SocketException)
{
// the client cut the connection - our mission was accomplished apart from a little error message
if (logger.isDebugEnabled())
logger.debug("Client aborted stream read:\n\tnode: " + nodeRef + "\n\tcontent: " + reader);
}
else throw err;
}
}
else
{
if (logger.isDebugEnabled())
logger.debug("HEAD request processed - no content sent.");
res.getOutputStream().close();
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during download content servlet processing: " + err.getMessage(), err);
}
}
private void setHeaderContentDisposition(HttpServletRequest req, HttpServletResponse res, String filename)
{
// set header based on filename - will force a Save As from the browse if it doesn't recognise it
// this is better than the default response of the browser trying to display the contents
// IE requires that "Content-Disposition" header in case of "attachment" type should include
// "filename" part. See MNT-9900
String userAgent = req.getHeader(HEADER_USER_AGENT);
if (userAgent != null && (userAgent.toLowerCase().contains("firefox") || userAgent.toLowerCase().contains("safari")))
{
res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + URLDecoder.decode(filename) + "\"");
}
else
{
res.setHeader(HEADER_CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"");
}
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
*
* @param pattern The pattern to use for the URL
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
protected final static String generateUrl(String pattern, NodeRef ref, String name)
{
return MessageFormat.format(pattern, new Object[] {
ref.getStoreRef().getProtocol(),
ref.getStoreRef().getIdentifier(),
ref.getId(),
URLEncoder.encode(name) } );
}
}

View File

@@ -1,481 +1,481 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginOutcomeBean;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Base servlet class containing useful constant values and common methods for Alfresco servlets.
*
* @author Kevin Roast
*/
public abstract class BaseServlet extends HttpServlet
{
private static final long serialVersionUID = -826295358696861789L;
public static final String FACES_SERVLET = "/faces";
public static final String KEY_STORE = "store";
public static final String KEY_ROOT_PATH = "rootPath";
/** an existing Ticket can be passed to most servlet for non-session based authentication */
private static final String ARG_TICKET = "ticket";
/** forcing guess access is available on most servlets */
private static final String ARG_GUEST = "guest";
private static final String MSG_ERROR_PERMISSIONS = "error_permissions";
/** list of valid JSPs for redirect after a clean login */
// TODO: make this list configurable
private static Set<String> validRedirectJSPs = new HashSet<String>();
static
{
validRedirectJSPs.add("/jsp/browse/browse.jsp");
validRedirectJSPs.add("/jsp/admin/admin-console.jsp");
validRedirectJSPs.add("/jsp/admin/avm-console.jsp");
validRedirectJSPs.add("/jsp/admin/node-browser.jsp");
validRedirectJSPs.add("/jsp/admin/store-browser.jsp");
validRedirectJSPs.add("/jsp/users/user-console.jsp");
validRedirectJSPs.add("/jsp/categories/categories.jsp");
validRedirectJSPs.add("/jsp/dialog/about.jsp");
validRedirectJSPs.add("/jsp/search/advanced-search.jsp");
validRedirectJSPs.add("/jsp/admin/system-info.jsp");
validRedirectJSPs.add("/jsp/forums/forums.jsp");
validRedirectJSPs.add("/jsp/users/users.jsp");
validRedirectJSPs.add("/jsp/trashcan/trash-list.jsp");
}
private static Log logger = LogFactory.getLog(BaseServlet.class);
/**
* Return the ServiceRegistry helper instance
*
* @param sc ServletContext
*
* @return ServiceRegistry
*/
public static ServiceRegistry getServiceRegistry(ServletContext sc)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
return (ServiceRegistry)wc.getBean(ServiceRegistry.SERVICE_REGISTRY);
}
/**
* Perform an authentication for the servlet request URI. Processing any "ticket" or
* "guest" URL arguments.
*
* @return AuthenticationStatus
*
* @throws IOException
*/
public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res)
throws IOException
{
return servletAuthenticate(req, res, true);
}
/**
* Perform an authentication for the servlet request URI. Processing any "ticket" or
* "guest" URL arguments.
*
* @return AuthenticationStatus
*
* @throws IOException
*/
public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res,
boolean redirectToLoginPage) throws IOException
{
AuthenticationStatus status;
// see if a ticket or a force Guest parameter has been supplied
String ticket = req.getParameter(ARG_TICKET);
if (ticket != null && ticket.length() != 0)
{
status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
}
else
{
boolean forceGuest = false;
String guest = req.getParameter(ARG_GUEST);
if (guest != null)
{
forceGuest = Boolean.parseBoolean(guest);
}
status = AuthenticationHelper.authenticate(getServletContext(), req, res, forceGuest);
}
if (status == AuthenticationStatus.Failure && redirectToLoginPage)
{
// authentication failed - now need to display the login page to the user, if asked to
redirectToLoginPage(req, res, getServletContext());
}
return status;
}
/**
* Check the user has the given permission on the given node. If they do not either force a log on if this is a guest
* user or forward to an error page.
*
* @param req
* the request
* @param res
* the response
* @param nodeRef
* the node in question
* @param allowLogIn
* Indicates whether guest users without access to the node should be redirected to the log in page. If
* <code>false</code>, a status 403 forbidden page is displayed instead.
* @return <code>true</code>, if the user has access
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws ServletException
* On other errors
*/
public boolean checkAccess(HttpServletRequest req, HttpServletResponse res, NodeRef nodeRef, String permission,
boolean allowLogIn) throws IOException, ServletException
{
ServletContext sc = getServletContext();
ServiceRegistry serviceRegistry = getServiceRegistry(sc);
PermissionService permissionService = serviceRegistry.getPermissionService();
// check that the user has the permission
if (permissionService.hasPermission(nodeRef, permission) == AccessStatus.DENIED)
{
if (logger.isDebugEnabled())
logger.debug("User does not have " + permission + " permission for NodeRef: " + nodeRef.toString());
if (allowLogIn && serviceRegistry.getAuthorityService().hasGuestAuthority())
{
if (logger.isDebugEnabled())
logger.debug("Redirecting to login page...");
redirectToLoginPage(req, res, sc);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Forwarding to error page...");
Application
.handleSystemError(sc, req, res, MSG_ERROR_PERMISSIONS, HttpServletResponse.SC_FORBIDDEN, logger);
}
return false;
}
return true;
}
/**
* Redirect to the Login page - saving the current URL which can be redirected back later
* once the user has successfully completed the authentication process.
*/
public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc)
throws IOException
{
redirectToLoginPage(req, res, sc, AuthenticationHelper.getRemoteUserMapper(sc) == null);
}
/**
* Redirect to the Login page - saving the current URL which can be redirected back later
* once the user has successfully completed the authentication process.
* @param sendRedirect allow a redirect status code to be set? If <code>false</code> redirect
* will be via markup rather than status code (to allow the status code to be used for handshake
* responses etc.
*/
public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc, boolean sendRedirect)
throws IOException
{
// Pass the full requested URL as a parameter so the login page knows where to redirect to later
final String uri = req.getRequestURI();
String redirectURL = uri;
// authentication failed - so end servlet execution and redirect to login page
if (WebApplicationContextUtils.getRequiredWebApplicationContext(sc).containsBean(Application.BEAN_CONFIG_SERVICE))
{
StringBuilder redirect = new StringBuilder(128)
.append(req.getContextPath()).append(FACES_SERVLET).append(Application.getLoginPage(sc));
// if we find a JSF servlet reference in the URI then we need to check if the rest of the
// JSP specified is valid for a redirect operation after Login has occured.
int jspIndex;
if (uri.indexOf(req.getContextPath() + FACES_SERVLET) == -1
|| uri.length() > (jspIndex = uri.indexOf(BaseServlet.FACES_SERVLET) + BaseServlet.FACES_SERVLET.length())
&& BaseServlet.validRedirectJSP(uri.substring(jspIndex)))
{
if (redirect.indexOf("?") == -1)
{
redirect.append('?');
}
else
{
redirect.append('&');
}
redirect.append(LoginOutcomeBean.PARAM_REDIRECT_URL);
redirect.append('=');
String url = uri;
// Append the query string if necessary
String queryString = req.getQueryString();
if (queryString != null)
{
// Strip out leading ticket arguments
queryString = queryString.replaceAll("(?<=^|&)" + ARG_TICKET + "(=[^&=]*)?&", "");
// Strip out trailing ticket arguments
queryString = queryString.replaceAll("(^|&)" + ARG_TICKET + "(=[^&=]*)?(?=&|$)", "");
if (queryString.length() != 0)
{
url += "?" + queryString;
}
}
redirect.append(URLEncoder.encode(url, "UTF-8"));
}
redirectURL = redirect.toString();
}
// If external authentication isn't in use (e.g. proxied share authentication), it's safe to return a redirect to the client
if (sendRedirect)
{
res.sendRedirect(redirectURL);
}
// Otherwise, we must signal to the client with an unauthorized status code and rely on a browser refresh to do
// the redirect for failover login (as we do with NTLM, Kerberos)
else
{
res.setContentType("text/html; charset=UTF-8");
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
final PrintWriter out = res.getWriter();
out.println("<html><head>");
out.println("<meta http-equiv=\"Refresh\" content=\"0; url=" + redirectURL + "\">");
out.println("</head><body><p>Please <a href=\"" + redirectURL + "\">log in</a>.</p>");
out.println("</body></html>");
out.close();
}
}
/**
* Apply the headers required to disallow caching of the response in the browser
*/
public static void setNoCacheHeaders(HttpServletResponse res)
{
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Pragma", "no-cache");
}
/**
* Returns true if the specified JSP file is valid for a redirect after login.
* Only a specific sub-set of the available JSPs are valid to jump directly too after a
* clean login attempt - e.g. those that do not require JSF bean context setup. This is
* a limitation of the JSP architecture. The ExternalAccessServlet provides a mechanism to
* setup the JSF bean context directly for some specific cases.
*
* @param jsp Filename of JSP to check, for example "/jsp/browse/browse.jsp"
*
* @return true if the JSP is in the list of valid direct URLs, false otherwise
*/
public static boolean validRedirectJSP(String jsp)
{
return validRedirectJSPs.contains(jsp);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context Faces context
* @param args The elements of the path to lookup
*/
public static NodeRef resolveWebDAVPath(FacesContext context, String[] args)
{
WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, true);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context Faces context
* @param args The elements of the path to lookup
* @param decode True to decode the arg from UTF-8 format, false for no decoding
*/
public static NodeRef resolveWebDAVPath(FacesContext context, String[] args, boolean decode)
{
WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, decode);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context ServletContext context
* @param args The elements of the path to lookup
*/
public static NodeRef resolveWebDAVPath(ServletContext context, String[] args)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, true);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context ServletContext context
* @param args The elements of the path to lookup
* @param decode True to decode the arg from UTF-8 format, false for no decoding
*/
public static NodeRef resolveWebDAVPath(ServletContext context, String[] args, boolean decode)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, decode);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param wc WebApplicationContext Context
* @param args The elements of the path to lookup
* @param decode True to decode the arg from UTF-8 format, false for no decoding
*/
private static NodeRef resolveWebDAVPath(final WebApplicationContext wc, final String[] args, final boolean decode)
{
return AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
{
public NodeRef doWork() throws Exception
{
NodeRef nodeRef = null;
List<String> paths = new ArrayList<String>(args.length - 1);
FileInfo file = null;
try
{
// create a list of path elements (decode the URL as we go)
for (int x = 1; x < args.length; x++)
{
paths.add(decode ? URLDecoder.decode(args[x]) : args[x]);
}
if (logger.isDebugEnabled())
logger.debug("Attempting to resolve webdav path: " + paths);
// get the company home node to start the search from
nodeRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
TenantService tenantService = (TenantService)wc.getBean("tenantService");
if (tenantService != null && tenantService.isEnabled())
{
if (logger.isDebugEnabled())
logger.debug("MT is enabled.");
NodeService nodeService = (NodeService) wc.getBean("NodeService");
SearchService searchService = (SearchService) wc.getBean("SearchService");
NamespaceService namespaceService = (NamespaceService) wc.getBean("NamespaceService");
// TODO: since these constants are used more widely than just the WebDAVServlet,
// they should be defined somewhere other than in that servlet
String rootPath = wc.getServletContext().getInitParameter(BaseServlet.KEY_ROOT_PATH);
// note: rootNodeRef is required (for storeRef part)
nodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, nodeRef);
}
if (paths.size() != 0)
{
FileFolderService ffs = (FileFolderService)wc.getBean("FileFolderService");
file = ffs.resolveNamePath(nodeRef, paths);
nodeRef = file.getNodeRef();
}
if (logger.isDebugEnabled())
logger.debug("Resolved webdav path to NodeRef: " + nodeRef);
}
catch (FileNotFoundException fne)
{
if (logger.isWarnEnabled())
logger.warn("Failed to resolve webdav path", fne);
nodeRef = null;
}
return nodeRef;
}
}, AuthenticationUtil.getSystemUserName());
}
/**
* Resolve a name based into a NodeRef and Filename string
*
* @param sc ServletContext
* @param path 'cm:name' based path using the '/' character as a separator
*
* @return PathRefInfo structure containing the resolved NodeRef and filename
*
* @throws IllegalArgumentException
*/
public final static PathRefInfo resolveNamePath(ServletContext sc, String path)
{
StringTokenizer t = new StringTokenizer(path, "/");
int tokenCount = t.countTokens();
String[] elements = new String[tokenCount];
for (int i=0; i<tokenCount; i++)
{
elements[i] = t.nextToken();
}
// process name based path tokens using the webdav path resolving helper
NodeRef nodeRef = resolveWebDAVPath(sc, elements, false);
if (nodeRef == null)
{
// unable to resolve path - output helpful error to the user
throw new IllegalArgumentException("Unable to resolve item Path: " + path);
}
return new PathRefInfo(nodeRef, elements[tokenCount - 1]);
}
/**
* Simple structure class for returning both a NodeRef and Filename String
* @author Kevin Roast
*/
public static class PathRefInfo
{
PathRefInfo(NodeRef ref, String filename)
{
this.NodeRef = ref;
this.Filename = filename;
}
public NodeRef NodeRef;
public String Filename;
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.LoginOutcomeBean;
import org.alfresco.web.bean.repository.Repository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.jsf.FacesContextUtils;
/**
* Base servlet class containing useful constant values and common methods for Alfresco servlets.
*
* @author Kevin Roast
*/
public abstract class BaseServlet extends HttpServlet
{
private static final long serialVersionUID = -826295358696861789L;
public static final String FACES_SERVLET = "/faces";
public static final String KEY_STORE = "store";
public static final String KEY_ROOT_PATH = "rootPath";
/** an existing Ticket can be passed to most servlet for non-session based authentication */
private static final String ARG_TICKET = "ticket";
/** forcing guess access is available on most servlets */
private static final String ARG_GUEST = "guest";
private static final String MSG_ERROR_PERMISSIONS = "error_permissions";
/** list of valid JSPs for redirect after a clean login */
// TODO: make this list configurable
private static Set<String> validRedirectJSPs = new HashSet<String>();
static
{
validRedirectJSPs.add("/jsp/browse/browse.jsp");
validRedirectJSPs.add("/jsp/admin/admin-console.jsp");
validRedirectJSPs.add("/jsp/admin/avm-console.jsp");
validRedirectJSPs.add("/jsp/admin/node-browser.jsp");
validRedirectJSPs.add("/jsp/admin/store-browser.jsp");
validRedirectJSPs.add("/jsp/users/user-console.jsp");
validRedirectJSPs.add("/jsp/categories/categories.jsp");
validRedirectJSPs.add("/jsp/dialog/about.jsp");
validRedirectJSPs.add("/jsp/search/advanced-search.jsp");
validRedirectJSPs.add("/jsp/admin/system-info.jsp");
validRedirectJSPs.add("/jsp/forums/forums.jsp");
validRedirectJSPs.add("/jsp/users/users.jsp");
validRedirectJSPs.add("/jsp/trashcan/trash-list.jsp");
}
private static Log logger = LogFactory.getLog(BaseServlet.class);
/**
* Return the ServiceRegistry helper instance
*
* @param sc ServletContext
*
* @return ServiceRegistry
*/
public static ServiceRegistry getServiceRegistry(ServletContext sc)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
return (ServiceRegistry)wc.getBean(ServiceRegistry.SERVICE_REGISTRY);
}
/**
* Perform an authentication for the servlet request URI. Processing any "ticket" or
* "guest" URL arguments.
*
* @return AuthenticationStatus
*
* @throws IOException
*/
public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res)
throws IOException
{
return servletAuthenticate(req, res, true);
}
/**
* Perform an authentication for the servlet request URI. Processing any "ticket" or
* "guest" URL arguments.
*
* @return AuthenticationStatus
*
* @throws IOException
*/
public AuthenticationStatus servletAuthenticate(HttpServletRequest req, HttpServletResponse res,
boolean redirectToLoginPage) throws IOException
{
AuthenticationStatus status;
// see if a ticket or a force Guest parameter has been supplied
String ticket = req.getParameter(ARG_TICKET);
if (ticket != null && ticket.length() != 0)
{
status = AuthenticationHelper.authenticate(getServletContext(), req, res, ticket);
}
else
{
boolean forceGuest = false;
String guest = req.getParameter(ARG_GUEST);
if (guest != null)
{
forceGuest = Boolean.parseBoolean(guest);
}
status = AuthenticationHelper.authenticate(getServletContext(), req, res, forceGuest);
}
if (status == AuthenticationStatus.Failure && redirectToLoginPage)
{
// authentication failed - now need to display the login page to the user, if asked to
redirectToLoginPage(req, res, getServletContext());
}
return status;
}
/**
* Check the user has the given permission on the given node. If they do not either force a log on if this is a guest
* user or forward to an error page.
*
* @param req
* the request
* @param res
* the response
* @param nodeRef
* the node in question
* @param allowLogIn
* Indicates whether guest users without access to the node should be redirected to the log in page. If
* <code>false</code>, a status 403 forbidden page is displayed instead.
* @return <code>true</code>, if the user has access
* @throws IOException
* Signals that an I/O exception has occurred.
* @throws ServletException
* On other errors
*/
public boolean checkAccess(HttpServletRequest req, HttpServletResponse res, NodeRef nodeRef, String permission,
boolean allowLogIn) throws IOException, ServletException
{
ServletContext sc = getServletContext();
ServiceRegistry serviceRegistry = getServiceRegistry(sc);
PermissionService permissionService = serviceRegistry.getPermissionService();
// check that the user has the permission
if (permissionService.hasPermission(nodeRef, permission) == AccessStatus.DENIED)
{
if (logger.isDebugEnabled())
logger.debug("User does not have " + permission + " permission for NodeRef: " + nodeRef.toString());
if (allowLogIn && serviceRegistry.getAuthorityService().hasGuestAuthority())
{
if (logger.isDebugEnabled())
logger.debug("Redirecting to login page...");
redirectToLoginPage(req, res, sc);
}
else
{
if (logger.isDebugEnabled())
logger.debug("Forwarding to error page...");
Application
.handleSystemError(sc, req, res, MSG_ERROR_PERMISSIONS, HttpServletResponse.SC_FORBIDDEN, logger);
}
return false;
}
return true;
}
/**
* Redirect to the Login page - saving the current URL which can be redirected back later
* once the user has successfully completed the authentication process.
*/
public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc)
throws IOException
{
redirectToLoginPage(req, res, sc, AuthenticationHelper.getRemoteUserMapper(sc) == null);
}
/**
* Redirect to the Login page - saving the current URL which can be redirected back later
* once the user has successfully completed the authentication process.
* @param sendRedirect allow a redirect status code to be set? If <code>false</code> redirect
* will be via markup rather than status code (to allow the status code to be used for handshake
* responses etc.
*/
public static void redirectToLoginPage(HttpServletRequest req, HttpServletResponse res, ServletContext sc, boolean sendRedirect)
throws IOException
{
// Pass the full requested URL as a parameter so the login page knows where to redirect to later
final String uri = req.getRequestURI();
String redirectURL = uri;
// authentication failed - so end servlet execution and redirect to login page
if (WebApplicationContextUtils.getRequiredWebApplicationContext(sc).containsBean(Application.BEAN_CONFIG_SERVICE))
{
StringBuilder redirect = new StringBuilder(128)
.append(req.getContextPath()).append(FACES_SERVLET).append(Application.getLoginPage(sc));
// if we find a JSF servlet reference in the URI then we need to check if the rest of the
// JSP specified is valid for a redirect operation after Login has occured.
int jspIndex;
if (uri.indexOf(req.getContextPath() + FACES_SERVLET) == -1
|| uri.length() > (jspIndex = uri.indexOf(BaseServlet.FACES_SERVLET) + BaseServlet.FACES_SERVLET.length())
&& BaseServlet.validRedirectJSP(uri.substring(jspIndex)))
{
if (redirect.indexOf("?") == -1)
{
redirect.append('?');
}
else
{
redirect.append('&');
}
redirect.append(LoginOutcomeBean.PARAM_REDIRECT_URL);
redirect.append('=');
String url = uri;
// Append the query string if necessary
String queryString = req.getQueryString();
if (queryString != null)
{
// Strip out leading ticket arguments
queryString = queryString.replaceAll("(?<=^|&)" + ARG_TICKET + "(=[^&=]*)?&", "");
// Strip out trailing ticket arguments
queryString = queryString.replaceAll("(^|&)" + ARG_TICKET + "(=[^&=]*)?(?=&|$)", "");
if (queryString.length() != 0)
{
url += "?" + queryString;
}
}
redirect.append(URLEncoder.encode(url, "UTF-8"));
}
redirectURL = redirect.toString();
}
// If external authentication isn't in use (e.g. proxied share authentication), it's safe to return a redirect to the client
if (sendRedirect)
{
res.sendRedirect(redirectURL);
}
// Otherwise, we must signal to the client with an unauthorized status code and rely on a browser refresh to do
// the redirect for failover login (as we do with NTLM, Kerberos)
else
{
res.setContentType("text/html; charset=UTF-8");
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
final PrintWriter out = res.getWriter();
out.println("<html><head>");
out.println("<meta http-equiv=\"Refresh\" content=\"0; url=" + redirectURL + "\">");
out.println("</head><body><p>Please <a href=\"" + redirectURL + "\">log in</a>.</p>");
out.println("</body></html>");
out.close();
}
}
/**
* Apply the headers required to disallow caching of the response in the browser
*/
public static void setNoCacheHeaders(HttpServletResponse res)
{
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Pragma", "no-cache");
}
/**
* Returns true if the specified JSP file is valid for a redirect after login.
* Only a specific sub-set of the available JSPs are valid to jump directly too after a
* clean login attempt - e.g. those that do not require JSF bean context setup. This is
* a limitation of the JSP architecture. The ExternalAccessServlet provides a mechanism to
* setup the JSF bean context directly for some specific cases.
*
* @param jsp Filename of JSP to check, for example "/jsp/browse/browse.jsp"
*
* @return true if the JSP is in the list of valid direct URLs, false otherwise
*/
public static boolean validRedirectJSP(String jsp)
{
return validRedirectJSPs.contains(jsp);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context Faces context
* @param args The elements of the path to lookup
*/
public static NodeRef resolveWebDAVPath(FacesContext context, String[] args)
{
WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, true);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context Faces context
* @param args The elements of the path to lookup
* @param decode True to decode the arg from UTF-8 format, false for no decoding
*/
public static NodeRef resolveWebDAVPath(FacesContext context, String[] args, boolean decode)
{
WebApplicationContext wc = FacesContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, decode);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context ServletContext context
* @param args The elements of the path to lookup
*/
public static NodeRef resolveWebDAVPath(ServletContext context, String[] args)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, true);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param context ServletContext context
* @param args The elements of the path to lookup
* @param decode True to decode the arg from UTF-8 format, false for no decoding
*/
public static NodeRef resolveWebDAVPath(ServletContext context, String[] args, boolean decode)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
return resolveWebDAVPath(wc, args, decode);
}
/**
* Resolves the given path elements to a NodeRef in the current repository
*
* @param wc WebApplicationContext Context
* @param args The elements of the path to lookup
* @param decode True to decode the arg from UTF-8 format, false for no decoding
*/
private static NodeRef resolveWebDAVPath(final WebApplicationContext wc, final String[] args, final boolean decode)
{
return AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
{
public NodeRef doWork() throws Exception
{
NodeRef nodeRef = null;
List<String> paths = new ArrayList<String>(args.length - 1);
FileInfo file = null;
try
{
// create a list of path elements (decode the URL as we go)
for (int x = 1; x < args.length; x++)
{
paths.add(decode ? URLDecoder.decode(args[x]) : args[x]);
}
if (logger.isDebugEnabled())
logger.debug("Attempting to resolve webdav path: " + paths);
// get the company home node to start the search from
nodeRef = new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId());
TenantService tenantService = (TenantService)wc.getBean("tenantService");
if (tenantService != null && tenantService.isEnabled())
{
if (logger.isDebugEnabled())
logger.debug("MT is enabled.");
NodeService nodeService = (NodeService) wc.getBean("NodeService");
SearchService searchService = (SearchService) wc.getBean("SearchService");
NamespaceService namespaceService = (NamespaceService) wc.getBean("NamespaceService");
// TODO: since these constants are used more widely than just the WebDAVServlet,
// they should be defined somewhere other than in that servlet
String rootPath = wc.getServletContext().getInitParameter(BaseServlet.KEY_ROOT_PATH);
// note: rootNodeRef is required (for storeRef part)
nodeRef = tenantService.getRootNode(nodeService, searchService, namespaceService, rootPath, nodeRef);
}
if (paths.size() != 0)
{
FileFolderService ffs = (FileFolderService)wc.getBean("FileFolderService");
file = ffs.resolveNamePath(nodeRef, paths);
nodeRef = file.getNodeRef();
}
if (logger.isDebugEnabled())
logger.debug("Resolved webdav path to NodeRef: " + nodeRef);
}
catch (FileNotFoundException fne)
{
if (logger.isWarnEnabled())
logger.warn("Failed to resolve webdav path", fne);
nodeRef = null;
}
return nodeRef;
}
}, AuthenticationUtil.getSystemUserName());
}
/**
* Resolve a name based into a NodeRef and Filename string
*
* @param sc ServletContext
* @param path 'cm:name' based path using the '/' character as a separator
*
* @return PathRefInfo structure containing the resolved NodeRef and filename
*
* @throws IllegalArgumentException
*/
public final static PathRefInfo resolveNamePath(ServletContext sc, String path)
{
StringTokenizer t = new StringTokenizer(path, "/");
int tokenCount = t.countTokens();
String[] elements = new String[tokenCount];
for (int i=0; i<tokenCount; i++)
{
elements[i] = t.nextToken();
}
// process name based path tokens using the webdav path resolving helper
NodeRef nodeRef = resolveWebDAVPath(sc, elements, false);
if (nodeRef == null)
{
// unable to resolve path - output helpful error to the user
throw new IllegalArgumentException("Unable to resolve item Path: " + path);
}
return new PathRefInfo(nodeRef, elements[tokenCount - 1]);
}
/**
* Simple structure class for returning both a NodeRef and Filename String
* @author Kevin Roast
*/
public static class PathRefInfo
{
PathRefInfo(NodeRef ref, String filename)
{
this.NodeRef = ref;
this.Filename = filename;
}
public NodeRef NodeRef;
public String Filename;
}
}

View File

@@ -1,363 +1,363 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.web.scripts.FileTypeImageUtils;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.FileTypeImageSize;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.apache.commons.logging.Log;
/**
* Base class for the template content servlets. Provides common
* processing for the request.
*
* @see org.alfresco.web.app.servlet.TemplateContentServlet
* @see org.alfresco.web.app.servlet.GuestTemplateContentServlet
*
* @author Kevin Roast
* @author gavinc
*/
@SuppressWarnings("serial")
public abstract class BaseTemplateContentServlet extends BaseServlet
{
private static final String MIMETYPE_HTML = "text/html;charset=utf-8";
private static final long serialVersionUID = -4123407921997235977L;
private static final String ARG_MIMETYPE = "mimetype";
private static final String ARG_TEMPLATE_PATH = "templatePath";
private static final String ARG_CONTEXT_PATH = "contextPath";
/**
* Gets the logger to use for this request.
* <p>
* This will show all debug entries from this class as though they
* came from the subclass.
*
* @return The logger
*/
protected abstract Log getLogger();
/**
* Builds the FreeMarker model
*
* @param services Service Registry instance
* @param req Http request
* @param templateRef The node ref of the template to process
* @return The FreeMarker model
*/
protected abstract Map<String, Object> buildModel(ServiceRegistry services,
HttpServletRequest req, NodeRef templateRef);
/**
* Processes the template request using the current context i.e. no
* authentication checks are made, it is presumed they have already
* been done.
*
* @param req The HTTP request
* @param res The HTTP response
* @param redirectToLogin Flag to determine whether to redirect to the login
* page if the user does not have the correct permissions
*/
protected void processTemplateRequest(HttpServletRequest req, HttpServletResponse res,
boolean redirectToLogin) throws ServletException, IOException
{
Log logger = getLogger();
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Processing URL: " + uri +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
t.nextToken(); // skip servlet name
NodeRef nodeRef = null;
NodeRef templateRef = null;
try
{
String contentPath = req.getParameter(ARG_CONTEXT_PATH);
if (contentPath != null && contentPath.length() != 0)
{
// process the name based path to resolve the NodeRef
PathRefInfo pathInfo = resolveNamePath(getServletContext(), contentPath);
nodeRef = pathInfo.NodeRef;
}
else if (tokenCount > 3)
{
// get NodeRef to the content from the URL elements
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
nodeRef = new NodeRef(storeRef, t.nextToken());
}
// get NodeRef to the template if supplied
String templatePath = req.getParameter(ARG_TEMPLATE_PATH);
if (templatePath != null && templatePath.length() != 0)
{
// process the name based path to resolve the NodeRef
PathRefInfo pathInfo = resolveNamePath(getServletContext(), templatePath);
templateRef = pathInfo.NodeRef;
}
else if (tokenCount >= 7)
{
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
templateRef = new NodeRef(storeRef, t.nextToken());
}
}
catch (AccessDeniedException err)
{
if (redirectToLogin)
{
if (logger.isDebugEnabled())
logger.debug("Redirecting to login page...");
redirectToLoginPage(req, res, getServletContext());
}
else
{
if (logger.isDebugEnabled())
logger.debug("Returning 403 Forbidden error...");
res.sendError(HttpServletResponse.SC_FORBIDDEN);
}
return;
}
// if no context is specified, use the template itself
// TODO: should this default to something else?
if (nodeRef == null && templateRef != null)
{
nodeRef = templateRef;
}
if (nodeRef == null)
{
throw new TemplateException("Not enough elements supplied in URL or no 'path' argument specified.");
}
// get the services we need to retrieve the content
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
NodeService nodeService = serviceRegistry.getNodeService();
TemplateService templateService = serviceRegistry.getTemplateService();
PermissionService permissionService = serviceRegistry.getPermissionService();
// check that the user has at least READ access on any nodes - else redirect to the login page
if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED ||
(templateRef != null && permissionService.hasPermission(templateRef, PermissionService.READ) == AccessStatus.DENIED))
{
if (redirectToLogin)
{
if (logger.isDebugEnabled())
logger.debug("Redirecting to login page...");
redirectToLoginPage(req, res, getServletContext());
}
else
{
if (logger.isDebugEnabled())
logger.debug("Returning 403 Forbidden error...");
res.sendError(HttpServletResponse.SC_FORBIDDEN);
}
return;
}
String mimetype = MIMETYPE_HTML;
if (req.getParameter(ARG_MIMETYPE) != null)
{
mimetype = req.getParameter(ARG_MIMETYPE);
}
res.setContentType(mimetype);
try
{
UserTransaction txn = null;
try
{
txn = serviceRegistry.getTransactionService().getUserTransaction(true);
txn.begin();
// if template not supplied, then use the default against the node
if (templateRef == null)
{
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPLATABLE))
{
templateRef = (NodeRef)nodeService.getProperty(nodeRef, ContentModel.PROP_TEMPLATE);
}
if (templateRef == null)
{
throw new TemplateException("Template reference not set against node or not supplied in URL.");
}
}
// create the model - put the supplied noderef in as space/document as appropriate
Map<String, Object> model = getModel(serviceRegistry, req, templateRef, nodeRef);
// process the template against the node content directly to the response output stream
// assuming the repo is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
templateService.processTemplate(
templateRef.toString(),
model,
res.getWriter());
// commit the transaction
txn.commit();
}
catch (SocketException e)
{
if (e.getMessage().contains("ClientAbortException"))
{
// the client cut the connection - our mission was accomplished apart from a little error message
logger.error("Client aborted stream read:\n node: " + nodeRef + "\n template: " + templateRef);
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
}
else
{
throw e;
}
}
finally
{
res.getWriter().close();
}
}
catch (Throwable txnErr)
{
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
throw txnErr;
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during template servlet processing: " + err.getMessage(), err);
}
}
/**
* Build the model that to process the template against.
* <p>
* The model includes the usual template root objects such as 'companyhome', 'userhome',
* 'person' and also includes the node specified on the servlet URL as 'space' and 'document'
*
* @param services ServiceRegistry
* @param req Http request - for accessing Session and url args
* @param templateRef NodeRef of the template itself
* @param nodeRef NodeRef of the space/document to process template against
*
* @return an object model ready for executing template against
*/
@SuppressWarnings("unchecked")
private Map<String, Object> getModel(ServiceRegistry services, HttpServletRequest req, NodeRef templateRef, NodeRef nodeRef)
{
// build FreeMarker default model and merge
Map<String, Object> root = buildModel(services, req, templateRef);
// put the current NodeRef in as "space" and "document"
root.put("space", nodeRef);
root.put("document", nodeRef);
// add URL arguments as a map called 'args' to the root of the model
Map<String, String> args = new HashMap<String, String>(8, 1.0f);
Enumeration names = req.getParameterNames();
while (names.hasMoreElements())
{
String name = (String)names.nextElement();
try
{
args.put(name, new String(req.getParameter(name).getBytes(), "UTF-8"));
}
catch (UnsupportedEncodingException err) {}
}
root.put("args", args);
// Add the image resolver
root.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver);
// method to allow client urls to be generated
root.put("url", new URLHelper(req));
return root;
}
/** Template Image resolver helper */
protected TemplateImageResolver imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, FileTypeImageSize size)
{
return FileTypeImageUtils.getFileTypeImage(getServletContext(), filename, size);
}
};
/**
* Helper to return context path for generating urls
*/
public static class URLHelper
{
String contextPath;
String serverPath;
public URLHelper(HttpServletRequest request)
{
this.contextPath = request.getContextPath();
this.serverPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
}
public URLHelper(FacesContext context)
{
this.contextPath = context.getExternalContext().getRequestContextPath();
final Object request = context.getExternalContext().getRequest();
if (request instanceof HttpServletRequest)
{
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
this.serverPath = httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName() + ":" + httpServletRequest.getServerPort();
}
}
public String getContext()
{
return this.contextPath;
}
public String getServerPath()
{
return this.serverPath;
}
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.web.scripts.FileTypeImageUtils;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.FileTypeImageSize;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.TemplateException;
import org.alfresco.service.cmr.repository.TemplateImageResolver;
import org.alfresco.service.cmr.repository.TemplateService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.apache.commons.logging.Log;
/**
* Base class for the template content servlets. Provides common
* processing for the request.
*
* @see org.alfresco.web.app.servlet.TemplateContentServlet
* @see org.alfresco.web.app.servlet.GuestTemplateContentServlet
*
* @author Kevin Roast
* @author gavinc
*/
@SuppressWarnings("serial")
public abstract class BaseTemplateContentServlet extends BaseServlet
{
private static final String MIMETYPE_HTML = "text/html;charset=utf-8";
private static final long serialVersionUID = -4123407921997235977L;
private static final String ARG_MIMETYPE = "mimetype";
private static final String ARG_TEMPLATE_PATH = "templatePath";
private static final String ARG_CONTEXT_PATH = "contextPath";
/**
* Gets the logger to use for this request.
* <p>
* This will show all debug entries from this class as though they
* came from the subclass.
*
* @return The logger
*/
protected abstract Log getLogger();
/**
* Builds the FreeMarker model
*
* @param services Service Registry instance
* @param req Http request
* @param templateRef The node ref of the template to process
* @return The FreeMarker model
*/
protected abstract Map<String, Object> buildModel(ServiceRegistry services,
HttpServletRequest req, NodeRef templateRef);
/**
* Processes the template request using the current context i.e. no
* authentication checks are made, it is presumed they have already
* been done.
*
* @param req The HTTP request
* @param res The HTTP response
* @param redirectToLogin Flag to determine whether to redirect to the login
* page if the user does not have the correct permissions
*/
protected void processTemplateRequest(HttpServletRequest req, HttpServletResponse res,
boolean redirectToLogin) throws ServletException, IOException
{
Log logger = getLogger();
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Processing URL: " + uri +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
t.nextToken(); // skip servlet name
NodeRef nodeRef = null;
NodeRef templateRef = null;
try
{
String contentPath = req.getParameter(ARG_CONTEXT_PATH);
if (contentPath != null && contentPath.length() != 0)
{
// process the name based path to resolve the NodeRef
PathRefInfo pathInfo = resolveNamePath(getServletContext(), contentPath);
nodeRef = pathInfo.NodeRef;
}
else if (tokenCount > 3)
{
// get NodeRef to the content from the URL elements
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
nodeRef = new NodeRef(storeRef, t.nextToken());
}
// get NodeRef to the template if supplied
String templatePath = req.getParameter(ARG_TEMPLATE_PATH);
if (templatePath != null && templatePath.length() != 0)
{
// process the name based path to resolve the NodeRef
PathRefInfo pathInfo = resolveNamePath(getServletContext(), templatePath);
templateRef = pathInfo.NodeRef;
}
else if (tokenCount >= 7)
{
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
templateRef = new NodeRef(storeRef, t.nextToken());
}
}
catch (AccessDeniedException err)
{
if (redirectToLogin)
{
if (logger.isDebugEnabled())
logger.debug("Redirecting to login page...");
redirectToLoginPage(req, res, getServletContext());
}
else
{
if (logger.isDebugEnabled())
logger.debug("Returning 403 Forbidden error...");
res.sendError(HttpServletResponse.SC_FORBIDDEN);
}
return;
}
// if no context is specified, use the template itself
// TODO: should this default to something else?
if (nodeRef == null && templateRef != null)
{
nodeRef = templateRef;
}
if (nodeRef == null)
{
throw new TemplateException("Not enough elements supplied in URL or no 'path' argument specified.");
}
// get the services we need to retrieve the content
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
NodeService nodeService = serviceRegistry.getNodeService();
TemplateService templateService = serviceRegistry.getTemplateService();
PermissionService permissionService = serviceRegistry.getPermissionService();
// check that the user has at least READ access on any nodes - else redirect to the login page
if (permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.DENIED ||
(templateRef != null && permissionService.hasPermission(templateRef, PermissionService.READ) == AccessStatus.DENIED))
{
if (redirectToLogin)
{
if (logger.isDebugEnabled())
logger.debug("Redirecting to login page...");
redirectToLoginPage(req, res, getServletContext());
}
else
{
if (logger.isDebugEnabled())
logger.debug("Returning 403 Forbidden error...");
res.sendError(HttpServletResponse.SC_FORBIDDEN);
}
return;
}
String mimetype = MIMETYPE_HTML;
if (req.getParameter(ARG_MIMETYPE) != null)
{
mimetype = req.getParameter(ARG_MIMETYPE);
}
res.setContentType(mimetype);
try
{
UserTransaction txn = null;
try
{
txn = serviceRegistry.getTransactionService().getUserTransaction(true);
txn.begin();
// if template not supplied, then use the default against the node
if (templateRef == null)
{
if (nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TEMPLATABLE))
{
templateRef = (NodeRef)nodeService.getProperty(nodeRef, ContentModel.PROP_TEMPLATE);
}
if (templateRef == null)
{
throw new TemplateException("Template reference not set against node or not supplied in URL.");
}
}
// create the model - put the supplied noderef in as space/document as appropriate
Map<String, Object> model = getModel(serviceRegistry, req, templateRef, nodeRef);
// process the template against the node content directly to the response output stream
// assuming the repo is capable of streaming in chunks, this should allow large files
// to be streamed directly to the browser response stream.
try
{
templateService.processTemplate(
templateRef.toString(),
model,
res.getWriter());
// commit the transaction
txn.commit();
}
catch (SocketException e)
{
if (e.getMessage().contains("ClientAbortException"))
{
// the client cut the connection - our mission was accomplished apart from a little error message
logger.error("Client aborted stream read:\n node: " + nodeRef + "\n template: " + templateRef);
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
}
else
{
throw e;
}
}
finally
{
res.getWriter().close();
}
}
catch (Throwable txnErr)
{
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
throw txnErr;
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during template servlet processing: " + err.getMessage(), err);
}
}
/**
* Build the model that to process the template against.
* <p>
* The model includes the usual template root objects such as 'companyhome', 'userhome',
* 'person' and also includes the node specified on the servlet URL as 'space' and 'document'
*
* @param services ServiceRegistry
* @param req Http request - for accessing Session and url args
* @param templateRef NodeRef of the template itself
* @param nodeRef NodeRef of the space/document to process template against
*
* @return an object model ready for executing template against
*/
@SuppressWarnings("unchecked")
private Map<String, Object> getModel(ServiceRegistry services, HttpServletRequest req, NodeRef templateRef, NodeRef nodeRef)
{
// build FreeMarker default model and merge
Map<String, Object> root = buildModel(services, req, templateRef);
// put the current NodeRef in as "space" and "document"
root.put("space", nodeRef);
root.put("document", nodeRef);
// add URL arguments as a map called 'args' to the root of the model
Map<String, String> args = new HashMap<String, String>(8, 1.0f);
Enumeration names = req.getParameterNames();
while (names.hasMoreElements())
{
String name = (String)names.nextElement();
try
{
args.put(name, new String(req.getParameter(name).getBytes(), "UTF-8"));
}
catch (UnsupportedEncodingException err) {}
}
root.put("args", args);
// Add the image resolver
root.put(TemplateService.KEY_IMAGE_RESOLVER, imageResolver);
// method to allow client urls to be generated
root.put("url", new URLHelper(req));
return root;
}
/** Template Image resolver helper */
protected TemplateImageResolver imageResolver = new TemplateImageResolver()
{
public String resolveImagePathForName(String filename, FileTypeImageSize size)
{
return FileTypeImageUtils.getFileTypeImage(getServletContext(), filename, size);
}
};
/**
* Helper to return context path for generating urls
*/
public static class URLHelper
{
String contextPath;
String serverPath;
public URLHelper(HttpServletRequest request)
{
this.contextPath = request.getContextPath();
this.serverPath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
}
public URLHelper(FacesContext context)
{
this.contextPath = context.getExternalContext().getRequestContextPath();
final Object request = context.getExternalContext().getRequest();
if (request instanceof HttpServletRequest)
{
final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
this.serverPath = httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName() + ":" + httpServletRequest.getServerPort();
}
}
public String getContext()
{
return this.contextPath;
}
public String getServerPath()
{
return this.serverPath;
}
}
}

View File

@@ -1,248 +1,248 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.springframework.extensions.config.Config;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.command.CommandFactory;
import org.alfresco.web.app.servlet.command.CommandProcessor;
import org.alfresco.web.app.servlet.command.ExtCommandProcessor;
import org.alfresco.web.config.CommandServletConfigElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for executing commands upon node(s).
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/command/processor-name/command-name/args/...</pre>
* <p>
* The 'processor-name' identifies the command processor to execute the command. For example the
* 'workflow' processor will execute workflow commands upon a node (e.g. "approve" or "reject").
* For example:
* <pre>/alfresco/command/workflow/approve/workspace/SpacesStore/0000-0000-0000-0000</pre>
* The store protocol, followed by the store ID, followed by the content Node Id used to
* identify the node to execute the workflow action upon.
* <p>
* A 'return-page' URL argument can be specified as the redirect page to navigate too after processing.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
* <p>
* And/or also followed by the "?guest=true" argument to force guest access login for the URL.
*
* @author Kevin Roast
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class CommandServlet extends BaseServlet
{
private static final long serialVersionUID = -5432407921038376133L;
private static Log logger = LogFactory.getLog(CommandServlet.class);
private static CommandFactory commandfactory = CommandFactory.getInstance();
public static final String ARG_RETURNPAGE = "return-page";
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
logger.debug("Processing URL: " + uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : ""));
AuthenticationStatus status = servletAuthenticate(req, res);
if (status == AuthenticationStatus.Failure)
{
return;
}
setNoCacheHeaders(res);
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
if (tokenCount < 3)
{
throw new IllegalArgumentException("Command Servlet URL did not contain all required args: " + uri);
}
t.nextToken(); // skip servlet name
// get the command processor to execute the command e.g. "workflow"
String procName = t.nextToken();
// get the command to perform
String command = t.nextToken();
// get any remaining uri elements to pass to the processor
String[] urlElements = new String[tokenCount - 3];
for (int i=0; i<tokenCount-3; i++)
{
urlElements[i] = t.nextToken();
}
// retrieve the URL arguments to pass to the processor
Map<String, String> args = new HashMap<String, String>(8, 1.0f);
Enumeration names = req.getParameterNames();
while (names.hasMoreElements())
{
String name = (String)names.nextElement();
args.put(name, req.getParameter(name));
}
try
{
// get configured command processor by name from Config Service
CommandProcessor processor = createCommandProcessor(procName);
// validate that the processor has everything it needs to run the command
if (processor.validateArguments(getServletContext(), command, args, urlElements) == false)
{
redirectToLoginPage(req, res, getServletContext());
return;
}
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
UserTransaction txn = null;
try
{
txn = serviceRegistry.getTransactionService().getUserTransaction();
txn.begin();
// inform the processor to execute the specified command
if (processor instanceof ExtCommandProcessor)
{
((ExtCommandProcessor)processor).process(serviceRegistry, req, res, command);
}
else
{
processor.process(serviceRegistry, req, command);
}
// commit the transaction
txn.commit();
}
catch (Throwable txnErr)
{
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
throw txnErr;
}
String returnPage = req.getParameter(ARG_RETURNPAGE);
if (returnPage != null && returnPage.length() != 0)
{
validateReturnPage(returnPage, req);
if (logger.isDebugEnabled())
logger.debug("Redirecting to specified return page: " + returnPage);
res.sendRedirect(returnPage);
}
else
{
if (logger.isDebugEnabled())
logger.debug("No return page specified, displaying status output.");
if (res.getContentType() == null && !res.isCommitted())
{
res.setContentType("text/html");
// request that the processor output a useful status message
PrintWriter out = res.getWriter();
processor.outputStatus(out);
out.close();
}
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during command servlet processing: " + err.getMessage(), err);
}
}
/**
* ALF-9113 CommandServlet.java, line 179 (Header Manipulation)
*
* Validates that the redirect page is within the current context.
*
* Examples of valid redirect pages:
* <ul>
* <li>/alfresco/faces/jsp/browse/browse.jsp</li>
* <li>../../browse/browse.jsp</li>
* </ul>
*
* @param pageUrl
* @param req
* @throws MalformedURLException
* @throws IllegalArgumentException
*/
private void validateReturnPage(String pageUrl, HttpServletRequest req) throws MalformedURLException
{
if (pageUrl.indexOf(':') != -1)
{
// ':' only allowed in a URL as part of a scheme prefix
throw new IllegalArgumentException("The redirect URL doesn't support absolute URls");
}
// Evaluate it relative to the request URL and strip out .. and .
pageUrl = new URL(new URL(req.getRequestURL().toString()), pageUrl).getPath();
if (!pageUrl.startsWith(req.getContextPath()))
{
throw new IllegalArgumentException("The redirect URL must be in the same context.");
}
}
/**
* Created the specified CommandProcessor instance. The name of the processor is looked up
* in the client config, it should find a valid class impl and then create it.
*
* @param procName Name of the CommandProcessor to lookup in the client config.
*
* @return CommandProcessor
*
* @throws InstantiationException
* @throws IllegalAccessException
*/
private CommandProcessor createCommandProcessor(String procName)
throws InstantiationException, IllegalAccessException
{
Config config = Application.getConfigService(getServletContext()).getConfig("Command Servlet");
if (config == null)
{
throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
}
CommandServletConfigElement configElement = (CommandServletConfigElement)
config.getConfigElement(CommandServletConfigElement.CONFIG_ELEMENT_ID);
if (configElement == null)
{
throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
}
Class clazz = configElement.getCommandProcessor(procName);
Object obj = clazz.newInstance();
if (obj instanceof CommandProcessor == false)
{
throw new AlfrescoRuntimeException("Configured command processor '" + procName + "' is does not implement interface CommandProcessor!");
}
return (CommandProcessor)obj;
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.springframework.extensions.config.Config;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.command.CommandFactory;
import org.alfresco.web.app.servlet.command.CommandProcessor;
import org.alfresco.web.app.servlet.command.ExtCommandProcessor;
import org.alfresco.web.config.CommandServletConfigElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for executing commands upon node(s).
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/command/processor-name/command-name/args/...</pre>
* <p>
* The 'processor-name' identifies the command processor to execute the command. For example the
* 'workflow' processor will execute workflow commands upon a node (e.g. "approve" or "reject").
* For example:
* <pre>/alfresco/command/workflow/approve/workspace/SpacesStore/0000-0000-0000-0000</pre>
* The store protocol, followed by the store ID, followed by the content Node Id used to
* identify the node to execute the workflow action upon.
* <p>
* A 'return-page' URL argument can be specified as the redirect page to navigate too after processing.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
* <p>
* And/or also followed by the "?guest=true" argument to force guest access login for the URL.
*
* @author Kevin Roast
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class CommandServlet extends BaseServlet
{
private static final long serialVersionUID = -5432407921038376133L;
private static Log logger = LogFactory.getLog(CommandServlet.class);
private static CommandFactory commandfactory = CommandFactory.getInstance();
public static final String ARG_RETURNPAGE = "return-page";
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
String uri = req.getRequestURI();
if (logger.isDebugEnabled())
logger.debug("Processing URL: " + uri + (req.getQueryString() != null ? ("?" + req.getQueryString()) : ""));
AuthenticationStatus status = servletAuthenticate(req, res);
if (status == AuthenticationStatus.Failure)
{
return;
}
setNoCacheHeaders(res);
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
if (tokenCount < 3)
{
throw new IllegalArgumentException("Command Servlet URL did not contain all required args: " + uri);
}
t.nextToken(); // skip servlet name
// get the command processor to execute the command e.g. "workflow"
String procName = t.nextToken();
// get the command to perform
String command = t.nextToken();
// get any remaining uri elements to pass to the processor
String[] urlElements = new String[tokenCount - 3];
for (int i=0; i<tokenCount-3; i++)
{
urlElements[i] = t.nextToken();
}
// retrieve the URL arguments to pass to the processor
Map<String, String> args = new HashMap<String, String>(8, 1.0f);
Enumeration names = req.getParameterNames();
while (names.hasMoreElements())
{
String name = (String)names.nextElement();
args.put(name, req.getParameter(name));
}
try
{
// get configured command processor by name from Config Service
CommandProcessor processor = createCommandProcessor(procName);
// validate that the processor has everything it needs to run the command
if (processor.validateArguments(getServletContext(), command, args, urlElements) == false)
{
redirectToLoginPage(req, res, getServletContext());
return;
}
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
UserTransaction txn = null;
try
{
txn = serviceRegistry.getTransactionService().getUserTransaction();
txn.begin();
// inform the processor to execute the specified command
if (processor instanceof ExtCommandProcessor)
{
((ExtCommandProcessor)processor).process(serviceRegistry, req, res, command);
}
else
{
processor.process(serviceRegistry, req, command);
}
// commit the transaction
txn.commit();
}
catch (Throwable txnErr)
{
try { if (txn != null) {txn.rollback();} } catch (Exception tex) {}
throw txnErr;
}
String returnPage = req.getParameter(ARG_RETURNPAGE);
if (returnPage != null && returnPage.length() != 0)
{
validateReturnPage(returnPage, req);
if (logger.isDebugEnabled())
logger.debug("Redirecting to specified return page: " + returnPage);
res.sendRedirect(returnPage);
}
else
{
if (logger.isDebugEnabled())
logger.debug("No return page specified, displaying status output.");
if (res.getContentType() == null && !res.isCommitted())
{
res.setContentType("text/html");
// request that the processor output a useful status message
PrintWriter out = res.getWriter();
processor.outputStatus(out);
out.close();
}
}
}
catch (Throwable err)
{
throw new AlfrescoRuntimeException("Error during command servlet processing: " + err.getMessage(), err);
}
}
/**
* ALF-9113 CommandServlet.java, line 179 (Header Manipulation)
*
* Validates that the redirect page is within the current context.
*
* Examples of valid redirect pages:
* <ul>
* <li>/alfresco/faces/jsp/browse/browse.jsp</li>
* <li>../../browse/browse.jsp</li>
* </ul>
*
* @param pageUrl
* @param req
* @throws MalformedURLException
* @throws IllegalArgumentException
*/
private void validateReturnPage(String pageUrl, HttpServletRequest req) throws MalformedURLException
{
if (pageUrl.indexOf(':') != -1)
{
// ':' only allowed in a URL as part of a scheme prefix
throw new IllegalArgumentException("The redirect URL doesn't support absolute URls");
}
// Evaluate it relative to the request URL and strip out .. and .
pageUrl = new URL(new URL(req.getRequestURL().toString()), pageUrl).getPath();
if (!pageUrl.startsWith(req.getContextPath()))
{
throw new IllegalArgumentException("The redirect URL must be in the same context.");
}
}
/**
* Created the specified CommandProcessor instance. The name of the processor is looked up
* in the client config, it should find a valid class impl and then create it.
*
* @param procName Name of the CommandProcessor to lookup in the client config.
*
* @return CommandProcessor
*
* @throws InstantiationException
* @throws IllegalAccessException
*/
private CommandProcessor createCommandProcessor(String procName)
throws InstantiationException, IllegalAccessException
{
Config config = Application.getConfigService(getServletContext()).getConfig("Command Servlet");
if (config == null)
{
throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
}
CommandServletConfigElement configElement = (CommandServletConfigElement)
config.getConfigElement(CommandServletConfigElement.CONFIG_ELEMENT_ID);
if (configElement == null)
{
throw new AlfrescoRuntimeException("No command processors configured - unable to process any commands.");
}
Class clazz = configElement.getCommandProcessor(procName);
Object obj = clazz.newInstance();
if (obj instanceof CommandProcessor == false)
{
throw new AlfrescoRuntimeException("Configured command processor '" + procName + "' is does not implement interface CommandProcessor!");
}
return (CommandProcessor)obj;
}
}

View File

@@ -1,320 +1,320 @@
package org.alfresco.web.app.servlet;
import javax.faces.FactoryFinder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.el.EvaluationException;
import javax.faces.el.ValueBinding;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.web.bean.generator.IComponentGenerator;
import org.alfresco.web.ui.repo.RepoConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author Kevin Roast
*/
public final class FacesHelper
{
/** Root browse screen JSF view ID */
public static final String BROWSE_VIEW_ID = "/jsp/browse/browse.jsp";
private static Log logger = LogFactory.getLog(FacesHelper.class);
/**
* Mask for hex encoding
*/
private static final int MASK = (1 << 4) - 1;
/**
* Digits used for hex string encoding
*/
private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* Private constructor
*/
private FacesHelper()
{
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet use.
*
* @param context ServletContext
* @param request ServletRequest
* @param response ServletReponse
*
* @return FacesContext
*/
public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context)
{
return getFacesContextImpl(request, response, context, null);
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet use.
*
* @param context ServletContext
* @param request ServletRequest
* @param response ServletReponse
*
* @return FacesContext
*/
public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context, String viewRoot)
{
return getFacesContextImpl(request, response, context, viewRoot);
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet use.
*
* @param context PortletContext
* @param request PortletRequest
* @param response PortletResponse
*
* @return FacesContext
*/
public static FacesContext getFacesContext(Object request, Object response, Object context)
{
return getFacesContextImpl(request, response, context, null);
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet and Portlet use.
*
* @param context ServletContext or PortletContext
* @param request ServletRequest or PortletRequest
* @param response ServletReponse or PortletResponse
*
* @return FacesContext
*/
private static FacesContext getFacesContextImpl(Object request, Object response, Object context, String viewRoot)
{
FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
// Doesn't set this instance as the current instance of FacesContext.getCurrentInstance
FacesContext facesContext = contextFactory.getFacesContext(context, request, response, lifecycle);
// Set using our inner class
InnerFacesContext.setFacesContextAsCurrent(facesContext);
// set a new viewRoot, otherwise context.getViewRoot returns null
if (viewRoot == null)
{
viewRoot = FacesHelper.BROWSE_VIEW_ID;
}
UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, viewRoot);
facesContext.setViewRoot(view);
return facesContext;
}
/**
* Return a JSF managed bean reference.
*
* @param fc FacesContext
* @param name Name of the managed bean to return
*
* @return the managed bean or null if not found
*/
public static Object getManagedBean(FacesContext fc, String name)
{
Object obj = null;
try
{
ValueBinding vb = fc.getApplication().createValueBinding("#{" + name + "}");
obj = vb.getValue(fc);
}
catch (EvaluationException ee)
{
// catch exception to resolve ADB-158/ACT-7343
// not much we can do here, just make sure return is null
if (logger.isDebugEnabled())
logger.debug("Failed to resolve managed bean: " + name, ee);
obj = null;
}
return obj;
}
/**
* Sets up the id for the given component, if the id is null a unique one
* is generated using the standard Faces algorithm. If an id is present it
* is checked for illegal characters.
*
* @param context FacesContext
* @param component The component to set the id for
* @param id The id to set
*/
public static void setupComponentId(FacesContext context, UIComponent component, String id)
{
if (id == null)
{
id = context.getViewRoot().createUniqueId();
}
else
{
// make sure we do not have illegal characters in the id
id = makeLegalId(id);
}
component.setId(id);
}
/**
* Makes the given id a legal JSF component id by replacing illegal characters
* with ISO9075 encoding - which itself a subset of valid HTML ID characters.
*
* @param id The id to make legal
*
* @return the legalised id
*/
public static String makeLegalId(String id)
{
return (id != null ? validFacesId(id) : null);
}
/**
* Retrieves the named component generator implementation.
* If the named generator is not found the TextFieldGenerator is looked up
* as a default, if this is also not found an AlfrescoRuntimeException is thrown.
*
* @param context FacesContext
* @param generatorName The name of the component generator to retrieve
* @return The component generator instance
*/
public static IComponentGenerator getComponentGenerator(FacesContext context, String generatorName)
{
IComponentGenerator generator = lookupComponentGenerator(context, generatorName);
if (generator == null)
{
// create a text field if we can't find a component generator (a warning should have already been
// displayed on the appserver console)
logger.warn("Attempting to find default component generator '" + RepoConstants.GENERATOR_TEXT_FIELD + "'");
generator = lookupComponentGenerator(context, RepoConstants.GENERATOR_TEXT_FIELD);
}
// if we still don't have a component generator we should abort as vital configuration is missing
if (generator == null)
{
throw new AlfrescoRuntimeException("Failed to find a component generator, please ensure the '" +
RepoConstants.GENERATOR_TEXT_FIELD + "' bean is present in your configuration");
}
return generator;
}
private static IComponentGenerator lookupComponentGenerator(FacesContext context, String generatorName)
{
IComponentGenerator generator = null;
Object obj = FacesHelper.getManagedBean(context, generatorName);
if (obj != null)
{
if (obj instanceof IComponentGenerator)
{
generator = (IComponentGenerator)obj;
if (logger.isDebugEnabled())
logger.debug("Found component generator for '" + generatorName + "': " + generator);
}
else
{
logger.warn("Bean '" + generatorName + "' does not implement IComponentGenerator");
}
}
else
{
logger.warn("Failed to find component generator with name of '" + generatorName + "'");
}
return generator;
}
/**
* We need an inner class to be able to call FacesContext.setCurrentInstance
* since it's a protected method
*/
private abstract static class InnerFacesContext extends FacesContext
{
protected static void setFacesContextAsCurrent(FacesContext facesContext)
{
FacesContext.setCurrentInstance(facesContext);
}
}
/**
* Helper to ensure only valid and acceptable characters are output as Faces component IDs.
* Based on ISO9075 encoding - which itself a subset of valid HTML ID characters.
*/
private static String validFacesId(String id)
{
int len = id.length();
StringBuilder buf = new StringBuilder(len + (len>>1));
for (int i = 0; i<len; i++)
{
char c = id.charAt(i);
int ci = (int)c;
if (i == 0)
{
if ((ci >= 65 && ci <= 90) || // A-Z
(ci >= 97 && ci <= 122)) // a-z
{
buf.append(c);
}
else
{
encode(c, buf);
}
}
else
{
if ((ci >= 65 && ci <= 90) || // A-Z
(ci >= 97 && ci <= 122) || // a-z
(ci >= 48 && ci <= 57) || // 0-9
ci == 45 || ci == 95) // - and _
{
buf.append(c);
}
else
{
encode(c, buf);
}
}
}
return buf.toString();
}
private static void encode(char c, StringBuilder builder)
{
char[] buf = new char[] { 'x', '0', '0', '0', '0', '_' };
int charPos = 5;
do
{
buf[--charPos] = DIGITS[c & MASK];
c >>>= 4;
}
while (c != 0);
builder.append(buf);
}
}
package org.alfresco.web.app.servlet;
import javax.faces.FactoryFinder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.el.EvaluationException;
import javax.faces.el.ValueBinding;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.web.bean.generator.IComponentGenerator;
import org.alfresco.web.ui.repo.RepoConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author Kevin Roast
*/
public final class FacesHelper
{
/** Root browse screen JSF view ID */
public static final String BROWSE_VIEW_ID = "/jsp/browse/browse.jsp";
private static Log logger = LogFactory.getLog(FacesHelper.class);
/**
* Mask for hex encoding
*/
private static final int MASK = (1 << 4) - 1;
/**
* Digits used for hex string encoding
*/
private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/**
* Private constructor
*/
private FacesHelper()
{
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet use.
*
* @param context ServletContext
* @param request ServletRequest
* @param response ServletReponse
*
* @return FacesContext
*/
public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context)
{
return getFacesContextImpl(request, response, context, null);
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet use.
*
* @param context ServletContext
* @param request ServletRequest
* @param response ServletReponse
*
* @return FacesContext
*/
public static FacesContext getFacesContext(ServletRequest request, ServletResponse response, ServletContext context, String viewRoot)
{
return getFacesContextImpl(request, response, context, viewRoot);
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet use.
*
* @param context PortletContext
* @param request PortletRequest
* @param response PortletResponse
*
* @return FacesContext
*/
public static FacesContext getFacesContext(Object request, Object response, Object context)
{
return getFacesContextImpl(request, response, context, null);
}
/**
* Return a valid FacesContext for the specific context, request and response.
* The FacesContext can be constructor for Servlet and Portlet use.
*
* @param context ServletContext or PortletContext
* @param request ServletRequest or PortletRequest
* @param response ServletReponse or PortletResponse
*
* @return FacesContext
*/
private static FacesContext getFacesContextImpl(Object request, Object response, Object context, String viewRoot)
{
FacesContextFactory contextFactory = (FacesContextFactory)FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
LifecycleFactory lifecycleFactory = (LifecycleFactory)FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
Lifecycle lifecycle = lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE);
// Doesn't set this instance as the current instance of FacesContext.getCurrentInstance
FacesContext facesContext = contextFactory.getFacesContext(context, request, response, lifecycle);
// Set using our inner class
InnerFacesContext.setFacesContextAsCurrent(facesContext);
// set a new viewRoot, otherwise context.getViewRoot returns null
if (viewRoot == null)
{
viewRoot = FacesHelper.BROWSE_VIEW_ID;
}
UIViewRoot view = facesContext.getApplication().getViewHandler().createView(facesContext, viewRoot);
facesContext.setViewRoot(view);
return facesContext;
}
/**
* Return a JSF managed bean reference.
*
* @param fc FacesContext
* @param name Name of the managed bean to return
*
* @return the managed bean or null if not found
*/
public static Object getManagedBean(FacesContext fc, String name)
{
Object obj = null;
try
{
ValueBinding vb = fc.getApplication().createValueBinding("#{" + name + "}");
obj = vb.getValue(fc);
}
catch (EvaluationException ee)
{
// catch exception to resolve ADB-158/ACT-7343
// not much we can do here, just make sure return is null
if (logger.isDebugEnabled())
logger.debug("Failed to resolve managed bean: " + name, ee);
obj = null;
}
return obj;
}
/**
* Sets up the id for the given component, if the id is null a unique one
* is generated using the standard Faces algorithm. If an id is present it
* is checked for illegal characters.
*
* @param context FacesContext
* @param component The component to set the id for
* @param id The id to set
*/
public static void setupComponentId(FacesContext context, UIComponent component, String id)
{
if (id == null)
{
id = context.getViewRoot().createUniqueId();
}
else
{
// make sure we do not have illegal characters in the id
id = makeLegalId(id);
}
component.setId(id);
}
/**
* Makes the given id a legal JSF component id by replacing illegal characters
* with ISO9075 encoding - which itself a subset of valid HTML ID characters.
*
* @param id The id to make legal
*
* @return the legalised id
*/
public static String makeLegalId(String id)
{
return (id != null ? validFacesId(id) : null);
}
/**
* Retrieves the named component generator implementation.
* If the named generator is not found the TextFieldGenerator is looked up
* as a default, if this is also not found an AlfrescoRuntimeException is thrown.
*
* @param context FacesContext
* @param generatorName The name of the component generator to retrieve
* @return The component generator instance
*/
public static IComponentGenerator getComponentGenerator(FacesContext context, String generatorName)
{
IComponentGenerator generator = lookupComponentGenerator(context, generatorName);
if (generator == null)
{
// create a text field if we can't find a component generator (a warning should have already been
// displayed on the appserver console)
logger.warn("Attempting to find default component generator '" + RepoConstants.GENERATOR_TEXT_FIELD + "'");
generator = lookupComponentGenerator(context, RepoConstants.GENERATOR_TEXT_FIELD);
}
// if we still don't have a component generator we should abort as vital configuration is missing
if (generator == null)
{
throw new AlfrescoRuntimeException("Failed to find a component generator, please ensure the '" +
RepoConstants.GENERATOR_TEXT_FIELD + "' bean is present in your configuration");
}
return generator;
}
private static IComponentGenerator lookupComponentGenerator(FacesContext context, String generatorName)
{
IComponentGenerator generator = null;
Object obj = FacesHelper.getManagedBean(context, generatorName);
if (obj != null)
{
if (obj instanceof IComponentGenerator)
{
generator = (IComponentGenerator)obj;
if (logger.isDebugEnabled())
logger.debug("Found component generator for '" + generatorName + "': " + generator);
}
else
{
logger.warn("Bean '" + generatorName + "' does not implement IComponentGenerator");
}
}
else
{
logger.warn("Failed to find component generator with name of '" + generatorName + "'");
}
return generator;
}
/**
* We need an inner class to be able to call FacesContext.setCurrentInstance
* since it's a protected method
*/
private abstract static class InnerFacesContext extends FacesContext
{
protected static void setFacesContextAsCurrent(FacesContext facesContext)
{
FacesContext.setCurrentInstance(facesContext);
}
}
/**
* Helper to ensure only valid and acceptable characters are output as Faces component IDs.
* Based on ISO9075 encoding - which itself a subset of valid HTML ID characters.
*/
private static String validFacesId(String id)
{
int len = id.length();
StringBuilder buf = new StringBuilder(len + (len>>1));
for (int i = 0; i<len; i++)
{
char c = id.charAt(i);
int ci = (int)c;
if (i == 0)
{
if ((ci >= 65 && ci <= 90) || // A-Z
(ci >= 97 && ci <= 122)) // a-z
{
buf.append(c);
}
else
{
encode(c, buf);
}
}
else
{
if ((ci >= 65 && ci <= 90) || // A-Z
(ci >= 97 && ci <= 122) || // a-z
(ci >= 48 && ci <= 57) || // 0-9
ci == 45 || ci == 95) // - and _
{
buf.append(c);
}
else
{
encode(c, buf);
}
}
}
return buf.toString();
}
private static void encode(char c, StringBuilder builder)
{
char[] buf = new char[] { 'x', '0', '0', '0', '0', '_' };
int charPos = 5;
do
{
buf[--charPos] = DIGITS[c & MASK];
c >>>= 4;
}
while (c != 0);
builder.append(buf);
}
}

View File

@@ -1,130 +1,130 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for streaming node content from the repo directly to the response stream.
* The appropriate mimetype is calculated based on filename extension.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/guestDownload/attach/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* or
* <pre>/alfresco/guestDownload/direct/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* or
* <pre>/alfresco/guestDownload/[direct|attach]?path=/Company%20Home/MyFolder/myfile.pdf</pre>
* The protocol, followed by either the store and Id (NodeRef) or instead specify a name based
* encoded Path to the content, note that the filename element is used for mimetype lookup and
* as the returning filename for the response stream.
* <p>
* The 'attach' or 'direct' element is used to indicate whether to display the stream directly
* in the browser or download it as a file attachment.
* <p>
* By default, the download assumes that the content is on the
* {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.<br>
* To retrieve the content of a specific model property, use a 'property' arg, providing the workspace,
* node ID AND the qualified name of the property.
* <p>
* This servlet only accesses content available to the guest user. If the guest user does not
* have access to the requested a 403 Forbidden response is returned to the caller.
* <p>
* This servlet does not effect the current session, therefore if guest access is required to a
* resource this servlet can be used without logging out the current user.
*
* @author gavinc
*/
public class GuestDownloadContentServlet extends BaseDownloadContentServlet
{
private static final long serialVersionUID = -5258137503339817457L;
private static Log logger = LogFactory.getLog(GuestDownloadContentServlet.class);
private static final String DOWNLOAD_URL = "/gd/" + URL_ATTACH + "/{0}/{1}/{2}/{3}";
private static final String BROWSER_URL = "/gd/" + URL_DIRECT + "/{0}/{1}/{2}/{3}";
@Override
protected Log getLogger()
{
return logger;
}
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Setting up guest access to URL: " + req.getRequestURI() +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
DownloadContentWork dcw = new DownloadContentWork(req, res);
AuthenticationUtil.runAs(dcw, AuthenticationUtil.getGuestUserName());
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied as an HTTP1.1 attachment to the response. This generally means
* a browser should prompt the user to save the content to specified location.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
public final static String generateDownloadURL(NodeRef ref, String name)
{
return generateUrl(DOWNLOAD_URL, ref, name);
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied directly in the reponse. This generally means a browser will
* attempt to open the content directly if possible, else it will prompt to save the file.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
public final static String generateBrowserURL(NodeRef ref, String name)
{
return generateUrl(BROWSER_URL, ref, name);
}
/**
* Class to wrap the call to processDownloadRequest.
*
* @author gavinc
*/
public class DownloadContentWork implements RunAsWork<Object>
{
private HttpServletRequest req = null;
private HttpServletResponse res = null;
public DownloadContentWork(HttpServletRequest req, HttpServletResponse res)
{
this.req = req;
this.res = res;
}
public Object doWork() throws Exception
{
processDownloadRequest(this.req, this.res, false, true);
return null;
}
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for streaming node content from the repo directly to the response stream.
* The appropriate mimetype is calculated based on filename extension.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/guestDownload/attach/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* or
* <pre>/alfresco/guestDownload/direct/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* or
* <pre>/alfresco/guestDownload/[direct|attach]?path=/Company%20Home/MyFolder/myfile.pdf</pre>
* The protocol, followed by either the store and Id (NodeRef) or instead specify a name based
* encoded Path to the content, note that the filename element is used for mimetype lookup and
* as the returning filename for the response stream.
* <p>
* The 'attach' or 'direct' element is used to indicate whether to display the stream directly
* in the browser or download it as a file attachment.
* <p>
* By default, the download assumes that the content is on the
* {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.<br>
* To retrieve the content of a specific model property, use a 'property' arg, providing the workspace,
* node ID AND the qualified name of the property.
* <p>
* This servlet only accesses content available to the guest user. If the guest user does not
* have access to the requested a 403 Forbidden response is returned to the caller.
* <p>
* This servlet does not effect the current session, therefore if guest access is required to a
* resource this servlet can be used without logging out the current user.
*
* @author gavinc
*/
public class GuestDownloadContentServlet extends BaseDownloadContentServlet
{
private static final long serialVersionUID = -5258137503339817457L;
private static Log logger = LogFactory.getLog(GuestDownloadContentServlet.class);
private static final String DOWNLOAD_URL = "/gd/" + URL_ATTACH + "/{0}/{1}/{2}/{3}";
private static final String BROWSER_URL = "/gd/" + URL_DIRECT + "/{0}/{1}/{2}/{3}";
@Override
protected Log getLogger()
{
return logger;
}
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Setting up guest access to URL: " + req.getRequestURI() +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
DownloadContentWork dcw = new DownloadContentWork(req, res);
AuthenticationUtil.runAs(dcw, AuthenticationUtil.getGuestUserName());
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied as an HTTP1.1 attachment to the response. This generally means
* a browser should prompt the user to save the content to specified location.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
public final static String generateDownloadURL(NodeRef ref, String name)
{
return generateUrl(DOWNLOAD_URL, ref, name);
}
/**
* Helper to generate a URL to a content node for downloading content from the server.
* The content is supplied directly in the reponse. This generally means a browser will
* attempt to open the content directly if possible, else it will prompt to save the file.
*
* @param ref NodeRef of the content node to generate URL for (cannot be null)
* @param name File name to return in the URL (cannot be null)
*
* @return URL to download the content from the specified node
*/
public final static String generateBrowserURL(NodeRef ref, String name)
{
return generateUrl(BROWSER_URL, ref, name);
}
/**
* Class to wrap the call to processDownloadRequest.
*
* @author gavinc
*/
public class DownloadContentWork implements RunAsWork<Object>
{
private HttpServletRequest req = null;
private HttpServletResponse res = null;
public DownloadContentWork(HttpServletRequest req, HttpServletResponse res)
{
this.req = req;
this.res = res;
}
public Object doWork() throws Exception
{
processDownloadRequest(this.req, this.res, false, true);
return null;
}
}
}

View File

@@ -1,171 +1,171 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.ui.repo.component.template.DefaultModelHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for streaming content from a template processed against a node directly
* to the response stream.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000</pre>
* or
* <pre>/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000/workspace/SpacesStore/0000-0000-0000-0000</pre>
* or
* <pre>/alfresco/template?templatePath=/Company%20Home/Data%20Dictionary/Presentation%20Templates/doc_info.ftl&contextPath=/Company%20Home/mydoc.txt</pre>
* <p>
* The store protocol, followed by the store ID, followed by the content Node Id used to
* identify the node to execute the default template for. The second set of elements encode
* the store and node Id of the template to used if a default is not set or not requested. Instead
* of using NodeRef references to the template and context, path arguments can be used. The URL args
* of 'templatePath' and 'contextPath' can be used instead to specify name based encoded Paths to the
* template and its context.
* <p>
* The URL may be followed by a 'mimetype' argument specifying the mimetype to return the result as
* on the stream. Otherwise it is assumed that HTML is the default response mimetype.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
* <p>
* And/or also followed by the "?guest=true" argument to force guest access login for the URL. If the
* guest=true parameter is used the current session will be logged out and the guest user logged in.
* Therefore upon completion of this request the current user will be "guest".
* <p>
* This servlet only accesses content available to the guest user. If the guest user does not
* have access to the requested a 401 Forbidden response is returned to the caller.
* <p>
* This servlet does not effect the current session, therefore if guest access is required to a
* resource this servlet can be used without logging out the current user.
*
* @author gavinc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class GuestTemplateContentServlet extends BaseTemplateContentServlet
{
private static final long serialVersionUID = -2510767849932627519L;
private static final Log logger = LogFactory.getLog(GuestTemplateContentServlet.class);
private static final String DEFAULT_URL = "/guestTemplate/{0}/{1}/{2}";
private static final String TEMPLATE_URL = "/guestTemplate/{0}/{1}/{2}/{3}/{4}/{5}";
@Override
protected Log getLogger()
{
return logger;
}
@Override
protected Map<String, Object> buildModel(ServiceRegistry services, HttpServletRequest req,
NodeRef templateRef)
{
// setup the guest user to pass to the build model helper method
AuthenticationService auth = (AuthenticationService)services.getAuthenticationService();
PersonService personService = (PersonService)services.getPersonService();
NodeService nodeService = (NodeService)services.getNodeService();
NodeRef guestRef = personService.getPerson(AuthenticationUtil.getGuestUserName());
User guestUser = new User(AuthenticationUtil.getGuestUserName(), auth.getCurrentTicket(), guestRef);
NodeRef guestHomeRef = (NodeRef)nodeService.getProperty(guestRef, ContentModel.PROP_HOMEFOLDER);
if (nodeService.exists(guestHomeRef) == false)
{
throw new InvalidNodeRefException(guestHomeRef);
}
guestUser.setHomeSpaceId(guestHomeRef.getId());
// build the default model
return DefaultModelHelper.buildDefaultModel(services, guestUser, templateRef, this.imageResolver);
}
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Setting up guest access to URL: " + req.getRequestURI() +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
TemplateContentWork tcw = new TemplateContentWork(req, res);
AuthenticationUtil.runAs(tcw, AuthenticationUtil.getGuestUserName());
}
/**
* Helper to generate a URL to process a template against a node.
* <p>
* The result of the template is supplied returned as the response.
*
* @param nodeRef NodeRef of the content node to generate URL for (cannot be null)
* @param templateRef NodeRef of the template to process against, or null to use default
*
* @return URL to process the template
*/
public final static String generateURL(NodeRef nodeRef, NodeRef templateRef)
{
if (templateRef == null)
{
return MessageFormat.format(DEFAULT_URL, new Object[] {
nodeRef.getStoreRef().getProtocol(),
nodeRef.getStoreRef().getIdentifier(),
nodeRef.getId() } );
}
else
{
return MessageFormat.format(TEMPLATE_URL, new Object[] {
nodeRef.getStoreRef().getProtocol(),
nodeRef.getStoreRef().getIdentifier(),
nodeRef.getId(),
templateRef.getStoreRef().getProtocol(),
templateRef.getStoreRef().getIdentifier(),
templateRef.getId()} );
}
}
/**
* Class to wrap the call to processTemplateRequest.
*
* @author gavinc
*/
public class TemplateContentWork implements RunAsWork<Object>
{
private HttpServletRequest req = null;
private HttpServletResponse res = null;
public TemplateContentWork(HttpServletRequest req, HttpServletResponse res)
{
this.req = req;
this.res = res;
}
public Object doWork() throws Exception
{
processTemplateRequest(this.req, this.res, false);
return null;
}
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.ui.repo.component.template.DefaultModelHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for streaming content from a template processed against a node directly
* to the response stream.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000</pre>
* or
* <pre>/alfresco/template/workspace/SpacesStore/0000-0000-0000-0000/workspace/SpacesStore/0000-0000-0000-0000</pre>
* or
* <pre>/alfresco/template?templatePath=/Company%20Home/Data%20Dictionary/Presentation%20Templates/doc_info.ftl&contextPath=/Company%20Home/mydoc.txt</pre>
* <p>
* The store protocol, followed by the store ID, followed by the content Node Id used to
* identify the node to execute the default template for. The second set of elements encode
* the store and node Id of the template to used if a default is not set or not requested. Instead
* of using NodeRef references to the template and context, path arguments can be used. The URL args
* of 'templatePath' and 'contextPath' can be used instead to specify name based encoded Paths to the
* template and its context.
* <p>
* The URL may be followed by a 'mimetype' argument specifying the mimetype to return the result as
* on the stream. Otherwise it is assumed that HTML is the default response mimetype.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
* <p>
* And/or also followed by the "?guest=true" argument to force guest access login for the URL. If the
* guest=true parameter is used the current session will be logged out and the guest user logged in.
* Therefore upon completion of this request the current user will be "guest".
* <p>
* This servlet only accesses content available to the guest user. If the guest user does not
* have access to the requested a 401 Forbidden response is returned to the caller.
* <p>
* This servlet does not effect the current session, therefore if guest access is required to a
* resource this servlet can be used without logging out the current user.
*
* @author gavinc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class GuestTemplateContentServlet extends BaseTemplateContentServlet
{
private static final long serialVersionUID = -2510767849932627519L;
private static final Log logger = LogFactory.getLog(GuestTemplateContentServlet.class);
private static final String DEFAULT_URL = "/guestTemplate/{0}/{1}/{2}";
private static final String TEMPLATE_URL = "/guestTemplate/{0}/{1}/{2}/{3}/{4}/{5}";
@Override
protected Log getLogger()
{
return logger;
}
@Override
protected Map<String, Object> buildModel(ServiceRegistry services, HttpServletRequest req,
NodeRef templateRef)
{
// setup the guest user to pass to the build model helper method
AuthenticationService auth = (AuthenticationService)services.getAuthenticationService();
PersonService personService = (PersonService)services.getPersonService();
NodeService nodeService = (NodeService)services.getNodeService();
NodeRef guestRef = personService.getPerson(AuthenticationUtil.getGuestUserName());
User guestUser = new User(AuthenticationUtil.getGuestUserName(), auth.getCurrentTicket(), guestRef);
NodeRef guestHomeRef = (NodeRef)nodeService.getProperty(guestRef, ContentModel.PROP_HOMEFOLDER);
if (nodeService.exists(guestHomeRef) == false)
{
throw new InvalidNodeRefException(guestHomeRef);
}
guestUser.setHomeSpaceId(guestHomeRef.getId());
// build the default model
return DefaultModelHelper.buildDefaultModel(services, guestUser, templateRef, this.imageResolver);
}
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException
{
if (logger.isDebugEnabled())
{
String queryString = req.getQueryString();
logger.debug("Setting up guest access to URL: " + req.getRequestURI() +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
TemplateContentWork tcw = new TemplateContentWork(req, res);
AuthenticationUtil.runAs(tcw, AuthenticationUtil.getGuestUserName());
}
/**
* Helper to generate a URL to process a template against a node.
* <p>
* The result of the template is supplied returned as the response.
*
* @param nodeRef NodeRef of the content node to generate URL for (cannot be null)
* @param templateRef NodeRef of the template to process against, or null to use default
*
* @return URL to process the template
*/
public final static String generateURL(NodeRef nodeRef, NodeRef templateRef)
{
if (templateRef == null)
{
return MessageFormat.format(DEFAULT_URL, new Object[] {
nodeRef.getStoreRef().getProtocol(),
nodeRef.getStoreRef().getIdentifier(),
nodeRef.getId() } );
}
else
{
return MessageFormat.format(TEMPLATE_URL, new Object[] {
nodeRef.getStoreRef().getProtocol(),
nodeRef.getStoreRef().getIdentifier(),
nodeRef.getId(),
templateRef.getStoreRef().getProtocol(),
templateRef.getStoreRef().getIdentifier(),
templateRef.getId()} );
}
}
/**
* Class to wrap the call to processTemplateRequest.
*
* @author gavinc
*/
public class TemplateContentWork implements RunAsWork<Object>
{
private HttpServletRequest req = null;
private HttpServletResponse res = null;
public TemplateContentWork(HttpServletRequest req, HttpServletResponse res)
{
this.req = req;
this.res = res;
}
public Object doWork() throws Exception
{
processTemplateRequest(this.req, this.res, false);
return null;
}
}
}

View File

@@ -1,146 +1,146 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.workflow.jbpm.JBPMEngine;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* Servlet for handling process deployments from jBPM process designer.
*
* @author davidc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class JBPMDeployProcessServlet extends HttpServlet
{
private static final long serialVersionUID = 8002539291245090187L;
private static final String BEAN_GLOBAL_PROPERTIES = "global-properties";
private static final String PROP_ENABLED = "system.workflow.deployservlet.enabled";
@Override
public void init() throws ServletException
{
// Render this servlet permanently unavailable if its enablement property is not set
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
Properties globalProperties = (Properties) wc.getBean(BEAN_GLOBAL_PROPERTIES);
String enabled = globalProperties.getProperty(PROP_ENABLED);
if (!PropertyCheck.isValidPropertyString(enabled) || !Boolean.parseBoolean(enabled))
{
throw new UnavailableException("system.workflow.deployservlet.enabled=false");
}
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException
{
try
{
response.setContentType("text/html");
InputStream deploymentArchive = getDeploymentArchive(request);
WorkflowDefinition workflowDef = deployArchive(deploymentArchive);
response.getWriter().println("Deployed archive " + workflowDef.title + " successfully");
}
catch(IOException e)
{
// NOTE: according to original jBPM deployment servlet
response.getWriter().println("IOException");
}
catch(FileUploadException e)
{
// NOTE: according to original jBPM deployment servlet
response.getWriter().println("FileUploadException");
}
}
/**
* Retrieve the JBPM Process Designer deployment archive from the request
*
* @param request the request
* @return the input stream onto the deployment archive
* @throws WorkflowException
* @throws FileUploadException
* @throws IOException
*/
private InputStream getDeploymentArchive(HttpServletRequest request)
throws FileUploadException, IOException
{
if (!FileUpload.isMultipartContent(request))
{
throw new FileUploadException("Not a multipart request");
}
GPDUpload fileUpload = new GPDUpload();
List list = fileUpload.parseRequest(request);
Iterator iterator = list.iterator();
if (!iterator.hasNext())
{
throw new FileUploadException("No process file in the request");
}
FileItem fileItem = (FileItem) iterator.next();
if (fileItem.getContentType().indexOf("application/x-zip-compressed") == -1)
{
throw new FileUploadException("Not a process archive");
}
return fileItem.getInputStream();
}
/**
* Deploy the jBPM process archive to the Alfresco Repository
*
* @param deploymentArchive the archive to deploy
* @return the deployed workflow definition
*/
private WorkflowDefinition deployArchive(InputStream deploymentArchive)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
WorkflowService workflowService = (WorkflowService)wc.getBean(ServiceRegistry.WORKFLOW_SERVICE.getLocalName());
WorkflowDeployment deployment = workflowService.deployDefinition(JBPMEngine.ENGINE_ID, deploymentArchive, MimetypeMap.MIMETYPE_ZIP);
return deployment.definition;
}
/**
* NOTE: Workaround...
*
* The JBPM process designer (as of 3.1.2) issues a request with a multi-part line
* delimited by ",". It should be ":" according to the HTTP specification which
* the commons file-upload is adhering to.
*
* @author davidc
*/
@SuppressWarnings("deprecation")
private class GPDUpload extends DiskFileUpload
{
@Override
protected byte[] getBoundary(String contentType)
{
return super.getBoundary(contentType.replace(",", ";"));
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.workflow.jbpm.JBPMEngine;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.workflow.WorkflowDefinition;
import org.alfresco.service.cmr.workflow.WorkflowDeployment;
import org.alfresco.service.cmr.workflow.WorkflowException;
import org.alfresco.service.cmr.workflow.WorkflowService;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* Servlet for handling process deployments from jBPM process designer.
*
* @author davidc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class JBPMDeployProcessServlet extends HttpServlet
{
private static final long serialVersionUID = 8002539291245090187L;
private static final String BEAN_GLOBAL_PROPERTIES = "global-properties";
private static final String PROP_ENABLED = "system.workflow.deployservlet.enabled";
@Override
public void init() throws ServletException
{
// Render this servlet permanently unavailable if its enablement property is not set
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
Properties globalProperties = (Properties) wc.getBean(BEAN_GLOBAL_PROPERTIES);
String enabled = globalProperties.getProperty(PROP_ENABLED);
if (!PropertyCheck.isValidPropertyString(enabled) || !Boolean.parseBoolean(enabled))
{
throw new UnavailableException("system.workflow.deployservlet.enabled=false");
}
}
@Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException
{
try
{
response.setContentType("text/html");
InputStream deploymentArchive = getDeploymentArchive(request);
WorkflowDefinition workflowDef = deployArchive(deploymentArchive);
response.getWriter().println("Deployed archive " + workflowDef.title + " successfully");
}
catch(IOException e)
{
// NOTE: according to original jBPM deployment servlet
response.getWriter().println("IOException");
}
catch(FileUploadException e)
{
// NOTE: according to original jBPM deployment servlet
response.getWriter().println("FileUploadException");
}
}
/**
* Retrieve the JBPM Process Designer deployment archive from the request
*
* @param request the request
* @return the input stream onto the deployment archive
* @throws WorkflowException
* @throws FileUploadException
* @throws IOException
*/
private InputStream getDeploymentArchive(HttpServletRequest request)
throws FileUploadException, IOException
{
if (!FileUpload.isMultipartContent(request))
{
throw new FileUploadException("Not a multipart request");
}
GPDUpload fileUpload = new GPDUpload();
List list = fileUpload.parseRequest(request);
Iterator iterator = list.iterator();
if (!iterator.hasNext())
{
throw new FileUploadException("No process file in the request");
}
FileItem fileItem = (FileItem) iterator.next();
if (fileItem.getContentType().indexOf("application/x-zip-compressed") == -1)
{
throw new FileUploadException("Not a process archive");
}
return fileItem.getInputStream();
}
/**
* Deploy the jBPM process archive to the Alfresco Repository
*
* @param deploymentArchive the archive to deploy
* @return the deployed workflow definition
*/
private WorkflowDefinition deployArchive(InputStream deploymentArchive)
{
WebApplicationContext wc = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
WorkflowService workflowService = (WorkflowService)wc.getBean(ServiceRegistry.WORKFLOW_SERVICE.getLocalName());
WorkflowDeployment deployment = workflowService.deployDefinition(JBPMEngine.ENGINE_ID, deploymentArchive, MimetypeMap.MIMETYPE_ZIP);
return deployment.definition;
}
/**
* NOTE: Workaround...
*
* The JBPM process designer (as of 3.1.2) issues a request with a multi-part line
* delimited by ",". It should be ":" according to the HTTP specification which
* the commons file-upload is adhering to.
*
* @author davidc
*/
@SuppressWarnings("deprecation")
private class GPDUpload extends DiskFileUpload
{
@Override
protected byte[] getBoundary(String contentType)
{
return super.getBoundary(contentType.replace(",", ";"));
}
}
}

View File

@@ -1,259 +1,259 @@
package org.alfresco.web.app.servlet;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Locale;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* Servlet responsible for streaming content directly into the repository from the PUT request.
* The appropriate mimetype is calculated based on filename extension.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/upload/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* or
* <pre>/alfresco/upload/myfile.pdf</pre>
* <p>
* If the store and node id are specified in the URL then the content provided will be streamed onto the node
* using an updating writer, updating the content property value accordingly.
* <p>
* If only the file name is specified the content will be streamed into the content store and the content data
* will be returned in the reposonse. This can then be used to update the value of a content property manually.
* Any used content will be cleared up in the usual manner.
* <p>
* By default, the download assumes that the content is on the
* {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.<br>
* To set the content of a specific model property, use a 'property' arg, providing the qualified name of the property.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
* <p>
* Guest access is currently disabled for this servlet.
*
* @author Roy Wetherall
*/
public class UploadContentServlet extends BaseServlet
{
/** Serial version UID */
private static final long serialVersionUID = 1055960980867420355L;
/** Logger */
private static Log logger = LogFactory.getLog(UploadContentServlet.class);
/** Default mime type */
protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";
/** Argument properties */
protected static final String ARG_PROPERTY = "property";
protected static final String ARG_MIMETYPE = "mimetype";
protected static final String ARG_ENCODING = "encoding";
protected static final String ARG_LOCALE = "locale";
/**
* @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doPut(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
if (logger.isDebugEnabled() == true)
{
String queryString = req.getQueryString();
logger.debug("Authenticating request to URL: " + req.getRequestURI()
+ ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
AuthenticationStatus status = servletAuthenticate(req, res, false);
if (status == AuthenticationStatus.Failure || status == AuthenticationStatus.Guest)
{
res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// Tokenise the URI
String uri = req.getRequestURI();
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
t.nextToken(); // skip servlet name
// get or calculate the noderef and filename to download as
NodeRef nodeRef = null;
String filename = null;
QName propertyQName = null;
if (tokenCount == 2)
{
// filename is the only token
filename = t.nextToken();
}
else if (tokenCount == 4 || tokenCount == 5)
{
// assume 'workspace' or other NodeRef based protocol for remaining URL
// elements
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
String id = t.nextToken();
// build noderef from the appropriate URL elements
nodeRef = new NodeRef(storeRef, id);
if (tokenCount == 5)
{
// filename is last remaining token
filename = t.nextToken();
}
// get qualified of the property to get content from - default to
// ContentModel.PROP_CONTENT
propertyQName = ContentModel.PROP_CONTENT;
String property = req.getParameter(ARG_PROPERTY);
if (property != null && property.length() != 0)
{
propertyQName = QName.createQName(property);
}
}
else
{
logger.debug("Upload URL did not contain all required args: " + uri);
res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED);
return;
}
// get the services we need to retrieve the content
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
ContentService contentService = serviceRegistry.getContentService();
PermissionService permissionService = serviceRegistry.getPermissionService();
MimetypeService mimetypeService = serviceRegistry.getMimetypeService();
NodeService nodeService = serviceRegistry.getNodeService();
InputStream is = req.getInputStream();
BufferedInputStream inputStream = new BufferedInputStream(is);
// Sort out the mimetype
String mimetype = req.getParameter(ARG_MIMETYPE);
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MIMETYPE_OCTET_STREAM;
if (filename != null)
{
MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
int extIndex = filename.lastIndexOf('.');
if (extIndex != -1)
{
String ext = filename.substring(extIndex + 1);
mimetype = mimetypeService.getMimetype(ext);
}
}
}
// Get the encoding
String encoding = req.getParameter(ARG_ENCODING);
if (encoding == null || encoding.length() == 0)
{
// Get the encoding
ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder();
Charset charset = charsetFinder.getCharset(inputStream, mimetype);
encoding = charset.name();
}
// Get the locale
Locale locale = I18NUtil.parseLocale(req.getParameter(ARG_LOCALE));
if (locale == null)
{
locale = I18NUtil.getContentLocale();
if (nodeRef != null)
{
ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, propertyQName);
if (contentData != null)
{
locale = contentData.getLocale();
}
}
}
if (logger.isDebugEnabled())
{
if (nodeRef != null) {logger.debug("Found NodeRef: " + nodeRef.toString());}
logger.debug("For property: " + propertyQName);
logger.debug("File name: " + filename);
logger.debug("Mimetype: " + mimetype);
logger.debug("Encoding: " + encoding);
logger.debug("Locale: " + locale);
}
// Check that the user has the permissions to write the content
if (permissionService.hasPermission(nodeRef, PermissionService.WRITE_CONTENT) == AccessStatus.DENIED)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("User does not have permissions to wrtie content for NodeRef: " + nodeRef.toString());
}
if (logger.isDebugEnabled())
{
logger.debug("Returning 403 Forbidden error...");
}
res.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
// Try and get the content writer
ContentWriter writer = contentService.getWriter(nodeRef, propertyQName, true);
if (writer == null)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Content writer cannot be obtained for NodeRef: " + nodeRef.toString());
}
res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED);
return;
}
// Set the mimetype, encoding and locale
writer.setMimetype(mimetype);
writer.setEncoding(encoding);
if (locale != null)
{
writer.setLocale(locale);
}
// Stream the content into the repository
writer.putContent(inputStream);
if (logger.isDebugEnabled() == true)
{
logger.debug("Content details: " + writer.getContentData().toString());
}
// Set return status
res.getWriter().write(writer.getContentData().toString());
res.flushBuffer();
if (logger.isDebugEnabled() == true)
{
logger.debug("UploadContentServlet done");
}
}
}
package org.alfresco.web.app.servlet;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Locale;
import java.util.StringTokenizer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.encoding.ContentCharsetFinder;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* Servlet responsible for streaming content directly into the repository from the PUT request.
* The appropriate mimetype is calculated based on filename extension.
* <p>
* The URL to the servlet should be generated thus:
* <pre>/alfresco/upload/workspace/SpacesStore/0000-0000-0000-0000/myfile.pdf</pre>
* or
* <pre>/alfresco/upload/myfile.pdf</pre>
* <p>
* If the store and node id are specified in the URL then the content provided will be streamed onto the node
* using an updating writer, updating the content property value accordingly.
* <p>
* If only the file name is specified the content will be streamed into the content store and the content data
* will be returned in the reposonse. This can then be used to update the value of a content property manually.
* Any used content will be cleared up in the usual manner.
* <p>
* By default, the download assumes that the content is on the
* {@link org.alfresco.model.ContentModel#PROP_CONTENT content property}.<br>
* To set the content of a specific model property, use a 'property' arg, providing the qualified name of the property.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
* <p>
* Guest access is currently disabled for this servlet.
*
* @author Roy Wetherall
*/
public class UploadContentServlet extends BaseServlet
{
/** Serial version UID */
private static final long serialVersionUID = 1055960980867420355L;
/** Logger */
private static Log logger = LogFactory.getLog(UploadContentServlet.class);
/** Default mime type */
protected static final String MIMETYPE_OCTET_STREAM = "application/octet-stream";
/** Argument properties */
protected static final String ARG_PROPERTY = "property";
protected static final String ARG_MIMETYPE = "mimetype";
protected static final String ARG_ENCODING = "encoding";
protected static final String ARG_LOCALE = "locale";
/**
* @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void doPut(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
{
if (logger.isDebugEnabled() == true)
{
String queryString = req.getQueryString();
logger.debug("Authenticating request to URL: " + req.getRequestURI()
+ ((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
AuthenticationStatus status = servletAuthenticate(req, res, false);
if (status == AuthenticationStatus.Failure || status == AuthenticationStatus.Guest)
{
res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// Tokenise the URI
String uri = req.getRequestURI();
uri = uri.substring(req.getContextPath().length());
StringTokenizer t = new StringTokenizer(uri, "/");
int tokenCount = t.countTokens();
t.nextToken(); // skip servlet name
// get or calculate the noderef and filename to download as
NodeRef nodeRef = null;
String filename = null;
QName propertyQName = null;
if (tokenCount == 2)
{
// filename is the only token
filename = t.nextToken();
}
else if (tokenCount == 4 || tokenCount == 5)
{
// assume 'workspace' or other NodeRef based protocol for remaining URL
// elements
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
String id = t.nextToken();
// build noderef from the appropriate URL elements
nodeRef = new NodeRef(storeRef, id);
if (tokenCount == 5)
{
// filename is last remaining token
filename = t.nextToken();
}
// get qualified of the property to get content from - default to
// ContentModel.PROP_CONTENT
propertyQName = ContentModel.PROP_CONTENT;
String property = req.getParameter(ARG_PROPERTY);
if (property != null && property.length() != 0)
{
propertyQName = QName.createQName(property);
}
}
else
{
logger.debug("Upload URL did not contain all required args: " + uri);
res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED);
return;
}
// get the services we need to retrieve the content
ServiceRegistry serviceRegistry = getServiceRegistry(getServletContext());
ContentService contentService = serviceRegistry.getContentService();
PermissionService permissionService = serviceRegistry.getPermissionService();
MimetypeService mimetypeService = serviceRegistry.getMimetypeService();
NodeService nodeService = serviceRegistry.getNodeService();
InputStream is = req.getInputStream();
BufferedInputStream inputStream = new BufferedInputStream(is);
// Sort out the mimetype
String mimetype = req.getParameter(ARG_MIMETYPE);
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MIMETYPE_OCTET_STREAM;
if (filename != null)
{
MimetypeService mimetypeMap = serviceRegistry.getMimetypeService();
int extIndex = filename.lastIndexOf('.');
if (extIndex != -1)
{
String ext = filename.substring(extIndex + 1);
mimetype = mimetypeService.getMimetype(ext);
}
}
}
// Get the encoding
String encoding = req.getParameter(ARG_ENCODING);
if (encoding == null || encoding.length() == 0)
{
// Get the encoding
ContentCharsetFinder charsetFinder = mimetypeService.getContentCharsetFinder();
Charset charset = charsetFinder.getCharset(inputStream, mimetype);
encoding = charset.name();
}
// Get the locale
Locale locale = I18NUtil.parseLocale(req.getParameter(ARG_LOCALE));
if (locale == null)
{
locale = I18NUtil.getContentLocale();
if (nodeRef != null)
{
ContentData contentData = (ContentData) nodeService.getProperty(nodeRef, propertyQName);
if (contentData != null)
{
locale = contentData.getLocale();
}
}
}
if (logger.isDebugEnabled())
{
if (nodeRef != null) {logger.debug("Found NodeRef: " + nodeRef.toString());}
logger.debug("For property: " + propertyQName);
logger.debug("File name: " + filename);
logger.debug("Mimetype: " + mimetype);
logger.debug("Encoding: " + encoding);
logger.debug("Locale: " + locale);
}
// Check that the user has the permissions to write the content
if (permissionService.hasPermission(nodeRef, PermissionService.WRITE_CONTENT) == AccessStatus.DENIED)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("User does not have permissions to wrtie content for NodeRef: " + nodeRef.toString());
}
if (logger.isDebugEnabled())
{
logger.debug("Returning 403 Forbidden error...");
}
res.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
// Try and get the content writer
ContentWriter writer = contentService.getWriter(nodeRef, propertyQName, true);
if (writer == null)
{
if (logger.isDebugEnabled() == true)
{
logger.debug("Content writer cannot be obtained for NodeRef: " + nodeRef.toString());
}
res.sendError(HttpServletResponse.SC_EXPECTATION_FAILED);
return;
}
// Set the mimetype, encoding and locale
writer.setMimetype(mimetype);
writer.setEncoding(encoding);
if (locale != null)
{
writer.setLocale(locale);
}
// Stream the content into the repository
writer.putContent(inputStream);
if (logger.isDebugEnabled() == true)
{
logger.debug("Content details: " + writer.getContentData().toString());
}
// Set return status
res.getWriter().write(writer.getContentData().toString());
res.flushBuffer();
if (logger.isDebugEnabled() == true)
{
logger.debug("UploadContentServlet done");
}
}
}

View File

@@ -1,107 +1,107 @@
package org.alfresco.web.app.servlet;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter;
import org.alfresco.repo.webdav.auth.BaseAuthenticationFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.webscripts.Description.RequiredAuthentication;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.RuntimeContainer;
/**
* WebScript aware Authentication Filter Class. Takes into account the authentication setting in the descriptor for the
* webscript before chaining to the downstream authentication filters. If authentication is not required then chains
* with the NO_AUTH_REQUIRED request attribute set, which should cause any downstream authentication filter to bypass
* authentication checks.
*
* @author Kevin Roast
* @author dward
*/
public class WebScriptSSOAuthenticationFilter extends BaseAuthenticationFilter implements DependencyInjectedFilter,
ActivateableBean
{
private static final Log logger = LogFactory.getLog(WebScriptSSOAuthenticationFilter.class);
private RuntimeContainer container;
private boolean isActive = true;
/**
* @param container the container to set
*/
public void setContainer(RuntimeContainer container)
{
this.container = container;
}
/**
* Activates or deactivates the bean
*
* @param active
* <code>true</code> if the bean is active and initialization should complete
*/
public final void setActive(boolean active)
{
this.isActive = active;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive()
*/
public final boolean isActive()
{
return isActive;
}
/* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#doFilter(javax.servlet.ServletContext, javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletContext context, ServletRequest sreq, ServletResponse sresp, FilterChain chain)
throws IOException, ServletException
{
// Get the HTTP request/response
HttpServletRequest req = (HttpServletRequest)sreq;
// find a webscript match for the requested URI
String requestURI = req.getRequestURI();
String pathInfo = requestURI.substring((req.getContextPath() + req.getServletPath()).length());
if (getLogger().isDebugEnabled())
getLogger().debug("Processing request: " + requestURI + " SID:" +
(req.getSession(false) != null ? req.getSession().getId() : null));
Match match = container.getRegistry().findWebScript(req.getMethod(), URLDecoder.decode(pathInfo));
if (match != null && match.getWebScript() != null)
{
// check the authentication required - if none then we don't want any of
// the filters down the chain to require any authentication checks
if (RequiredAuthentication.none == match.getWebScript().getDescription().getRequiredAuthentication())
{
if (getLogger().isDebugEnabled())
getLogger().debug("Found webscript with no authentication - set NO_AUTH_REQUIRED flag.");
req.setAttribute(NO_AUTH_REQUIRED, Boolean.TRUE);
}
}
chain.doFilter(sreq, sresp);
}
/* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseAuthenticationFilter#getLogger()
*/
@Override
protected Log getLogger()
{
return logger;
}
}
package org.alfresco.web.app.servlet;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.repo.management.subsystems.ActivateableBean;
import org.alfresco.repo.web.filter.beans.DependencyInjectedFilter;
import org.alfresco.repo.webdav.auth.BaseAuthenticationFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.URLDecoder;
import org.springframework.extensions.webscripts.Description.RequiredAuthentication;
import org.springframework.extensions.webscripts.Match;
import org.springframework.extensions.webscripts.RuntimeContainer;
/**
* WebScript aware Authentication Filter Class. Takes into account the authentication setting in the descriptor for the
* webscript before chaining to the downstream authentication filters. If authentication is not required then chains
* with the NO_AUTH_REQUIRED request attribute set, which should cause any downstream authentication filter to bypass
* authentication checks.
*
* @author Kevin Roast
* @author dward
*/
public class WebScriptSSOAuthenticationFilter extends BaseAuthenticationFilter implements DependencyInjectedFilter,
ActivateableBean
{
private static final Log logger = LogFactory.getLog(WebScriptSSOAuthenticationFilter.class);
private RuntimeContainer container;
private boolean isActive = true;
/**
* @param container the container to set
*/
public void setContainer(RuntimeContainer container)
{
this.container = container;
}
/**
* Activates or deactivates the bean
*
* @param active
* <code>true</code> if the bean is active and initialization should complete
*/
public final void setActive(boolean active)
{
this.isActive = active;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive()
*/
public final boolean isActive()
{
return isActive;
}
/* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#doFilter(javax.servlet.ServletContext, javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletContext context, ServletRequest sreq, ServletResponse sresp, FilterChain chain)
throws IOException, ServletException
{
// Get the HTTP request/response
HttpServletRequest req = (HttpServletRequest)sreq;
// find a webscript match for the requested URI
String requestURI = req.getRequestURI();
String pathInfo = requestURI.substring((req.getContextPath() + req.getServletPath()).length());
if (getLogger().isDebugEnabled())
getLogger().debug("Processing request: " + requestURI + " SID:" +
(req.getSession(false) != null ? req.getSession().getId() : null));
Match match = container.getRegistry().findWebScript(req.getMethod(), URLDecoder.decode(pathInfo));
if (match != null && match.getWebScript() != null)
{
// check the authentication required - if none then we don't want any of
// the filters down the chain to require any authentication checks
if (RequiredAuthentication.none == match.getWebScript().getDescription().getRequiredAuthentication())
{
if (getLogger().isDebugEnabled())
getLogger().debug("Found webscript with no authentication - set NO_AUTH_REQUIRED flag.");
req.setAttribute(NO_AUTH_REQUIRED, Boolean.TRUE);
}
}
chain.doFilter(sreq, sresp);
}
/* (non-Javadoc)
* @see org.alfresco.repo.webdav.auth.BaseAuthenticationFilter#getLogger()
*/
@Override
protected Log getLogger()
{
return logger;
}
}

View File

@@ -1,37 +1,37 @@
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Interface for all Ajax commands executed by this servlet.
*
* The method is responsible for invoking the underlying managed bean
* and dealing with the response.
*
* @author gavinc
*/
public interface AjaxCommand
{
/**
* Invokes the relevant method on the bean represented by the given
* expression. Parameters required to call the method can be retrieved
* from the request.
*
* Currently the content type of the response will always be text/xml, in the
* future sublcasses may provide a mechanism to allow the content type to be set
* dynamically.
*
* @param facesContext FacesContext
* @param expression The binding expression
* @param request The request
* @param response The response
*/
public abstract void execute(FacesContext facesContext, String expression,
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Interface for all Ajax commands executed by this servlet.
*
* The method is responsible for invoking the underlying managed bean
* and dealing with the response.
*
* @author gavinc
*/
public interface AjaxCommand
{
/**
* Invokes the relevant method on the bean represented by the given
* expression. Parameters required to call the method can be retrieved
* from the request.
*
* Currently the content type of the response will always be text/xml, in the
* future sublcasses may provide a mechanism to allow the content type to be set
* dynamically.
*
* @param facesContext FacesContext
* @param expression The binding expression
* @param request The request
* @param response The response
*/
public abstract void execute(FacesContext facesContext, String expression,
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;
}

View File

@@ -1,197 +1,197 @@
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import java.util.Enumeration;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.acegisecurity.context.ContextHolder;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.web.app.servlet.AuthenticationStatus;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.app.servlet.FacesHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for processing AJAX requests.
*
* The URL to the servlet should be in the form:
* <pre>/alfresco/ajax/command/Bean.binding.expression</pre>
* <p>
* See http://wiki.alfresco.com/wiki/AJAX_Support for details.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
*
* @author gavinc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class AjaxServlet extends BaseServlet
{
public static final String AJAX_LOG_KEY = "alfresco.ajax";
protected enum Command { invoke, get, set};
private static final long serialVersionUID = -7654769105419391840L;
private static Log logger = LogFactory.getLog(AJAX_LOG_KEY);
private static Log headersLogger = LogFactory.getLog(AJAX_LOG_KEY + ".headers");
private static Log perfLogger = LogFactory.getLog(AJAX_LOG_KEY + ".performance");
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(final HttpServletRequest request,
final HttpServletResponse response)
throws ServletException, IOException
{
request.setCharacterEncoding("utf-8");
// set default character encoding for the response
response.setCharacterEncoding("utf-8");
response.setContentType("text/xml;charset=UTF-8");
long startTime = 0;
String uri = request.getRequestURI();
if (logger.isDebugEnabled())
{
final String queryString = request.getQueryString();
logger.debug("Processing URL: " + uri +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
// dump the request headers
if (headersLogger.isDebugEnabled())
{
final Enumeration<?> headers = request.getHeaderNames();
while (headers.hasMoreElements())
{
final String name = (String)headers.nextElement();
headersLogger.debug(name + ": " + request.getHeader(name));
}
}
try
{
// Make sure the user is authenticated, if not throw an error to return the
// 500 Internal Server Error code back to the client
AuthenticationStatus status = servletAuthenticate(request, response, false);
if (status == AuthenticationStatus.Failure)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Access Denied: User not authenticated");
return;
}
setNoCacheHeaders(response);
uri = uri.substring(request.getContextPath().length() + "/".length());
final String[] tokens = uri.split("/");
if (tokens.length < 3)
{
throw new AlfrescoRuntimeException("Servlet URL did not contain all required args: " + uri);
}
// retrieve the command from the URL
final String commandName = tokens[1];
// retrieve the binding expression from the URL
final String expression = tokens[2];
// setup the faces context
final FacesContext facesContext = FacesHelper.getFacesContext(request, response, getServletContext());
// start a timer
if (perfLogger.isDebugEnabled())
startTime = System.currentTimeMillis();
// instantiate the relevant command
AjaxCommand command = null;
if (Command.invoke.toString().equals(commandName))
{
command = new InvokeCommand();
}
else if (Command.get.toString().equals(commandName))
{
command = new GetCommand();
}
else
{
throw new AlfrescoRuntimeException("Unrecognised command received: " + commandName);
}
// execute the command
command.execute(facesContext, expression, request, response);
}
catch (RuntimeException error)
{
handleError(response, error);
}
finally
{
// measure the time taken
if (perfLogger.isDebugEnabled())
{
perfLogger.debug("Time to execute command: " + (System.currentTimeMillis() - startTime) + "ms");
}
ContextHolder.setContext(null);
}
}
/**
* Handles any error that occurs during the execution of the servlet
*
* @param response The response
* @param cause The cause of the error
*/
protected void handleError(HttpServletResponse response, RuntimeException cause)
throws ServletException, IOException
{
// if we can send back the 500 error with the error from the top of the
// stack as the error status message.
// NOTE: if we use the built in support for generating error pages for
// 500 errors we can tailor the output for AJAX calls so that the
// body of the response can be used to show the error details.
if (!response.isCommitted())
{
// dump the error if debugging is enabled
if (logger.isDebugEnabled())
{
logger.error(cause);
Throwable theCause = cause.getCause();
if (theCause != null)
{
logger.error("caused by: ", theCause);
}
}
// extract a message from the exception
String msg = cause.getMessage();
if (msg == null)
{
msg = cause.toString();
}
// ALF-9036. We need to trap incomplete sessions
if (cause instanceof IllegalStateException)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, cause.getMessage());
}
else
{
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
}
}
else
{
// the response has already been comitted, not much we can do but
// let the error through and let the container deal with it
throw cause;
}
}
}
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import java.util.Enumeration;
import javax.faces.context.FacesContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.acegisecurity.context.ContextHolder;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.web.app.servlet.AuthenticationStatus;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.app.servlet.FacesHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Servlet responsible for processing AJAX requests.
*
* The URL to the servlet should be in the form:
* <pre>/alfresco/ajax/command/Bean.binding.expression</pre>
* <p>
* See http://wiki.alfresco.com/wiki/AJAX_Support for details.
* <p>
* Like most Alfresco servlets, the URL may be followed by a valid 'ticket' argument for authentication:
* ?ticket=1234567890
*
* @author gavinc
* @deprecated 5.0 not exposed in web-client web.xml
*/
public class AjaxServlet extends BaseServlet
{
public static final String AJAX_LOG_KEY = "alfresco.ajax";
protected enum Command { invoke, get, set};
private static final long serialVersionUID = -7654769105419391840L;
private static Log logger = LogFactory.getLog(AJAX_LOG_KEY);
private static Log headersLogger = LogFactory.getLog(AJAX_LOG_KEY + ".headers");
private static Log perfLogger = LogFactory.getLog(AJAX_LOG_KEY + ".performance");
/**
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
protected void service(final HttpServletRequest request,
final HttpServletResponse response)
throws ServletException, IOException
{
request.setCharacterEncoding("utf-8");
// set default character encoding for the response
response.setCharacterEncoding("utf-8");
response.setContentType("text/xml;charset=UTF-8");
long startTime = 0;
String uri = request.getRequestURI();
if (logger.isDebugEnabled())
{
final String queryString = request.getQueryString();
logger.debug("Processing URL: " + uri +
((queryString != null && queryString.length() > 0) ? ("?" + queryString) : ""));
}
// dump the request headers
if (headersLogger.isDebugEnabled())
{
final Enumeration<?> headers = request.getHeaderNames();
while (headers.hasMoreElements())
{
final String name = (String)headers.nextElement();
headersLogger.debug(name + ": " + request.getHeader(name));
}
}
try
{
// Make sure the user is authenticated, if not throw an error to return the
// 500 Internal Server Error code back to the client
AuthenticationStatus status = servletAuthenticate(request, response, false);
if (status == AuthenticationStatus.Failure)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Access Denied: User not authenticated");
return;
}
setNoCacheHeaders(response);
uri = uri.substring(request.getContextPath().length() + "/".length());
final String[] tokens = uri.split("/");
if (tokens.length < 3)
{
throw new AlfrescoRuntimeException("Servlet URL did not contain all required args: " + uri);
}
// retrieve the command from the URL
final String commandName = tokens[1];
// retrieve the binding expression from the URL
final String expression = tokens[2];
// setup the faces context
final FacesContext facesContext = FacesHelper.getFacesContext(request, response, getServletContext());
// start a timer
if (perfLogger.isDebugEnabled())
startTime = System.currentTimeMillis();
// instantiate the relevant command
AjaxCommand command = null;
if (Command.invoke.toString().equals(commandName))
{
command = new InvokeCommand();
}
else if (Command.get.toString().equals(commandName))
{
command = new GetCommand();
}
else
{
throw new AlfrescoRuntimeException("Unrecognised command received: " + commandName);
}
// execute the command
command.execute(facesContext, expression, request, response);
}
catch (RuntimeException error)
{
handleError(response, error);
}
finally
{
// measure the time taken
if (perfLogger.isDebugEnabled())
{
perfLogger.debug("Time to execute command: " + (System.currentTimeMillis() - startTime) + "ms");
}
ContextHolder.setContext(null);
}
}
/**
* Handles any error that occurs during the execution of the servlet
*
* @param response The response
* @param cause The cause of the error
*/
protected void handleError(HttpServletResponse response, RuntimeException cause)
throws ServletException, IOException
{
// if we can send back the 500 error with the error from the top of the
// stack as the error status message.
// NOTE: if we use the built in support for generating error pages for
// 500 errors we can tailor the output for AJAX calls so that the
// body of the response can be used to show the error details.
if (!response.isCommitted())
{
// dump the error if debugging is enabled
if (logger.isDebugEnabled())
{
logger.error(cause);
Throwable theCause = cause.getCause();
if (theCause != null)
{
logger.error("caused by: ", theCause);
}
}
// extract a message from the exception
String msg = cause.getMessage();
if (msg == null)
{
msg = cause.toString();
}
// ALF-9036. We need to trap incomplete sessions
if (cause instanceof IllegalStateException)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, cause.getMessage());
}
else
{
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
}
}
else
{
// the response has already been comitted, not much we can do but
// let the error through and let the container deal with it
throw cause;
}
}
}

View File

@@ -1,19 +1,19 @@
package org.alfresco.web.app.servlet.ajax;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Base class for all Ajax based commands
*
* @author gavinc
*/
public abstract class BaseAjaxCommand implements AjaxCommand
{
protected static Log logger = LogFactory.getLog(AjaxServlet.AJAX_LOG_KEY);
public String makeBindingExpression(String expression)
{
return "#{" + expression + "}";
}
}
package org.alfresco.web.app.servlet.ajax;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Base class for all Ajax based commands
*
* @author gavinc
*/
public abstract class BaseAjaxCommand implements AjaxCommand
{
protected static Log logger = LogFactory.getLog(AjaxServlet.AJAX_LOG_KEY);
public String makeBindingExpression(String expression)
{
return "#{" + expression + "}";
}
}

View File

@@ -1,69 +1,69 @@
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.web.bean.repository.Repository;
/**
* Command that executes the given value binding expression.
* <p>
* This command is intended to be used for calling existing managed
* bean methods. The result of the value binding is added to
* the response as is i.e. by calling toString().
* The content type of the response is always text/html.
*
* @author gavinc
*/
public class GetCommand extends BaseAjaxCommand
{
public void execute(FacesContext facesContext, String expression,
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// create the JSF binding expression
String bindingExpr = makeBindingExpression(expression);
if (logger.isDebugEnabled())
logger.debug("Retrieving value from value binding: " + bindingExpr);
UserTransaction tx = null;
try
{
// create the value binding
ValueBinding binding = facesContext.getApplication().
createValueBinding(bindingExpr);
if (binding != null)
{
// setup the transaction
tx = Repository.getUserTransaction(facesContext, true);
tx.begin();
// get the value from the value binding
Object value = binding.getValue(facesContext);
if (value != null)
{
response.getWriter().write(value.toString());
}
// commit
tx.commit();
}
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
throw new AlfrescoRuntimeException("Failed to retrieve value: " + err.getMessage(), err);
}
}
}
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.UserTransaction;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.web.bean.repository.Repository;
/**
* Command that executes the given value binding expression.
* <p>
* This command is intended to be used for calling existing managed
* bean methods. The result of the value binding is added to
* the response as is i.e. by calling toString().
* The content type of the response is always text/html.
*
* @author gavinc
*/
public class GetCommand extends BaseAjaxCommand
{
public void execute(FacesContext facesContext, String expression,
HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// create the JSF binding expression
String bindingExpr = makeBindingExpression(expression);
if (logger.isDebugEnabled())
logger.debug("Retrieving value from value binding: " + bindingExpr);
UserTransaction tx = null;
try
{
// create the value binding
ValueBinding binding = facesContext.getApplication().
createValueBinding(bindingExpr);
if (binding != null)
{
// setup the transaction
tx = Repository.getUserTransaction(facesContext, true);
tx.begin();
// get the value from the value binding
Object value = binding.getValue(facesContext);
if (value != null)
{
response.getWriter().write(value.toString());
}
// commit
tx.commit();
}
}
catch (Throwable err)
{
// rollback the transaction
try { if (tx != null) {tx.rollback();} } catch (Exception ex) {}
throw new AlfrescoRuntimeException("Failed to retrieve value: " + err.getMessage(), err);
}
}
}

View File

@@ -1,218 +1,218 @@
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
/**
* Command that invokes the method represented by the expression.
* <p>
* The managed bean method called is responsible for writing the response
* by getting hold of the JSF ResponseWriter. Parameters can also be
* retrieved via the JSF ExternalContext object.
* <p>
* In a future release (if required) annotations may be used to state
* what content type to use for the response.
*
* @author gavinc
*/
public class InvokeCommand extends BaseAjaxCommand
{
/////////////////////////////////////////////////////////////////////////////
/**
* Annotation for a bean method that handles an ajax request.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResponseMimetype
{
// NOTE: replaced Mimetype.MIMETYPE_XML with string literal due to bug
// http://bugs.sun.com/view_bug.do?bug_id=6512707 - causing build to fail
public String value() default "text/xml";
}
/////////////////////////////////////////////////////////////////////////////
public void execute(final FacesContext facesContext,
final String expression,
final HttpServletRequest request,
final HttpServletResponse response)
throws ServletException, IOException
{
ResponseWriter writer = null;
try
{
final int indexOfDot = expression.indexOf('.');
final String variableName = expression.substring(0, indexOfDot);
final String methodName = expression.substring(indexOfDot + 1);
if (logger.isDebugEnabled())
logger.debug("Invoking method represented by " + expression +
" on variable " + variableName +
" with method " + methodName);
Object bean = null;
if (Application.inPortalServer())
{
// retrieve the managed bean, this is really weak but if the
// request comes from a portal server the bean we need to get
// is in the session with a prefix chosen by the portal vendor,
// to cover this scenario we have to go through the names of
// all the objects in the session to find the bean we want.
String beanNameSuffix = "?" + variableName;
Enumeration<?> enumNames = request.getSession().getAttributeNames();
while (enumNames.hasMoreElements())
{
String name = (String)enumNames.nextElement();
if (name.endsWith(beanNameSuffix))
{
bean = request.getSession().getAttribute(name);
if (logger.isDebugEnabled())
logger.debug("Found bean " + bean + " in the session");
break;
}
}
}
// if we don't have the bean yet try and get it via the variable resolver
if (bean == null)
{
VariableResolver vr = facesContext.getApplication().getVariableResolver();
bean = vr.resolveVariable(facesContext, variableName);
if (logger.isDebugEnabled())
logger.debug("Created bean " + bean + " via the variable resolver");
}
final Method method = bean.getClass().getMethod(methodName);
final String responseMimetype =
(method.isAnnotationPresent(ResponseMimetype.class)
? method.getAnnotation(ResponseMimetype.class).value()
: MimetypeMap.MIMETYPE_XML);
if (logger.isDebugEnabled())
logger.debug("invoking method " + method +
" with repsonse mimetype " + responseMimetype);
writer = this.setupResponseWriter(responseMimetype,
response,
facesContext);
// setup the transaction
RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance());
final Object beanFinal = bean;
RetryingTransactionCallback<Object> callback = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
// invoke the method
try
{
method.invoke(beanFinal);
return null;
}
// Let's prevent RuntimeExceptions being wrapped twice by unwrapping InvocationTargetExceptions
catch (InvocationTargetException e)
{
if (e.getCause() != null)
{
throw e.getCause();
}
throw e;
}
}
};
txnHelper.doInTransaction(callback);
}
catch (EvaluationException e)
{
Throwable err = e.getCause();
if (err == null)
{
logger.error("Failed to execute method " + expression + ": " + e.getMessage(), e);
throw e;
}
else
{
logger.error("Failed to execute method " + expression + ": " + err.getMessage(), err);
if (err instanceof RuntimeException)
{
throw (RuntimeException)err;
}
else
{
throw new AlfrescoRuntimeException("Failed to execute method " + expression + ": " + err.getMessage(), err);
}
}
}
catch (RuntimeException err)
{
logger.error("Failed to execute method " + expression + ": " + err.getMessage(), err);
throw err;
}
catch (Exception err)
{
logger.error("Failed to execute method " + expression + ": " + err.getMessage(), err);
throw new AlfrescoRuntimeException("Failed to execute method " + expression + ": " + err.getMessage(), err);
}
// force the output back to the client
writer.close();
}
/** setup the JSF response writer. */
private ResponseWriter setupResponseWriter(final String mimetype,
final HttpServletResponse response,
final FacesContext facesContext)
throws IOException
{
final OutputStream os = response.getOutputStream();
final UIViewRoot viewRoot = facesContext.getViewRoot();
final RenderKitFactory renderFactory = (RenderKitFactory)
FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
final RenderKit renderKit =
renderFactory.getRenderKit(facesContext, viewRoot.getRenderKitId());
final ResponseWriter writer =
renderKit.createResponseWriter(new OutputStreamWriter(os, "UTF-8"),
mimetype,
"UTF-8");
facesContext.setResponseWriter(writer);
// must be text/xml otherwise IE doesn't parse the response properly into responseXML
response.setContentType(mimetype);
return writer;
}
}
package org.alfresco.web.app.servlet.ajax;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
/**
* Command that invokes the method represented by the expression.
* <p>
* The managed bean method called is responsible for writing the response
* by getting hold of the JSF ResponseWriter. Parameters can also be
* retrieved via the JSF ExternalContext object.
* <p>
* In a future release (if required) annotations may be used to state
* what content type to use for the response.
*
* @author gavinc
*/
public class InvokeCommand extends BaseAjaxCommand
{
/////////////////////////////////////////////////////////////////////////////
/**
* Annotation for a bean method that handles an ajax request.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ResponseMimetype
{
// NOTE: replaced Mimetype.MIMETYPE_XML with string literal due to bug
// http://bugs.sun.com/view_bug.do?bug_id=6512707 - causing build to fail
public String value() default "text/xml";
}
/////////////////////////////////////////////////////////////////////////////
public void execute(final FacesContext facesContext,
final String expression,
final HttpServletRequest request,
final HttpServletResponse response)
throws ServletException, IOException
{
ResponseWriter writer = null;
try
{
final int indexOfDot = expression.indexOf('.');
final String variableName = expression.substring(0, indexOfDot);
final String methodName = expression.substring(indexOfDot + 1);
if (logger.isDebugEnabled())
logger.debug("Invoking method represented by " + expression +
" on variable " + variableName +
" with method " + methodName);
Object bean = null;
if (Application.inPortalServer())
{
// retrieve the managed bean, this is really weak but if the
// request comes from a portal server the bean we need to get
// is in the session with a prefix chosen by the portal vendor,
// to cover this scenario we have to go through the names of
// all the objects in the session to find the bean we want.
String beanNameSuffix = "?" + variableName;
Enumeration<?> enumNames = request.getSession().getAttributeNames();
while (enumNames.hasMoreElements())
{
String name = (String)enumNames.nextElement();
if (name.endsWith(beanNameSuffix))
{
bean = request.getSession().getAttribute(name);
if (logger.isDebugEnabled())
logger.debug("Found bean " + bean + " in the session");
break;
}
}
}
// if we don't have the bean yet try and get it via the variable resolver
if (bean == null)
{
VariableResolver vr = facesContext.getApplication().getVariableResolver();
bean = vr.resolveVariable(facesContext, variableName);
if (logger.isDebugEnabled())
logger.debug("Created bean " + bean + " via the variable resolver");
}
final Method method = bean.getClass().getMethod(methodName);
final String responseMimetype =
(method.isAnnotationPresent(ResponseMimetype.class)
? method.getAnnotation(ResponseMimetype.class).value()
: MimetypeMap.MIMETYPE_XML);
if (logger.isDebugEnabled())
logger.debug("invoking method " + method +
" with repsonse mimetype " + responseMimetype);
writer = this.setupResponseWriter(responseMimetype,
response,
facesContext);
// setup the transaction
RetryingTransactionHelper txnHelper = Repository.getRetryingTransactionHelper(FacesContext.getCurrentInstance());
final Object beanFinal = bean;
RetryingTransactionCallback<Object> callback = new RetryingTransactionCallback<Object>()
{
public Object execute() throws Throwable
{
// invoke the method
try
{
method.invoke(beanFinal);
return null;
}
// Let's prevent RuntimeExceptions being wrapped twice by unwrapping InvocationTargetExceptions
catch (InvocationTargetException e)
{
if (e.getCause() != null)
{
throw e.getCause();
}
throw e;
}
}
};
txnHelper.doInTransaction(callback);
}
catch (EvaluationException e)
{
Throwable err = e.getCause();
if (err == null)
{
logger.error("Failed to execute method " + expression + ": " + e.getMessage(), e);
throw e;
}
else
{
logger.error("Failed to execute method " + expression + ": " + err.getMessage(), err);
if (err instanceof RuntimeException)
{
throw (RuntimeException)err;
}
else
{
throw new AlfrescoRuntimeException("Failed to execute method " + expression + ": " + err.getMessage(), err);
}
}
}
catch (RuntimeException err)
{
logger.error("Failed to execute method " + expression + ": " + err.getMessage(), err);
throw err;
}
catch (Exception err)
{
logger.error("Failed to execute method " + expression + ": " + err.getMessage(), err);
throw new AlfrescoRuntimeException("Failed to execute method " + expression + ": " + err.getMessage(), err);
}
// force the output back to the client
writer.close();
}
/** setup the JSF response writer. */
private ResponseWriter setupResponseWriter(final String mimetype,
final HttpServletResponse response,
final FacesContext facesContext)
throws IOException
{
final OutputStream os = response.getOutputStream();
final UIViewRoot viewRoot = facesContext.getViewRoot();
final RenderKitFactory renderFactory = (RenderKitFactory)
FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
final RenderKit renderKit =
renderFactory.getRenderKit(facesContext, viewRoot.getRenderKitId());
final ResponseWriter writer =
renderKit.createResponseWriter(new OutputStreamWriter(os, "UTF-8"),
mimetype,
"UTF-8");
facesContext.setResponseWriter(writer);
// must be text/xml otherwise IE doesn't parse the response properly into responseXML
response.setContentType(mimetype);
return writer;
}
}

View File

@@ -1,45 +1,45 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.web.bean.workflow.WorkflowUtil;
/**
* Approve Workflow command implementation
*
* @author Kevin Roast
*/
public final class ApproveWorkflowCommand implements Command
{
public static final String PROP_TARGET = "target";
private static final String[] PROPERTIES = new String[] {PROP_TARGET};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
// get the target Node for the command
NodeRef nodeRef = (NodeRef)properties.get(PROP_TARGET);
if (nodeRef == null)
{
throw new IllegalArgumentException(
"Unable to execute ApproveCommand - mandatory parameter not supplied: " + PROP_TARGET);
}
WorkflowUtil.approve(nodeRef, serviceRegistry.getNodeService(), serviceRegistry.getCopyService());
return true;
}
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.web.bean.workflow.WorkflowUtil;
/**
* Approve Workflow command implementation
*
* @author Kevin Roast
*/
public final class ApproveWorkflowCommand implements Command
{
public static final String PROP_TARGET = "target";
private static final String[] PROPERTIES = new String[] {PROP_TARGET};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
// get the target Node for the command
NodeRef nodeRef = (NodeRef)properties.get(PROP_TARGET);
if (nodeRef == null)
{
throw new IllegalArgumentException(
"Unable to execute ApproveCommand - mandatory parameter not supplied: " + PROP_TARGET);
}
WorkflowUtil.approve(nodeRef, serviceRegistry.getNodeService(), serviceRegistry.getCopyService());
return true;
}
}

View File

@@ -1,47 +1,47 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import javax.servlet.ServletContext;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.web.bean.repository.Repository;
/**
* Initial implementation of a Command Processor that is always passed enough URL elements
* to construct a single NodeRef argument. The NodeRef is checked against READ permissions
* for the current user during the validateArguments() call.
* <p>
* This class should be enough to form the base of Command Processor objects that only require
* a single NodeRef passed on the URL.
*
* @author Kevin Roast
*/
public abstract class BaseNodeCommandProcessor implements CommandProcessor
{
protected NodeRef targetRef;
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements)
{
if (urlElements.length < 3)
{
throw new IllegalArgumentException("Not enough URL arguments passed to command servlet.");
}
// get NodeRef to the node with the workflow attached to it
StoreRef storeRef = new StoreRef(urlElements[0], urlElements[1]);
this.targetRef = new NodeRef(storeRef, urlElements[2]);
// get the services we need to execute the workflow command
PermissionService permissionService = Repository.getServiceRegistry(sc).getPermissionService();
// check that the user has at least READ access on the node - else redirect to the login page
return (permissionService.hasPermission(this.targetRef, PermissionService.READ) == AccessStatus.ALLOWED);
}
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import javax.servlet.ServletContext;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.web.bean.repository.Repository;
/**
* Initial implementation of a Command Processor that is always passed enough URL elements
* to construct a single NodeRef argument. The NodeRef is checked against READ permissions
* for the current user during the validateArguments() call.
* <p>
* This class should be enough to form the base of Command Processor objects that only require
* a single NodeRef passed on the URL.
*
* @author Kevin Roast
*/
public abstract class BaseNodeCommandProcessor implements CommandProcessor
{
protected NodeRef targetRef;
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements)
{
if (urlElements.length < 3)
{
throw new IllegalArgumentException("Not enough URL arguments passed to command servlet.");
}
// get NodeRef to the node with the workflow attached to it
StoreRef storeRef = new StoreRef(urlElements[0], urlElements[1]);
this.targetRef = new NodeRef(storeRef, urlElements[2]);
// get the services we need to execute the workflow command
PermissionService permissionService = Repository.getServiceRegistry(sc).getPermissionService();
// check that the user has at least READ access on the node - else redirect to the login page
return (permissionService.hasPermission(this.targetRef, PermissionService.READ) == AccessStatus.ALLOWED);
}
}

View File

@@ -1,15 +1,15 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
/**
* @author Kevin Roast
*/
public abstract class BaseUIActionCommand implements Command
{
public static final String PROP_SERVLETCONTEXT = "ServletContext";
public static final String PROP_REQUEST = "Request";
public static final String PROP_RESPONSE = "Response";
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
/**
* @author Kevin Roast
*/
public abstract class BaseUIActionCommand implements Command
{
public static final String PROP_SERVLETCONTEXT = "ServletContext";
public static final String PROP_REQUEST = "Request";
public static final String PROP_RESPONSE = "Response";
}

View File

@@ -1,28 +1,28 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
/**
* Simple servlet command pattern interface.
*
* @author Kevin Roast
*/
public interface Command
{
/**
* Execute the command
*
* @param serviceRegistry The ServiceRegistry instance
* @param properties Bag of named properties for the command
*
* @return return value from the command if any
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties);
/**
* @return the names of the properties required for this command
*/
public String[] getPropertyNames();
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
/**
* Simple servlet command pattern interface.
*
* @author Kevin Roast
*/
public interface Command
{
/**
* Execute the command
*
* @param serviceRegistry The ServiceRegistry instance
* @param properties Bag of named properties for the command
*
* @return return value from the command if any
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties);
/**
* @return the names of the properties required for this command
*/
public String[] getPropertyNames();
}

View File

@@ -1,81 +1,81 @@
package org.alfresco.web.app.servlet.command;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Command Factory helper
*
* @author Kevin Roast
*/
public final class CommandFactory
{
private static Log logger = LogFactory.getLog(CommandFactory.class);
private static CommandFactory instance = new CommandFactory();
private static Map<String, Class> registry = new HashMap<String, Class>(16, 1.0f);
/**
* Private constructor - protect the singleton instance
*/
private CommandFactory()
{
}
/**
* @return the singleton CommandFactory instance
*/
public static CommandFactory getInstance()
{
return instance;
}
/**
* Register a command name against an implementation
*
* @param name Unique name of the command
* @param clazz Class implementation of the command
*/
public void registerCommand(String name, Class clazz)
{
registry.put(name, clazz);
}
/**
* Create a command instance of the specified command name
*
* @param name Name of the command to create (must be registered)
*
* @return the Command instance or null if not found
*/
public Command createCommand(String name)
{
Command result = null;
// lookup command by name in the registry
Class clazz = registry.get(name);
if (clazz != null)
{
try
{
Object obj = clazz.newInstance();
if (obj instanceof Command)
{
result = (Command)obj;
}
}
catch (Throwable err)
{
// return default if this occurs
logger.warn("Unable to create workflow command instance '" + name +
"' with classname '" + clazz.getName() + "' due to error: " + err.getMessage());
}
}
return result;
}
}
package org.alfresco.web.app.servlet.command;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Command Factory helper
*
* @author Kevin Roast
*/
public final class CommandFactory
{
private static Log logger = LogFactory.getLog(CommandFactory.class);
private static CommandFactory instance = new CommandFactory();
private static Map<String, Class> registry = new HashMap<String, Class>(16, 1.0f);
/**
* Private constructor - protect the singleton instance
*/
private CommandFactory()
{
}
/**
* @return the singleton CommandFactory instance
*/
public static CommandFactory getInstance()
{
return instance;
}
/**
* Register a command name against an implementation
*
* @param name Unique name of the command
* @param clazz Class implementation of the command
*/
public void registerCommand(String name, Class clazz)
{
registry.put(name, clazz);
}
/**
* Create a command instance of the specified command name
*
* @param name Name of the command to create (must be registered)
*
* @return the Command instance or null if not found
*/
public Command createCommand(String name)
{
Command result = null;
// lookup command by name in the registry
Class clazz = registry.get(name);
if (clazz != null)
{
try
{
Object obj = clazz.newInstance();
if (obj instanceof Command)
{
result = (Command)obj;
}
}
catch (Throwable err)
{
// return default if this occurs
logger.warn("Unable to create workflow command instance '" + name +
"' with classname '" + clazz.getName() + "' due to error: " + err.getMessage());
}
}
return result;
}
}

View File

@@ -1,63 +1,63 @@
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.service.ServiceRegistry;
/**
* This interfaces defines the contract and lifecycle of a Servlet Command Processor.
* <p>
* A command processor is defined as a class capable of executing a set of related Command
* objects. It performs the bulk of the work for the command servlet. The processor impl
* is responsible for validating that the command can be processed (given the supplied remaining
* URL arguments from the servlet) and processing the command. It is also responsible for
* supply an output status page on successfuly execution of the command.
* <p>
* The arguments passed to a Command Processor are the remaining URL elements from the command
* servlet URL after removing the web-app name, servlet name and command processor name.
*
* @author Kevin Roast
*/
public interface CommandProcessor
{
/**
* Pass and validate URL arguments for the command processor. Validate if the command can be
* executed given the arguments supplied. Generally at this post a Command Processor will
* convert the supplied arguments to the objects it expects, and also check any permissions
* that are required by the current user to execute the command.
*
* @param sc ServletContext, can be used to retrieve ServiceRegistry instance
* from the Repository bean.
* @param command Name of the command the arguments are for
* @param args Map of URL args passed to the command servlet
* @param urlElements String[] of the remaining URL arguments to the command servlet
*
* @return true if the command can be executed by the current user given the supplied args.
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements);
/**
* Process the supplied command name. It is the responsibility of the Command Processor
* to lookup the specified command name using the CommandFactory registry. For that reason
* it also has the responsiblity to initially register commands it is responsible for so
* they can be constructed later. If the supplied command is unknown to it then an
* exception should be thrown to indicate this.
*
* @param serviceRegistry ServiceRegistry
* @param request HttpServletRequest
* @param command Name of the command to construct and execute
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command);
/**
* Output a simple status message to the supplied PrintWriter.
* It can be assumed that the process() method was successful if this method is called.
*
* @param out PrintWriter
*/
public void outputStatus(PrintWriter out);
}
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.service.ServiceRegistry;
/**
* This interfaces defines the contract and lifecycle of a Servlet Command Processor.
* <p>
* A command processor is defined as a class capable of executing a set of related Command
* objects. It performs the bulk of the work for the command servlet. The processor impl
* is responsible for validating that the command can be processed (given the supplied remaining
* URL arguments from the servlet) and processing the command. It is also responsible for
* supply an output status page on successfuly execution of the command.
* <p>
* The arguments passed to a Command Processor are the remaining URL elements from the command
* servlet URL after removing the web-app name, servlet name and command processor name.
*
* @author Kevin Roast
*/
public interface CommandProcessor
{
/**
* Pass and validate URL arguments for the command processor. Validate if the command can be
* executed given the arguments supplied. Generally at this post a Command Processor will
* convert the supplied arguments to the objects it expects, and also check any permissions
* that are required by the current user to execute the command.
*
* @param sc ServletContext, can be used to retrieve ServiceRegistry instance
* from the Repository bean.
* @param command Name of the command the arguments are for
* @param args Map of URL args passed to the command servlet
* @param urlElements String[] of the remaining URL arguments to the command servlet
*
* @return true if the command can be executed by the current user given the supplied args.
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements);
/**
* Process the supplied command name. It is the responsibility of the Command Processor
* to lookup the specified command name using the CommandFactory registry. For that reason
* it also has the responsiblity to initially register commands it is responsible for so
* they can be constructed later. If the supplied command is unknown to it then an
* exception should be thrown to indicate this.
*
* @param serviceRegistry ServiceRegistry
* @param request HttpServletRequest
* @param command Name of the command to construct and execute
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command);
/**
* Output a simple status message to the supplied PrintWriter.
* It can be assumed that the process() method was successful if this method is called.
*
* @param out PrintWriter
*/
public void outputStatus(PrintWriter out);
}

View File

@@ -1,72 +1,72 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.surf.util.ParameterCheck;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.repository.Node;
/**
* Command to execute the Edit Content Properties dialog via url.
* <p>
* Arguments: noderef - of the document to show the edit props dialog for
*
* @author Kevin Roast
*/
public class EditContentPropertiesCommand extends BaseUIActionCommand
{
public static final String PROP_NODEREF = "noderef";
private static final String[] PROPERTIES = new String[] {
PROP_SERVLETCONTEXT, PROP_REQUEST, PROP_RESPONSE, PROP_NODEREF};
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
ServletContext sc = (ServletContext)properties.get(PROP_SERVLETCONTEXT);
ServletRequest req = (ServletRequest)properties.get(PROP_REQUEST);
ServletResponse res = (ServletResponse)properties.get(PROP_RESPONSE);
FacesContext fc = FacesHelper.getFacesContext(req, res, sc, "/jsp/close.jsp");
BrowseBean browseBean = (BrowseBean)FacesHelper.getManagedBean(fc, BrowseBean.BEAN_NAME);
// setup context from url args in properties map
String strNodeRef = (String)properties.get(PROP_NODEREF);
ParameterCheck.mandatoryString(PROP_NODEREF, strNodeRef);
browseBean.setDocument(new Node(new NodeRef(strNodeRef)));
NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
navigationHandler.handleNavigation(fc, null, "dialog:editContentProperties");
String viewId = fc.getViewRoot().getViewId();
try
{
sc.getRequestDispatcher(BaseServlet.FACES_SERVLET + viewId).forward(req, res);
}
catch (Exception e)
{
throw new AlfrescoRuntimeException("Unable to forward to viewId: " + viewId, e);
}
return null;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.surf.util.ParameterCheck;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.repository.Node;
/**
* Command to execute the Edit Content Properties dialog via url.
* <p>
* Arguments: noderef - of the document to show the edit props dialog for
*
* @author Kevin Roast
*/
public class EditContentPropertiesCommand extends BaseUIActionCommand
{
public static final String PROP_NODEREF = "noderef";
private static final String[] PROPERTIES = new String[] {
PROP_SERVLETCONTEXT, PROP_REQUEST, PROP_RESPONSE, PROP_NODEREF};
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
ServletContext sc = (ServletContext)properties.get(PROP_SERVLETCONTEXT);
ServletRequest req = (ServletRequest)properties.get(PROP_REQUEST);
ServletResponse res = (ServletResponse)properties.get(PROP_RESPONSE);
FacesContext fc = FacesHelper.getFacesContext(req, res, sc, "/jsp/close.jsp");
BrowseBean browseBean = (BrowseBean)FacesHelper.getManagedBean(fc, BrowseBean.BEAN_NAME);
// setup context from url args in properties map
String strNodeRef = (String)properties.get(PROP_NODEREF);
ParameterCheck.mandatoryString(PROP_NODEREF, strNodeRef);
browseBean.setDocument(new Node(new NodeRef(strNodeRef)));
NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
navigationHandler.handleNavigation(fc, null, "dialog:editContentProperties");
String viewId = fc.getViewRoot().getViewId();
try
{
sc.getRequestDispatcher(BaseServlet.FACES_SERVLET + viewId).forward(req, res);
}
catch (Exception e)
{
throw new AlfrescoRuntimeException("Unable to forward to viewId: " + viewId, e);
}
return null;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
}

View File

@@ -1,44 +1,44 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.workflow.WorkflowService;
/**
* End Task command implementation
*
* @author David Caruana
*/
public final class EndTaskCommand implements Command
{
public static final String PROP_TASK_ID = "taskId";
public static final String PROP_TRANSITION = "transition";
private static final String[] PROPERTIES = new String[] {PROP_TASK_ID, PROP_TRANSITION};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
String taskId = (String)properties.get(PROP_TASK_ID);
if (taskId == null)
{
throw new IllegalArgumentException("Unable to execute EndTaskCommand - mandatory parameter not supplied: " + PROP_TASK_ID);
}
String transition = (String)properties.get(PROP_TRANSITION);
// end task
WorkflowService workflowService = serviceRegistry.getWorkflowService();
return workflowService.endTask(taskId, transition);
}
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.workflow.WorkflowService;
/**
* End Task command implementation
*
* @author David Caruana
*/
public final class EndTaskCommand implements Command
{
public static final String PROP_TASK_ID = "taskId";
public static final String PROP_TRANSITION = "transition";
private static final String[] PROPERTIES = new String[] {PROP_TASK_ID, PROP_TRANSITION};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
String taskId = (String)properties.get(PROP_TASK_ID);
if (taskId == null)
{
throw new IllegalArgumentException("Unable to execute EndTaskCommand - mandatory parameter not supplied: " + PROP_TASK_ID);
}
String transition = (String)properties.get(PROP_TRANSITION);
// end task
WorkflowService workflowService = serviceRegistry.getWorkflowService();
return workflowService.endTask(taskId, transition);
}
}

View File

@@ -1,81 +1,81 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
/**
* Execute Script command implementation.
* <p>
* Executes the supplied script against the default data-model.
*
* @author Kevin Roast
*/
public final class ExecuteScriptCommand implements Command
{
public static final String PROP_SCRIPT = "script";
public static final String PROP_DOCUMENT = "document";
public static final String PROP_USERPERSON = "person";
public static final String PROP_ARGS = "args";
private static final String[] PROPERTIES = new String[] {PROP_SCRIPT, PROP_DOCUMENT, PROP_USERPERSON, PROP_ARGS};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
// get the target Script node for the command
NodeRef scriptRef = (NodeRef)properties.get(PROP_SCRIPT);
if (scriptRef == null)
{
throw new IllegalArgumentException(
"Unable to execute ExecuteScriptCommand - mandatory parameter not supplied: " + PROP_SCRIPT);
}
NodeRef personRef = (NodeRef)properties.get(PROP_USERPERSON);
if (personRef == null)
{
throw new IllegalArgumentException(
"Unable to execute ExecuteScriptCommand - mandatory parameter not supplied: " + PROP_USERPERSON);
}
// get the optional document and space context ref
NodeService nodeService = serviceRegistry.getNodeService();
NodeRef docRef = (NodeRef)properties.get(PROP_DOCUMENT);
NodeRef spaceRef = null;
if (docRef != null)
{
spaceRef = nodeService.getPrimaryParent(docRef).getParentRef();
}
// build the model needed to execute the script
Map<String, Object> model = serviceRegistry.getScriptService().buildDefaultModel(
personRef,
new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId()),
(NodeRef)nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER),
scriptRef,
docRef,
spaceRef);
// add the url arguments map
model.put("args", properties.get(PROP_ARGS));
// execute the script and return the result
return serviceRegistry.getScriptService().executeScript(scriptRef, null, model);
}
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.web.app.Application;
import org.alfresco.web.bean.repository.Repository;
/**
* Execute Script command implementation.
* <p>
* Executes the supplied script against the default data-model.
*
* @author Kevin Roast
*/
public final class ExecuteScriptCommand implements Command
{
public static final String PROP_SCRIPT = "script";
public static final String PROP_DOCUMENT = "document";
public static final String PROP_USERPERSON = "person";
public static final String PROP_ARGS = "args";
private static final String[] PROPERTIES = new String[] {PROP_SCRIPT, PROP_DOCUMENT, PROP_USERPERSON, PROP_ARGS};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
// get the target Script node for the command
NodeRef scriptRef = (NodeRef)properties.get(PROP_SCRIPT);
if (scriptRef == null)
{
throw new IllegalArgumentException(
"Unable to execute ExecuteScriptCommand - mandatory parameter not supplied: " + PROP_SCRIPT);
}
NodeRef personRef = (NodeRef)properties.get(PROP_USERPERSON);
if (personRef == null)
{
throw new IllegalArgumentException(
"Unable to execute ExecuteScriptCommand - mandatory parameter not supplied: " + PROP_USERPERSON);
}
// get the optional document and space context ref
NodeService nodeService = serviceRegistry.getNodeService();
NodeRef docRef = (NodeRef)properties.get(PROP_DOCUMENT);
NodeRef spaceRef = null;
if (docRef != null)
{
spaceRef = nodeService.getPrimaryParent(docRef).getParentRef();
}
// build the model needed to execute the script
Map<String, Object> model = serviceRegistry.getScriptService().buildDefaultModel(
personRef,
new NodeRef(Repository.getStoreRef(), Application.getCompanyRootId()),
(NodeRef)nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER),
scriptRef,
docRef,
spaceRef);
// add the url arguments map
model.put("args", properties.get(PROP_ARGS));
// execute the script and return the result
return serviceRegistry.getScriptService().executeScript(scriptRef, null, model);
}
}

View File

@@ -1,35 +1,35 @@
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.service.ServiceRegistry;
/**
* This interfaces defines the contract and lifecycle of a Servlet Command Processor.
* <p>
* The ExtCommandProcessor adds an overloaded process() method to allow the
* HttpServletResponse to be passed.
*
* @author Kevin Roast
*/
public interface ExtCommandProcessor extends CommandProcessor
{
/**
* Process the supplied command name. It is the responsibility of the Command Processor
* to lookup the specified command name using the CommandFactory registry. For that reason
* it also has the responsiblity to initially register commands it is responsible for so
* they can be constructed later. If the supplied command is unknown to it then an
* exception should be thrown to indicate this.
*
* @param serviceRegistry ServiceRegistry
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param command Name of the command to construct and execute
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, HttpServletResponse response, String command);
}
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.service.ServiceRegistry;
/**
* This interfaces defines the contract and lifecycle of a Servlet Command Processor.
* <p>
* The ExtCommandProcessor adds an overloaded process() method to allow the
* HttpServletResponse to be passed.
*
* @author Kevin Roast
*/
public interface ExtCommandProcessor extends CommandProcessor
{
/**
* Process the supplied command name. It is the responsibility of the Command Processor
* to lookup the specified command name using the CommandFactory registry. For that reason
* it also has the responsiblity to initially register commands it is responsible for so
* they can be constructed later. If the supplied command is unknown to it then an
* exception should be thrown to indicate this.
*
* @param serviceRegistry ServiceRegistry
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param command Name of the command to construct and execute
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, HttpServletResponse response, String command);
}

View File

@@ -1,75 +1,75 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.workflow.WorkflowBean;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* Command to execute the Manage Task dialog via url.
* <p>
* Arguments: id = the id of the task
* type = the qname type of the task
*
* @author Kevin Roast
*/
public class ManageTaskDialogCommand extends BaseUIActionCommand
{
public static final String PROP_TASKID = "id";
public static final String PROP_TASKTYPE = "type";
private static final String[] PROPERTIES = new String[] {
PROP_SERVLETCONTEXT, PROP_REQUEST, PROP_RESPONSE, PROP_TASKID, PROP_TASKTYPE};
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
ServletContext sc = (ServletContext)properties.get(PROP_SERVLETCONTEXT);
ServletRequest req = (ServletRequest)properties.get(PROP_REQUEST);
ServletResponse res = (ServletResponse)properties.get(PROP_RESPONSE);
FacesContext fc = FacesHelper.getFacesContext(req, res, sc, "/jsp/close.jsp");
WorkflowBean wfBean = (WorkflowBean)FacesHelper.getManagedBean(fc, WorkflowBean.BEAN_NAME);
// setup dialog context from url args in properties map
String taskId = (String)properties.get(PROP_TASKID);
ParameterCheck.mandatoryString(PROP_TASKID, taskId);
String taskType = (String)properties.get(PROP_TASKTYPE);
ParameterCheck.mandatoryString(PROP_TASKTYPE, taskType);
wfBean.setupTaskDialog(taskId, taskType);
NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
navigationHandler.handleNavigation(fc, null, "dialog:manageTask");
String viewId = fc.getViewRoot().getViewId();
try
{
sc.getRequestDispatcher(BaseServlet.FACES_SERVLET + viewId).forward(req, res);
}
catch (Exception e)
{
throw new AlfrescoRuntimeException("Unable to forward to viewId: " + viewId, e);
}
return null;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import javax.faces.application.NavigationHandler;
import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.bean.workflow.WorkflowBean;
import org.springframework.extensions.surf.util.ParameterCheck;
/**
* Command to execute the Manage Task dialog via url.
* <p>
* Arguments: id = the id of the task
* type = the qname type of the task
*
* @author Kevin Roast
*/
public class ManageTaskDialogCommand extends BaseUIActionCommand
{
public static final String PROP_TASKID = "id";
public static final String PROP_TASKTYPE = "type";
private static final String[] PROPERTIES = new String[] {
PROP_SERVLETCONTEXT, PROP_REQUEST, PROP_RESPONSE, PROP_TASKID, PROP_TASKTYPE};
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
ServletContext sc = (ServletContext)properties.get(PROP_SERVLETCONTEXT);
ServletRequest req = (ServletRequest)properties.get(PROP_REQUEST);
ServletResponse res = (ServletResponse)properties.get(PROP_RESPONSE);
FacesContext fc = FacesHelper.getFacesContext(req, res, sc, "/jsp/close.jsp");
WorkflowBean wfBean = (WorkflowBean)FacesHelper.getManagedBean(fc, WorkflowBean.BEAN_NAME);
// setup dialog context from url args in properties map
String taskId = (String)properties.get(PROP_TASKID);
ParameterCheck.mandatoryString(PROP_TASKID, taskId);
String taskType = (String)properties.get(PROP_TASKTYPE);
ParameterCheck.mandatoryString(PROP_TASKTYPE, taskType);
wfBean.setupTaskDialog(taskId, taskType);
NavigationHandler navigationHandler = fc.getApplication().getNavigationHandler();
navigationHandler.handleNavigation(fc, null, "dialog:manageTask");
String viewId = fc.getViewRoot().getViewId();
try
{
sc.getRequestDispatcher(BaseServlet.FACES_SERVLET + viewId).forward(req, res);
}
catch (Exception e)
{
throw new AlfrescoRuntimeException("Unable to forward to viewId: " + viewId, e);
}
return null;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
}

View File

@@ -1,45 +1,45 @@
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.web.bean.workflow.WorkflowUtil;
/**
* Reject Workflow command implementation
*
* @author Kevin Roast
*/
public final class RejectWorkflowCommand implements Command
{
public static final String PROP_TARGET = "target";
private static final String[] PROPERTIES = new String[] {PROP_TARGET};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
// get the target Node for the command
NodeRef nodeRef = (NodeRef)properties.get(PROP_TARGET);
if (nodeRef == null)
{
throw new IllegalArgumentException(
"Unable to execute RejectCommand - mandatory parameter not supplied: " + PROP_TARGET);
}
WorkflowUtil.reject(nodeRef, serviceRegistry.getNodeService(), serviceRegistry.getCopyService());
return true;
}
}
package org.alfresco.web.app.servlet.command;
import java.util.Map;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.web.bean.workflow.WorkflowUtil;
/**
* Reject Workflow command implementation
*
* @author Kevin Roast
*/
public final class RejectWorkflowCommand implements Command
{
public static final String PROP_TARGET = "target";
private static final String[] PROPERTIES = new String[] {PROP_TARGET};
/**
* @see org.alfresco.web.app.servlet.command.Command#getPropertyNames()
*/
public String[] getPropertyNames()
{
return PROPERTIES;
}
/**
* @see org.alfresco.web.app.servlet.command.Command#execute(org.alfresco.service.ServiceRegistry, java.util.Map)
*/
public Object execute(ServiceRegistry serviceRegistry, Map<String, Object> properties)
{
// get the target Node for the command
NodeRef nodeRef = (NodeRef)properties.get(PROP_TARGET);
if (nodeRef == null)
{
throw new IllegalArgumentException(
"Unable to execute RejectCommand - mandatory parameter not supplied: " + PROP_TARGET);
}
WorkflowUtil.reject(nodeRef, serviceRegistry.getNodeService(), serviceRegistry.getCopyService());
return true;
}
}

View File

@@ -1,143 +1,143 @@
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.jscript.ScriptableHashMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.ClientConfigElement;
import org.springframework.extensions.config.ConfigService;
/**
* Script command processor implementation.
* <p>
* Responsible for executing 'execute' script commands on a Node.
*
* @author Kevin Roast
*/
public final class ScriptCommandProcessor implements CommandProcessor
{
private static final String ARG_SCRIPT_PATH = "scriptPath";
private static final String ARG_CONTEXT_PATH = "contextPath";
private NodeRef scriptRef;
private NodeRef docRef;
private Object result;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand("execute", ExecuteScriptCommand.class);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements)
{
boolean allowed = false;
String scriptPath = args.get(ARG_SCRIPT_PATH);
if (scriptPath != null)
{
// resolve path to a node
this.scriptRef = BaseServlet.resolveNamePath(sc, scriptPath).NodeRef;
// same for the document context path if specified
String docPath = args.get(ARG_CONTEXT_PATH);
if (docPath != null)
{
this.docRef = BaseServlet.resolveNamePath(sc, docPath).NodeRef;
}
}
else
{
if (urlElements.length < 3)
{
throw new IllegalArgumentException("Not enough URL arguments passed to command servlet.");
}
// get NodeRef to the node script to execute
StoreRef storeRef = new StoreRef(urlElements[0], urlElements[1]);
this.scriptRef = new NodeRef(storeRef, urlElements[2]);
if (urlElements.length >= 6)
{
storeRef = new StoreRef(urlElements[3], urlElements[4]);
this.docRef = new NodeRef(storeRef, urlElements[5]);
}
}
// check we can READ access the nodes specified
PermissionService ps = Repository.getServiceRegistry(sc).getPermissionService();
allowed = (ps.hasPermission(this.scriptRef, PermissionService.READ) == AccessStatus.ALLOWED);
if (this.docRef != null)
{
allowed &= (ps.hasPermission(this.docRef, PermissionService.READ) == AccessStatus.ALLOWED);
}
// check to see if user is allowed to execute arbituary javascript
// by default only an admin authority can perform this action
ConfigService configService = Application.getConfigService(sc);
ClientConfigElement configElement = (ClientConfigElement)configService.getGlobalConfig().getConfigElement("client");
boolean allowScriptExecute = configElement.getAllowUserScriptExecute();
AuthorityService authService = Repository.getServiceRegistry(sc).getAuthorityService();
allowed &= (allowScriptExecute || authService.isAdminAuthority(AuthenticationUtil.getFullyAuthenticatedUser()));
return allowed;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command)
{
Map<String, Object> properties = new HashMap<String, Object>(4, 1.0f);
properties.put(ExecuteScriptCommand.PROP_SCRIPT, this.scriptRef);
properties.put(ExecuteScriptCommand.PROP_DOCUMENT, this.docRef);
User user = Application.getCurrentUser(request.getSession());
properties.put(ExecuteScriptCommand.PROP_USERPERSON, user.getPerson());
// add URL arguments as a special Scriptable Map property called 'args'
Map<String, String> args = new ScriptableHashMap<String, String>();
Enumeration names = request.getParameterNames();
while (names.hasMoreElements())
{
String name = (String)names.nextElement();
args.put(name, request.getParameter(name));
}
properties.put(ExecuteScriptCommand.PROP_ARGS, args);
Command cmd = CommandFactory.getInstance().createCommand(command);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered script command specified: " + command);
}
this.result = cmd.execute(serviceRegistry, properties);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.write(this.result != null ? this.result.toString() : "Successfully executed script.");
}
}
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.jscript.ScriptableHashMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.BaseServlet;
import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.ClientConfigElement;
import org.springframework.extensions.config.ConfigService;
/**
* Script command processor implementation.
* <p>
* Responsible for executing 'execute' script commands on a Node.
*
* @author Kevin Roast
*/
public final class ScriptCommandProcessor implements CommandProcessor
{
private static final String ARG_SCRIPT_PATH = "scriptPath";
private static final String ARG_CONTEXT_PATH = "contextPath";
private NodeRef scriptRef;
private NodeRef docRef;
private Object result;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand("execute", ExecuteScriptCommand.class);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements)
{
boolean allowed = false;
String scriptPath = args.get(ARG_SCRIPT_PATH);
if (scriptPath != null)
{
// resolve path to a node
this.scriptRef = BaseServlet.resolveNamePath(sc, scriptPath).NodeRef;
// same for the document context path if specified
String docPath = args.get(ARG_CONTEXT_PATH);
if (docPath != null)
{
this.docRef = BaseServlet.resolveNamePath(sc, docPath).NodeRef;
}
}
else
{
if (urlElements.length < 3)
{
throw new IllegalArgumentException("Not enough URL arguments passed to command servlet.");
}
// get NodeRef to the node script to execute
StoreRef storeRef = new StoreRef(urlElements[0], urlElements[1]);
this.scriptRef = new NodeRef(storeRef, urlElements[2]);
if (urlElements.length >= 6)
{
storeRef = new StoreRef(urlElements[3], urlElements[4]);
this.docRef = new NodeRef(storeRef, urlElements[5]);
}
}
// check we can READ access the nodes specified
PermissionService ps = Repository.getServiceRegistry(sc).getPermissionService();
allowed = (ps.hasPermission(this.scriptRef, PermissionService.READ) == AccessStatus.ALLOWED);
if (this.docRef != null)
{
allowed &= (ps.hasPermission(this.docRef, PermissionService.READ) == AccessStatus.ALLOWED);
}
// check to see if user is allowed to execute arbituary javascript
// by default only an admin authority can perform this action
ConfigService configService = Application.getConfigService(sc);
ClientConfigElement configElement = (ClientConfigElement)configService.getGlobalConfig().getConfigElement("client");
boolean allowScriptExecute = configElement.getAllowUserScriptExecute();
AuthorityService authService = Repository.getServiceRegistry(sc).getAuthorityService();
allowed &= (allowScriptExecute || authService.isAdminAuthority(AuthenticationUtil.getFullyAuthenticatedUser()));
return allowed;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command)
{
Map<String, Object> properties = new HashMap<String, Object>(4, 1.0f);
properties.put(ExecuteScriptCommand.PROP_SCRIPT, this.scriptRef);
properties.put(ExecuteScriptCommand.PROP_DOCUMENT, this.docRef);
User user = Application.getCurrentUser(request.getSession());
properties.put(ExecuteScriptCommand.PROP_USERPERSON, user.getPerson());
// add URL arguments as a special Scriptable Map property called 'args'
Map<String, String> args = new ScriptableHashMap<String, String>();
Enumeration names = request.getParameterNames();
while (names.hasMoreElements())
{
String name = (String)names.nextElement();
args.put(name, request.getParameter(name));
}
properties.put(ExecuteScriptCommand.PROP_ARGS, args);
Command cmd = CommandFactory.getInstance().createCommand(command);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered script command specified: " + command);
}
this.result = cmd.execute(serviceRegistry, properties);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.write(this.result != null ? this.result.toString() : "Successfully executed script.");
}
}

View File

@@ -1,84 +1,84 @@
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.bean.workflow.WorkflowUtil;
import org.alfresco.web.ui.common.Utils;
/**
* Task specific command processor implementation.
* <p>
* Responsible for executing workflow task operations.
*
* @author David Caruana
*/
public final class TaskCommandProcessor implements CommandProcessor
{
private String taskId;
private String transition = null;
private String command;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand("end", EndTaskCommand.class);
}
/* (non-Javadoc)
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String cmd, Map<String, String> args, String[] urlElements)
{
if (urlElements.length == 0)
{
throw new IllegalArgumentException("Not enough URL arguments passed to command servlet.");
}
taskId = urlElements[0];
if (urlElements.length == 2)
{
transition = urlElements[1];
}
return WorkflowUtil.isTaskEditable(taskId, sc);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String commandName)
{
Map<String, Object> properties = new HashMap<String, Object>(1, 1.0f);
// all workflow commands use a "target" Node property as an argument
properties.put(EndTaskCommand.PROP_TASK_ID, taskId);
if (transition != null)
{
properties.put(EndTaskCommand.PROP_TRANSITION, transition);
}
Command cmd = CommandFactory.getInstance().createCommand(commandName);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered workflow command specified: " + commandName);
}
cmd.execute(serviceRegistry, properties);
this.command = commandName;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.print("Task command: '");
out.print(Utils.encode(command));
out.print("' executed against task: ");
out.println(Utils.encode(taskId));
}
}
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.bean.workflow.WorkflowUtil;
import org.alfresco.web.ui.common.Utils;
/**
* Task specific command processor implementation.
* <p>
* Responsible for executing workflow task operations.
*
* @author David Caruana
*/
public final class TaskCommandProcessor implements CommandProcessor
{
private String taskId;
private String transition = null;
private String command;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand("end", EndTaskCommand.class);
}
/* (non-Javadoc)
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String cmd, Map<String, String> args, String[] urlElements)
{
if (urlElements.length == 0)
{
throw new IllegalArgumentException("Not enough URL arguments passed to command servlet.");
}
taskId = urlElements[0];
if (urlElements.length == 2)
{
transition = urlElements[1];
}
return WorkflowUtil.isTaskEditable(taskId, sc);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String commandName)
{
Map<String, Object> properties = new HashMap<String, Object>(1, 1.0f);
// all workflow commands use a "target" Node property as an argument
properties.put(EndTaskCommand.PROP_TASK_ID, taskId);
if (transition != null)
{
properties.put(EndTaskCommand.PROP_TRANSITION, transition);
}
Command cmd = CommandFactory.getInstance().createCommand(commandName);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered workflow command specified: " + commandName);
}
cmd.execute(serviceRegistry, properties);
this.command = commandName;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.print("Task command: '");
out.print(Utils.encode(command));
out.print("' executed against task: ");
out.println(Utils.encode(taskId));
}
}

View File

@@ -1,112 +1,112 @@
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.bean.workflow.WorkflowUtil;
import org.alfresco.web.ui.common.Utils;
/**
* UI action command processor implementation.
* <p>
* Responsible for executing specific UI actions via a REST style URL interface.
* <p>
* The URL postfix for each specific command depends on the context that is required
* for that command. For example, a command to launch the Create Web Content dialog may
* require the current sandbox and the current web project as its context e.g.
* <br>
* http://server/alfresco/command/ui/createwebcontent?sandbox=website1&webproject=1234567890
*
* @author Kevin Roast
*/
public class UIActionCommandProcessor implements ExtCommandProcessor
{
private static final String MANAGE_TASK = "managetask";
public static final String PARAM_CONTAINER = "container";
private ServletContext sc = null;
private String command = null;
private Map<String, String> args = null;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand(MANAGE_TASK, ManageTaskDialogCommand.class);
CommandFactory.getInstance().registerCommand("editcontentprops", EditContentPropertiesCommand.class);
CommandFactory.getInstance().registerCommand("userprofile", UserProfileDialogCommand.class);
CommandFactory.getInstance().registerCommand("editspace", EditSpaceCommand.class);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements)
{
this.sc = sc;
if (args.size() != 0)
{
this.args = new HashMap<String, String>(args);
}
if (MANAGE_TASK.equals(command))
{
String taskId = args.get(ManageTaskDialogCommand.PROP_TASKID);
return WorkflowUtil.isTaskEditable(taskId, sc);
}
return true;
}
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command)
{
// not implemented in ExtCommandProcessor!
}
/**
* @see org.alfresco.web.app.servlet.command.ExtCommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, HttpServletResponse response, String command)
{
Map<String, Object> properties = new HashMap<String, Object>(this.args);
properties.put(BaseUIActionCommand.PROP_SERVLETCONTEXT, this.sc);
properties.put(BaseUIActionCommand.PROP_REQUEST, request);
properties.put(BaseUIActionCommand.PROP_RESPONSE, response);
// if the container parameter is present and equal to "plain" add the
// external container object to the session
String container = request.getParameter(PARAM_CONTAINER);
if (container != null && container.equalsIgnoreCase("plain"))
{
request.getSession().setAttribute(
AlfrescoNavigationHandler.EXTERNAL_CONTAINER_SESSION, Boolean.TRUE);
}
Command cmd = CommandFactory.getInstance().createCommand(command);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered UI Action command specified: " + command);
}
cmd.execute(serviceRegistry, properties);
this.command = command;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.print("UI Action command: '");
out.print(Utils.encode(this.command));
out.print("' executed with args: ");
out.println(this.args != null ? (Utils.encode(this.args.toString())) : "");
}
}
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.app.AlfrescoNavigationHandler;
import org.alfresco.web.bean.workflow.WorkflowUtil;
import org.alfresco.web.ui.common.Utils;
/**
* UI action command processor implementation.
* <p>
* Responsible for executing specific UI actions via a REST style URL interface.
* <p>
* The URL postfix for each specific command depends on the context that is required
* for that command. For example, a command to launch the Create Web Content dialog may
* require the current sandbox and the current web project as its context e.g.
* <br>
* http://server/alfresco/command/ui/createwebcontent?sandbox=website1&webproject=1234567890
*
* @author Kevin Roast
*/
public class UIActionCommandProcessor implements ExtCommandProcessor
{
private static final String MANAGE_TASK = "managetask";
public static final String PARAM_CONTAINER = "container";
private ServletContext sc = null;
private String command = null;
private Map<String, String> args = null;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand(MANAGE_TASK, ManageTaskDialogCommand.class);
CommandFactory.getInstance().registerCommand("editcontentprops", EditContentPropertiesCommand.class);
CommandFactory.getInstance().registerCommand("userprofile", UserProfileDialogCommand.class);
CommandFactory.getInstance().registerCommand("editspace", EditSpaceCommand.class);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#validateArguments(javax.servlet.ServletContext, java.lang.String, java.util.Map, java.lang.String[])
*/
public boolean validateArguments(ServletContext sc, String command, Map<String, String> args, String[] urlElements)
{
this.sc = sc;
if (args.size() != 0)
{
this.args = new HashMap<String, String>(args);
}
if (MANAGE_TASK.equals(command))
{
String taskId = args.get(ManageTaskDialogCommand.PROP_TASKID);
return WorkflowUtil.isTaskEditable(taskId, sc);
}
return true;
}
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command)
{
// not implemented in ExtCommandProcessor!
}
/**
* @see org.alfresco.web.app.servlet.command.ExtCommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, HttpServletResponse response, String command)
{
Map<String, Object> properties = new HashMap<String, Object>(this.args);
properties.put(BaseUIActionCommand.PROP_SERVLETCONTEXT, this.sc);
properties.put(BaseUIActionCommand.PROP_REQUEST, request);
properties.put(BaseUIActionCommand.PROP_RESPONSE, response);
// if the container parameter is present and equal to "plain" add the
// external container object to the session
String container = request.getParameter(PARAM_CONTAINER);
if (container != null && container.equalsIgnoreCase("plain"))
{
request.getSession().setAttribute(
AlfrescoNavigationHandler.EXTERNAL_CONTAINER_SESSION, Boolean.TRUE);
}
Command cmd = CommandFactory.getInstance().createCommand(command);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered UI Action command specified: " + command);
}
cmd.execute(serviceRegistry, properties);
this.command = command;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.print("UI Action command: '");
out.print(Utils.encode(this.command));
out.print("' executed with args: ");
out.println(this.args != null ? (Utils.encode(this.args.toString())) : "");
}
}

View File

@@ -1,59 +1,59 @@
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.ui.common.Utils;
/**
* Workflow specific command processor implementation.
* <p>
* Responsible for executing 'approve' and 'reject' workflow commands on a Node.
*
* @author Kevin Roast
*/
public final class WorkflowCommandProcessor extends BaseNodeCommandProcessor
{
private String command;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand("approve", ApproveWorkflowCommand.class);
CommandFactory.getInstance().registerCommand("reject", RejectWorkflowCommand.class);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command)
{
Map<String, Object> properties = new HashMap<String, Object>(1, 1.0f);
// all workflow commands use a "target" Node property as an argument
properties.put(ApproveWorkflowCommand.PROP_TARGET, this.targetRef);
Command cmd = CommandFactory.getInstance().createCommand(command);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered workflow command specified: " + command);
}
cmd.execute(serviceRegistry, properties);
this.command = command;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.print("Workflow command: '");
out.print(Utils.encode(this.command));
out.print("' executed against node: ");
out.println(Utils.encode(this.targetRef.toString()));
}
}
package org.alfresco.web.app.servlet.command;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.web.ui.common.Utils;
/**
* Workflow specific command processor implementation.
* <p>
* Responsible for executing 'approve' and 'reject' workflow commands on a Node.
*
* @author Kevin Roast
*/
public final class WorkflowCommandProcessor extends BaseNodeCommandProcessor
{
private String command;
static
{
// add our commands to the command registry
CommandFactory.getInstance().registerCommand("approve", ApproveWorkflowCommand.class);
CommandFactory.getInstance().registerCommand("reject", RejectWorkflowCommand.class);
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#process(org.alfresco.service.ServiceRegistry, javax.servlet.http.HttpServletRequest, java.lang.String)
*/
public void process(ServiceRegistry serviceRegistry, HttpServletRequest request, String command)
{
Map<String, Object> properties = new HashMap<String, Object>(1, 1.0f);
// all workflow commands use a "target" Node property as an argument
properties.put(ApproveWorkflowCommand.PROP_TARGET, this.targetRef);
Command cmd = CommandFactory.getInstance().createCommand(command);
if (cmd == null)
{
throw new AlfrescoRuntimeException("Unregistered workflow command specified: " + command);
}
cmd.execute(serviceRegistry, properties);
this.command = command;
}
/**
* @see org.alfresco.web.app.servlet.command.CommandProcessor#outputStatus(java.io.PrintWriter)
*/
public void outputStatus(PrintWriter out)
{
out.print("Workflow command: '");
out.print(Utils.encode(this.command));
out.print("' executed against node: ");
out.println(Utils.encode(this.targetRef.toString()));
}
}