?? dwrpplainjsmarshaller.java
字號(hào):
/*
* Copyright 2005 Joe Walker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.directwebremoting.dwrp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.directwebremoting.AccessControl;
import org.directwebremoting.Call;
import org.directwebremoting.Calls;
import org.directwebremoting.ConverterManager;
import org.directwebremoting.Creator;
import org.directwebremoting.CreatorManager;
import org.directwebremoting.InboundContext;
import org.directwebremoting.InboundVariable;
import org.directwebremoting.MarshallException;
import org.directwebremoting.Marshaller;
import org.directwebremoting.OutboundContext;
import org.directwebremoting.OutboundVariable;
import org.directwebremoting.Replies;
import org.directwebremoting.Reply;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.TypeHintContext;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.remoted.DwrSystem;
import org.directwebremoting.util.ContinuationUtil;
import org.directwebremoting.util.DebuggingPrintWriter;
import org.directwebremoting.util.JavascriptUtil;
import org.directwebremoting.util.LocalUtil;
import org.directwebremoting.util.Logger;
import org.directwebremoting.util.Messages;
import org.directwebremoting.util.MimeConstants;
/**
* A Marshaller that output plain Javascript.
* This marshaller can be tweaked to output Javascript in an HTML context.
* This class works in concert with DirectScriptConduit, they should be
* considered closely related and it is important to understand what one does
* while editing the other.
* @author Joe Walker [joe at getahead dot ltd dot uk]
*/
public class DwrpPlainJsMarshaller implements Marshaller
{
/* (non-Javadoc)
* @see org.directwebremoting.Marshaller#marshallInbound(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public Calls marshallInbound(HttpServletRequest request, HttpServletResponse response) throws IOException
{
// We must parse the parameters before we setup the conduit because it's
// only after doing this that we know the scriptSessionId
WebContext webContext = WebContextFactory.get();
ParseResponse parseResponse = (ParseResponse) request.getAttribute(ATTRIBUTE_PARSE_RESPONSE);
if (parseResponse == null)
{
parseResponse = parseRequest(request);
// Save calls for retry exception
request.setAttribute(ATTRIBUTE_PARSE_RESPONSE, parseResponse);
}
// Various bits of parseResponse need to be stashed away places
storeParseResponse(request, webContext, parseResponse);
Calls calls = parseResponse.getCalls();
// Special case handling for long poll of the DWRSystem.poll() method.
// If there is only 1 call and that call is a Poll, then we will wait until
// there are scripts to send. If there is more than 1 request, do not suspend
// as it should not be held up by the poll.
if (calls.getCallCount() == 1)
{
Call call = calls.getCall(0);
if ("DWRSystem".equals(call.getScriptName()) && "poll".equals(call.getMethodName())) //$NON-NLS-1$ //$NON-NLS-2$
{
try
{
DwrSystem system = (DwrSystem) webContext.getServletContext().getAttribute(call.getScriptName());
if (system != null)
{
system.pollPreStreamWait();
}
}
catch (Exception ex)
{
// Allow Jetty RequestRetry exception to propogate to container
ContinuationUtil.rethrowIfContinuation(ex);
log.warn("Error calling pollWait()", ex); //$NON-NLS-1$
}
}
}
// Get the output stream and setup the mimetype
response.setContentType(getOutboundMimeType());
PrintWriter out;
if (log.isDebugEnabled())
{
// This might be considered evil - altering the program flow
// depending on the log status, however DebuggingPrintWriter is
// very thin and only about logging
out = new DebuggingPrintWriter("", response.getWriter()); //$NON-NLS-1$
}
else
{
out = response.getWriter();
}
// Save the output stream so the outbound marshaller can get at it
request.setAttribute(ATTRIBUTE_REQUEST, out);
// The conduit to pass on reverse ajax scripts
DirectScriptConduit conduit = new DirectScriptConduit(out, this);
request.setAttribute(ATTRIBUTE_CONDUIT, conduit);
// Setup a debugging prefix
if (out instanceof DebuggingPrintWriter)
{
DebuggingPrintWriter dpw = (DebuggingPrintWriter) out;
dpw.setPrefix("out(" + conduit.hashCode() + "): "); //$NON-NLS-1$ //$NON-NLS-2$
}
// Send the script prefix (if any)
sendOutboundScriptPrefix(out);
// From the call to addScriptConduit() there could be 2 threads writing
// to 'out' so we synchronize on 'out' to make sure there are no
// clashes
ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
scriptSession.addScriptConduit(conduit);
// Debug the environment
if (log.isDebugEnabled() && calls.getCallCount() > 0)
{
// We can just use 0 because they are all shared
InboundContext inctx = (InboundContext) parseResponse.getInboundContexts().get(0);
StringBuffer buffer = new StringBuffer();
for (Iterator it = inctx.getInboundVariableNames(); it.hasNext();)
{
String key = (String) it.next();
InboundVariable value = inctx.getInboundVariable(key);
if (key.startsWith(ConversionConstants.INBOUND_CALLNUM_PREFIX) &&
key.indexOf(ConversionConstants.INBOUND_CALLNUM_SUFFIX + ConversionConstants.INBOUND_KEY_ENV) != -1)
{
buffer.append(key + '=' + value.toString() + ", "); //$NON-NLS-1$
}
}
if (buffer.length() > 0)
{
log.debug("Environment: " + buffer.toString()); //$NON-NLS-1$
}
}
callLoop:
for (int callNum = 0; callNum < calls.getCallCount(); callNum++)
{
Call call = calls.getCall(callNum);
InboundContext inctx = (InboundContext) parseResponse.getInboundContexts().get(callNum);
// Get a list of the available matching methods with the coerced
// parameters that we will use to call it if we choose to use
// that method.
Creator creator = creatorManager.getCreator(call.getScriptName());
// Which method are we using?
Method method = findMethod(call, inctx);
call.setMethod(method);
if (method == null)
{
String name = call.getScriptName() + '.' + call.getMethodName();
throw new IllegalArgumentException(Messages.getString("DefaultRemoter.UnknownMethod", name)); //$NON-NLS-1$
}
// Check this method is accessible
String reason = accessControl.getReasonToNotExecute(creator, call.getScriptName(), method);
if (reason != null)
{
throw new SecurityException(Messages.getString("ExecuteQuery.AccessDenied")); //$NON-NLS-1$
}
// Convert all the parameters to the correct types
Object[] params = new Object[method.getParameterTypes().length];
for (int j = 0; j < method.getParameterTypes().length; j++)
{
try
{
Class paramType = method.getParameterTypes()[j];
InboundVariable param = inctx.getParameter(callNum, j);
TypeHintContext incc = new TypeHintContext(converterManager, method, j);
params[j] = converterManager.convertInbound(paramType, param, inctx, incc);
}
catch (MarshallException ex)
{
log.warn("Marshalling exception: " + ex.getMessage()); //$NON-NLS-1$
call.setMethod(null);
call.setParameters(null);
call.setException(ex);
continue callLoop;
}
}
call.setParameters(params);
}
return calls;
}
/**
* @param request
* @param webContext
* @param parseResponse
*/
private void storeParseResponse(HttpServletRequest request, WebContext webContext, ParseResponse parseResponse)
{
webContext.setCurrentPageInformation(parseResponse.getPage(), parseResponse.getScriptSessionId());
// Remaining parameters get put into the request for later consumption
Map paramMap = parseResponse.getSpareParameters();
if (paramMap.size() != 0)
{
for (Iterator it = paramMap.entrySet().iterator(); it.hasNext();)
{
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
String value = (String) entry.getValue();
request.setAttribute(key, value);
log.debug("Moved param to request: " + key + "=" + value); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
/**
* Find the method the best matches the method name and parameters
* @param call The function call we are going to make
* @param inctx The data conversion context
* @return A matching method, or null if one was not found.
*/
private Method findMethod(Call call, InboundContext inctx)
{
if (call.getScriptName() == null)
{
throw new IllegalArgumentException(Messages.getString("DefaultRemoter.MissingClassParam")); //$NON-NLS-1$
}
if (call.getMethodName() == null)
{
throw new IllegalArgumentException(Messages.getString("DefaultRemoter.MissingMethodParam")); //$NON-NLS-1$
}
Creator creator = creatorManager.getCreator(call.getScriptName());
Method[] methods = creator.getType().getMethods();
List available = new ArrayList();
methods:
for (int i = 0; i < methods.length; i++)
{
// Check method name and access
if (methods[i].getName().equals(call.getMethodName()))
{
// Check number of parameters
if (methods[i].getParameterTypes().length == inctx.getParameterCount())
{
// Clear the previous conversion attempts (the param types
// will probably be different)
inctx.clearConverted();
// Check parameter types
for (int j = 0; j < methods[i].getParameterTypes().length; j++)
{
Class paramType = methods[i].getParameterTypes()[j];
if (!converterManager.isConvertable(paramType))
{
// Give up with this method and try the next
continue methods;
}
}
available.add(methods[i]);
}
}
}
// Pick a method to call
if (available.size() > 1)
{
log.warn("Warning multiple matching methods. Using first match."); //$NON-NLS-1$
}
if (available.isEmpty())
{
String name = call.getScriptName() + '.' + call.getMethodName();
throw new IllegalArgumentException(Messages.getString("DefaultRemoter.UnknownMethod", name)); //$NON-NLS-1$
}
// At the moment we are just going to take the first match, for a
// later increment we might pick the best implementation
return (Method) available.get(0);
}
/* (non-Javadoc)
* @see org.directwebremoting.Marshaller#marshallOutbound(org.directwebremoting.Replies, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
public void marshallOutbound(Replies replies, HttpServletRequest request, HttpServletResponse response) throws IOException
{
// We build the answer up in a StringBuffer because that makes is easier
// to debug, and because that's only what the compiler does anyway.
PrintWriter out = (PrintWriter) request.getAttribute(ATTRIBUTE_REQUEST);
DirectScriptConduit conduit = (DirectScriptConduit) request.getAttribute(ATTRIBUTE_CONDUIT);
ScriptSession scriptSession = WebContextFactory.get().getScriptSession();
OutboundContext converted = new OutboundContext();
for (int i = 0; i < replies.getReplyCount(); i++)
{
Reply reply = replies.getReply(i);
// The existance of a throwable indicates that something went wrong
if (reply.getThrowable() != null)
{
Throwable ex = reply.getThrowable();
OutboundVariable ov = convertException(ex, converted);
String script = ov.getInitCode() + "DWREngine._handleServerError('" + reply.getId() + "', " + ov.getAssignCode() + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
sendScript(out, script);
log.warn("--Erroring: id[" + reply.getId() + "] message[" + ex.toString() + ']'); //$NON-NLS-1$ //$NON-NLS-2$
}
else
{
Object data = reply.getReply();
try
{
OutboundVariable ov = converterManager.convertOutbound(data, converted);
String script = ov.getInitCode() + "DWREngine._handleResponse('" + reply.getId() + "', " + ov.getAssignCode() + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
sendScript(out, script);
}
catch (MarshallException ex)
{
OutboundVariable ov = convertException(ex, converted);
String script = ov.getInitCode() + "DWREngine._handleServerError('" + reply.getId() + "', " + ov.getAssignCode() + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
sendScript(out, script);
log.warn("--MarshallException: id[" + reply.getId() + "] message[" + ex.toString() + ']'); //$NON-NLS-1$ //$NON-NLS-2$
}
catch (Exception ex)
{
OutboundVariable ov = convertException(ex, converted);
String script = ov.getInitCode() + "DWREngine._handleServerError('" + reply.getId() + "', " + ov.getAssignCode() + ");"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
sendScript(out, script);
log.warn("--Erroring: id[" + reply.getId() + "] message[" + ex.toString() + ']', ex); //$NON-NLS-1$ //$NON-NLS-2$
}
}
}
scriptSession.removeScriptConduit(conduit);
conduit.close();
sendOutboundScriptSuffix(out);
// log.debug(replyString);
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -