ApplicationDispatcherpublic final class ApplicationDispatcher extends Object implements RequestDispatcherStandard implementation of RequestDispatcher that allows a
request to be forwarded to a different resource to create the ultimate
response, or to include the output of another resource in the response
from this resource. This implementation allows application level servlets
to wrap the request and/or response objects that are passed on to the
called resource, as long as the wrapping classes extend
javax.servlet.ServletRequestWrapper and
javax.servlet.ServletResponseWrapper . |
Fields Summary |
---|
private static com.sun.org.apache.commons.logging.Log | log | private Boolean | crossContextFlagis this dispatch cross context | private org.apache.catalina.Context | contextThe Context this RequestDispatcher is associated with. | private int | debugThe debugging detail level for this component. | private static final String | infoDescriptive information about this implementation. | private String | nameThe servlet name for a named dispatcher. | private String | pathInfoThe extra path information for this RequestDispatcher. | private String | queryStringThe query string parameters for this RequestDispatcher. | private String | requestURIThe request URI for this RequestDispatcher. | private String | servletPathThe servlet path for this RequestDispatcher. | private static final org.apache.catalina.util.StringManager | smThe StringManager for this package. | private org.apache.catalina.util.InstanceSupport | supportThe InstanceSupport instance associated with our Wrapper (used to
send "before dispatch" and "after dispatch" events. | private org.apache.catalina.Wrapper | wrapperThe Wrapper associated with the resource that will be forwarded to
or included. |
Constructors Summary |
---|
public ApplicationDispatcher(org.apache.catalina.Wrapper wrapper, String requestURI, String servletPath, String pathInfo, String queryString, String name)Construct a new instance of this class, configured according to the
specified parameters. If both servletPath and pathInfo are
null , it will be assumed that this RequestDispatcher
was acquired by name, rather than by path.
// ----------------------------------------------------------- Constructors
super();
// Save all of our configuration parameters
this.wrapper = wrapper;
this.context = (Context) wrapper.getParent();
this.requestURI = requestURI;
this.servletPath = servletPath;
this.pathInfo = pathInfo;
this.queryString = queryString;
this.name = name;
/* GlassFish 6386229
if (wrapper instanceof StandardWrapper)
this.support = ((StandardWrapper) wrapper).getInstanceSupport();
else
this.support = new InstanceSupport(wrapper);
*/
// START GlassFish 6386229
this.support = ((StandardWrapper) wrapper).getInstanceSupport();
// END GlassFish 6386229
if ( log.isDebugEnabled() )
log.debug("servletPath=" + this.servletPath + ", pathInfo=" +
this.pathInfo + ", queryString=" + queryString +
", name=" + this.name);
|
Methods Summary |
---|
private void | doForward(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response)
// Reset any output that has been buffered, but keep headers/cookies
if (response.isCommitted()) {
if ( log.isDebugEnabled() )
log.debug(" Forward on committed response --> ISE");
throw new IllegalStateException
(sm.getString("applicationDispatcher.forward.ise"));
}
try {
response.resetBuffer();
} catch (IllegalStateException e) {
if ( log.isDebugEnabled() )
log.debug(" Forward resetBuffer() returned ISE: " + e);
throw e;
}
// Set up to handle the specified request and response
State state = new State(request, response, false);
// Identify the HTTP-specific request and response objects (if any)
HttpServletRequest hrequest = null;
/* GlassFish 6386229
if (request instanceof HttpServletRequest)
hrequest = (HttpServletRequest) request;
*/
// START GlassFish 6386229
hrequest = (HttpServletRequest) request;
// END GlassFish 6386229
HttpServletResponse hresponse = null;
/* GlassFish 6386229
if (response instanceof HttpServletResponse)
hresponse = (HttpServletResponse) response;
*/
// START GlassFish 6386229
hresponse = (HttpServletResponse) response;
// END GlassFish 6386229
// Handle a non-HTTP forward by passing the existing request/response
if ((hrequest == null) || (hresponse == null)) {
if ( log.isDebugEnabled() )
log.debug(" Non-HTTP Forward");
processRequest(hrequest,hresponse,state);
}
// Handle an HTTP named dispatcher forward
else if ((servletPath == null) && (pathInfo == null)) {
if ( log.isDebugEnabled() )
log.debug(" Named Dispatcher Forward");
ApplicationHttpRequest wrequest =
(ApplicationHttpRequest) wrapRequest(state);
wrequest.setRequestURI(hrequest.getRequestURI());
wrequest.setContextPath(hrequest.getContextPath());
wrequest.setServletPath(hrequest.getServletPath());
wrequest.setPathInfo(hrequest.getPathInfo());
wrequest.setQueryString(hrequest.getQueryString());
processRequest(request,response,state);
wrequest.recycle();
unwrapRequest(state);
}
// Handle an HTTP path-based forward
else {
if ( log.isDebugEnabled() )
log.debug(" Path Based Forward");
ApplicationHttpRequest wrequest =
(ApplicationHttpRequest) wrapRequest(state);
String contextPath = context.getPath();
if (hrequest.getAttribute(Globals.FORWARD_REQUEST_URI_ATTR) == null) {
wrequest.initSpecialAttributes(false,
hrequest.getRequestURI(),
hrequest.getContextPath(),
hrequest.getServletPath(),
hrequest.getPathInfo(),
hrequest.getQueryString());
}
wrequest.setContextPath(contextPath);
wrequest.setRequestURI(requestURI);
wrequest.setServletPath(servletPath);
wrequest.setPathInfo(pathInfo);
if (queryString != null) {
wrequest.setQueryString(queryString);
wrequest.setQueryParams(queryString);
}
processRequest(request,response,state);
wrequest.recycle();
unwrapRequest(state);
}
/* SJSAS 6374990
// This is not a real close in order to support error processing
if ( log.isDebugEnabled() )
log.debug(" Disabling the response for futher output");
if (response instanceof ResponseFacade) {
((ResponseFacade) response).finish();
} else {
// Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
// and may no longer be instance of RequestFacade
if (log.isDebugEnabled()){
log.debug( " The Response is vehiculed using a wrapper: "
+ response.getClass().getName() );
}
// Close anyway
try {
PrintWriter writer = response.getWriter();
writer.close();
} catch (IllegalStateException e) {
try {
ServletOutputStream stream = response.getOutputStream();
stream.close();
} catch (IllegalStateException f) {
;
} catch (IOException f) {
;
}
} catch (IOException e) {
;
}
}
*/
| private void | doInclude(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response)
// Set up to handle the specified request and response
State state = new State(request, response, true);
// Create a wrapped response to use for this request
wrapResponse(state);
// Handle a non-HTTP include
/* GlassFish 6386229
if (!(request instanceof HttpServletRequest) ||
!(response instanceof HttpServletResponse)) {
if ( log.isDebugEnabled() )
log.debug(" Non-HTTP Include");
request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
Integer.valueOf(ApplicationFilterFactory.INCLUDE));
request.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
//origServletPath);
servletPath);
invoke(request, state.outerResponse, state);
unwrapResponse(state);
}
// Handle an HTTP named dispatcher include
else if (name != null) {
*/
// START GlassFish 6386229
// Handle an HTTP named dispatcher include
if (name != null) {
// END GlassFish 6386229
if ( log.isDebugEnabled() )
log.debug(" Named Dispatcher Include");
ApplicationHttpRequest wrequest =
(ApplicationHttpRequest) wrapRequest(state);
wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name);
if (servletPath != null)
wrequest.setServletPath(servletPath);
wrequest.setAttribute(
ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
Integer.valueOf(ApplicationFilterFactory.INCLUDE));
wrequest.setAttribute(
ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
servletPath);
invoke(state.outerRequest, state.outerResponse, state);
wrequest.recycle();
unwrapRequest(state);
unwrapResponse(state);
}
// Handle an HTTP path based include
else {
if ( log.isDebugEnabled() )
log.debug(" Path Based Include");
ApplicationHttpRequest wrequest =
(ApplicationHttpRequest) wrapRequest(state);
wrequest.initSpecialAttributes(true,
requestURI,
context.getPath(),
servletPath,
pathInfo,
queryString);
wrequest.setQueryParams(queryString);
wrequest.setAttribute(
ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
Integer.valueOf(ApplicationFilterFactory.INCLUDE));
wrequest.setAttribute(
ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
servletPath);
invoke(state.outerRequest, state.outerResponse, state);
wrequest.recycle();
unwrapRequest(state);
unwrapResponse(state);
}
| private void | doInvoke(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response)Ask the resource represented by this RequestDispatcher to process
the associated request, and create (or append to) the associated
response.
IMPLEMENTATION NOTE: This implementation assumes
that no filters are applied to a forwarded or included resource,
because they were already done for the original request.
// Checking to see if the context classloader is the current context
// classloader. If it's not, we're saving it, and setting the context
// classloader to the Context classloader
ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
ClassLoader contextClassLoader = context.getLoader().getClassLoader();
if (oldCCL != contextClassLoader) {
Thread.currentThread().setContextClassLoader(contextClassLoader);
} else {
oldCCL = null;
}
// Initialize local variables we may need
HttpServletRequest hrequest = null;
/* GlassFish 6386229
if (request instanceof HttpServletRequest)
hrequest = (HttpServletRequest) request;
*/
// START GlassFish 6386229
hrequest = (HttpServletRequest) request;
// END GlassFish 6386229
HttpServletResponse hresponse = null;
/* GlassFish 6386229
if (response instanceof HttpServletResponse)
hresponse = (HttpServletResponse) response;
*/
// START GlassFish 6386229
hresponse = (HttpServletResponse) response;
// END GlassFish 6386229
Servlet servlet = null;
IOException ioException = null;
ServletException servletException = null;
RuntimeException runtimeException = null;
boolean unavailable = false;
// Check for the servlet being marked unavailable
if (wrapper.isUnavailable()) {
log(sm.getString("applicationDispatcher.isUnavailable",
wrapper.getName()));
if (hresponse == null) {
; // NOTE - Not much we can do generically
} else {
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE))
hresponse.setDateHeader("Retry-After", available);
hresponse.sendError
(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("applicationDispatcher.isUnavailable",
wrapper.getName()));
}
unavailable = true;
}
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
// if (debug >= 2)
// log(" Allocating servlet instance");
servlet = wrapper.allocate();
// if ((debug >= 2) && (servlet == null))
// log(" No servlet instance returned!");
}
} catch (ServletException e) {
log(sm.getString("applicationDispatcher.allocateException",
wrapper.getName()),
StandardWrapper.getRootCause(e));
servletException = e;
servlet = null;
} catch (Throwable e) {
log(sm.getString("applicationDispatcher.allocateException",
wrapper.getName()), e);
servletException = new ServletException
(sm.getString("applicationDispatcher.allocateException",
wrapper.getName()), e);
servlet = null;
}
// Get the FilterChain Here
ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
ApplicationFilterChain filterChain = factory.createFilterChain(request,
wrapper,servlet);
// START OF S1AS 4703023
CoyoteRequest origRequest = null;
// END OF S1AS 4703023
// Call the service() method for the allocated servlet instance
try {
String jspFile = wrapper.getJspFile();
if (jspFile != null) {
request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
}
support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT,
servlet, request, response);
// for includes/forwards
/* IASRI 4665318
if ((servlet != null) && (filterChain != null)) {
*/
// START IASRI 4665318
if (servlet != null) {
// END IASRI 4665318
// START OF S1AS 4703023
origRequest = getCoyoteRequest(request);
if (origRequest != null) {
origRequest.incrementDispatchDepth();
if (origRequest.isMaxDispatchDepthReached())
throw new ServletException(sm.getString(
"applicationDispatcher.maxDispatchDepthReached",
new Object[] {
Integer.valueOf(origRequest.getMaxDispatchDepth())}));
}
// END OF S1AS 4703023
/* IASRI 4665318
filterChain.doFilter(request, response);
*/
// START IASRI 4665318
if (filterChain != null)
filterChain.doFilter(request, response);
else {
ApplicationFilterChain.servletService(request, response,
servlet, support);
}
// END IASRI 4665318
}
// Servlet Service Method is called by the FilterChain
support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
servlet, request, response);
} catch (ClientAbortException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
servlet, request, response);
ioException = e;
} catch (IOException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
servlet, request, response);
log(sm.getString("applicationDispatcher.serviceException",
wrapper.getName()), e);
ioException = e;
} catch (UnavailableException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
servlet, request, response);
log(sm.getString("applicationDispatcher.serviceException",
wrapper.getName()), e);
servletException = e;
wrapper.unavailable(e);
} catch (ServletException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
servlet, request, response);
Throwable rootCause = StandardWrapper.getRootCause(e);
if (!(rootCause instanceof ClientAbortException)) {
log(sm.getString("applicationDispatcher.serviceException",
wrapper.getName()), rootCause);
}
servletException = e;
} catch (RuntimeException e) {
support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT,
servlet, request, response);
log(sm.getString("applicationDispatcher.serviceException",
wrapper.getName()), e);
runtimeException = e;
// START OF S1AS 4703023
} finally {
if (origRequest != null)
origRequest.decrementDispatchDepth();
// END OF S1AS 4703023
}
// Release the filter chain (if any) for this request
try {
if (filterChain != null)
filterChain.release();
} catch (Throwable e) {
log.error(sm.getString("standardWrapper.releaseFilters",
wrapper.getName()), e);
//FIXME Exception handling needs to be simpiler to what is in the StandardWrapperValue
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
} catch (ServletException e) {
log(sm.getString("applicationDispatcher.deallocateException",
wrapper.getName()), e);
servletException = e;
} catch (Throwable e) {
log(sm.getString("applicationDispatcher.deallocateException",
wrapper.getName()), e);
servletException = new ServletException
(sm.getString("applicationDispatcher.deallocateException",
wrapper.getName()), e);
}
// Reset the old context class loader
if (oldCCL != null)
Thread.currentThread().setContextClassLoader(oldCCL);
// Rethrow an exception if one was thrown by the invoked servlet
if (ioException != null)
throw ioException;
if (servletException != null)
throw servletException;
if (runtimeException != null)
throw runtimeException;
| public void | forward(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response)Forward this request and response to another resource for processing.
Any runtime exception, IOException, or ServletException thrown by the
called servlet will be propogated to the caller.
if (Globals.IS_SECURITY_ENABLED) {
try {
PrivilegedForward dp = new PrivilegedForward(request,response);
AccessController.doPrivileged(dp);
// START SJSAS 6374990
ApplicationDispatcherForward.commit(
(HttpServletRequest) request,
(HttpServletResponse) response,
context, wrapper);
// END SJSAS 6374990
} catch (PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
throw (IOException) e;
}
} else {
doForward(request,response);
// START SJSAS 6374990
ApplicationDispatcherForward.commit(
(HttpServletRequest) request,
(HttpServletResponse) response,
context, wrapper);
// END SJSAS 6374990
}
| private org.apache.coyote.tomcat5.CoyoteRequest | getCoyoteRequest(javax.servlet.ServletRequest request)Finds and returns the underlying/original request object.
(Doing instanceof in a loop will impact performance)
CoyoteRequest coyoteRequest = null;
Object current = request;
while (current != null) {
// When we run into the original request object, return it
if (current instanceof CoyoteRequestFacade) {
coyoteRequest = ((CoyoteRequestFacade)current).getUnwrappedCoyoteRequest();
break;
} else if (current instanceof ServletRequestWrapper) {
current = ((ServletRequestWrapper) current).getRequest();
} else
break;
}
return coyoteRequest;
| public java.lang.String | getInfo()Return the descriptive information about this implementation.
// ------------------------------------------------------------- Properties
return (this.info);
| public void | include(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response)Include the response from another resource in the current response.
Any runtime exception, IOException, or ServletException thrown by the
called servlet will be propogated to the caller.
if (Globals.IS_SECURITY_ENABLED) {
try {
PrivilegedInclude dp = new PrivilegedInclude(request,response);
AccessController.doPrivileged(dp);
} catch (PrivilegedActionException pe) {
Exception e = pe.getException();
if (e instanceof ServletException)
throw (ServletException) e;
throw (IOException) e;
}
} else {
doInclude(request,response);
}
| private void | invoke(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response, org.apache.catalina.core.ApplicationDispatcher$State state)Ask the resource represented by this RequestDispatcher to process
the associated request, and create (or append to) the associated
response.
IMPLEMENTATION NOTE: This implementation assumes
that no filters are applied to a forwarded or included resource,
because they were already done for the original request.
//START OF 6364900 original invoke has been renamed to doInvoke
boolean crossContext = false;
if(crossContextFlag != null && crossContextFlag.booleanValue()) {
crossContext = true;
}
if(crossContext) {
context.getManager().lockSession(request);
}
try {
if(crossContext) {
context.getManager().preRequestDispatcherProcess(request, response);
}
doInvoke(request,response);
if(crossContext) {
context.getManager().postRequestDispatcherProcess(request, response);
}
} finally {
if(crossContext) {
context.getManager().unlockSession(request);
}
crossContextFlag = null;
}
//END OF 6364900
| private void | log(java.lang.String message)Log a message on the Logger associated with our Context (if any)
Logger logger = context.getLogger();
if (logger != null)
logger.log("ApplicationDispatcher[" + context.getPath() +
"]: " + message);
else
System.out.println("ApplicationDispatcher[" +
context.getPath() + "]: " + message);
| private void | log(java.lang.String message, java.lang.Throwable throwable)Log a message on the Logger associated with our Container (if any)
Logger logger = context.getLogger();
if (logger != null)
logger.log("ApplicationDispatcher[" + context.getPath() +
"] " + message, throwable);
else {
System.out.println("ApplicationDispatcher[" +
context.getPath() + "]: " + message);
throwable.printStackTrace(System.out);
}
| private void | processRequest(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response, org.apache.catalina.core.ApplicationDispatcher$State state)Prepare the request based on the filter configuration.
Integer disInt = (Integer) request.getAttribute
(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR);
if (disInt != null) {
if (disInt.intValue() != ApplicationFilterFactory.ERROR) {
state.outerRequest.setAttribute
(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR,
servletPath);
state.outerRequest.setAttribute
(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR,
Integer.valueOf(ApplicationFilterFactory.FORWARD));
invoke(state.outerRequest, response, state);
} else {
invoke(state.outerRequest, response, state);
}
}
| private void | unwrapRequest(org.apache.catalina.core.ApplicationDispatcher$State state)Unwrap the request if we have wrapped it.
if (state.wrapRequest == null)
return;
ServletRequest previous = null;
ServletRequest current = state.outerRequest;
while (current != null) {
// If we run into the container request we are done
if ((current instanceof Request)
|| (current instanceof RequestFacade))
break;
// Remove the current request if it is our wrapper
if (current == state.wrapRequest) {
ServletRequest next =
((ServletRequestWrapper) current).getRequest();
if (previous == null)
state.outerRequest = next;
else
((ServletRequestWrapper) previous).setRequest(next);
break;
}
// Advance to the next request in the chain
previous = current;
current = ((ServletRequestWrapper) current).getRequest();
}
| private void | unwrapResponse(org.apache.catalina.core.ApplicationDispatcher$State state)Unwrap the response if we have wrapped it.
if (state.wrapResponse == null)
return;
ServletResponse previous = null;
ServletResponse current = state.outerResponse;
while (current != null) {
// If we run into the container response we are done
if ((current instanceof Response)
|| (current instanceof ResponseFacade))
break;
// Remove the current response if it is our wrapper
if (current == state.wrapResponse) {
ServletResponse next =
((ServletResponseWrapper) current).getResponse();
if (previous == null)
state.outerResponse = next;
else
((ServletResponseWrapper) previous).setResponse(next);
break;
}
// Advance to the next response in the chain
previous = current;
current = ((ServletResponseWrapper) current).getResponse();
}
| private javax.servlet.ServletRequest | wrapRequest(org.apache.catalina.core.ApplicationDispatcher$State state)Create and return a request wrapper that has been inserted in the
appropriate spot in the request chain.
// Locate the request we should insert in front of
ServletRequest previous = null;
ServletRequest current = state.outerRequest;
while (current != null) {
if ("org.apache.catalina.servlets.InvokerHttpRequest".
equals(current.getClass().getName()))
break; // KLUDGE - Make nested RD.forward() using invoker work
if (!(current instanceof ServletRequestWrapper))
break;
if (current instanceof ApplicationHttpRequest)
break;
if (current instanceof ApplicationRequest)
break;
if (current instanceof Request)
break;
previous = current;
current = ((ServletRequestWrapper) current).getRequest();
}
// Instantiate a new wrapper at this point and insert it in the chain
ServletRequest wrapper = null;
if ((current instanceof ApplicationHttpRequest) ||
(current instanceof HttpRequest) ||
(current instanceof HttpServletRequest)) {
// Compute a crossContext flag
HttpServletRequest hcurrent = (HttpServletRequest) current;
boolean crossContext =
!(context.getPath().equals(hcurrent.getContextPath()));
//START OF 6364900
crossContextFlag = Boolean.valueOf(crossContext);
//END OF 6364900
wrapper = new ApplicationHttpRequest
(hcurrent, context, crossContext);
} else {
wrapper = new ApplicationRequest(current);
}
if (previous == null)
state.outerRequest = wrapper;
else
((ServletRequestWrapper) previous).setRequest(wrapper);
state.wrapRequest = wrapper;
return (wrapper);
| private javax.servlet.ServletResponse | wrapResponse(org.apache.catalina.core.ApplicationDispatcher$State state)Create and return a response wrapper that has been inserted in the
appropriate spot in the response chain.
// Locate the response we should insert in front of
ServletResponse previous = null;
ServletResponse current = state.outerResponse;
while (current != null) {
if (!(current instanceof ServletResponseWrapper))
break;
if (current instanceof ApplicationHttpResponse)
break;
if (current instanceof ApplicationResponse)
break;
if (current instanceof Response)
break;
previous = current;
current = ((ServletResponseWrapper) current).getResponse();
}
// Instantiate a new wrapper at this point and insert it in the chain
ServletResponse wrapper = null;
if ((current instanceof ApplicationHttpResponse) ||
(current instanceof HttpResponse) ||
(current instanceof HttpServletResponse))
wrapper =
new ApplicationHttpResponse((HttpServletResponse) current,
state.including);
else
wrapper = new ApplicationResponse(current, state.including);
if (previous == null)
state.outerResponse = wrapper;
else
((ServletResponseWrapper) previous).setResponse(wrapper);
state.wrapResponse = wrapper;
return (wrapper);
|
|