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

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


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

View File

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

View File

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

View File

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

View File

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

View File

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