mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
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:
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
* <application>
|
||||
* ...
|
||||
* <variable-resolver>org.alfresco.web.app.AlfrescoVariableResolver</variable-resolver>
|
||||
* </application></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>
|
||||
* <application>
|
||||
* ...
|
||||
* <variable-resolver>org.alfresco.web.app.AlfrescoVariableResolver</variable-resolver>
|
||||
* </application></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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
|
@@ -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) } );
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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(",", ";"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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 + "}";
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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";
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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())) : "");
|
||||
}
|
||||
}
|
||||
|
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user