1 16 package org.directwebremoting.dwrp; 17 18 import java.io.IOException ; 19 import java.io.PrintWriter ; 20 import java.lang.reflect.Method ; 21 import java.util.ArrayList ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 26 import javax.servlet.http.HttpServletRequest ; 27 import javax.servlet.http.HttpServletResponse ; 28 29 import org.directwebremoting.ScriptBuffer; 30 import org.directwebremoting.WebContext; 31 import org.directwebremoting.WebContextFactory; 32 import org.directwebremoting.extend.AccessControl; 33 import org.directwebremoting.extend.Call; 34 import org.directwebremoting.extend.Calls; 35 import org.directwebremoting.extend.ConverterManager; 36 import org.directwebremoting.extend.Creator; 37 import org.directwebremoting.extend.CreatorManager; 38 import org.directwebremoting.extend.InboundContext; 39 import org.directwebremoting.extend.InboundVariable; 40 import org.directwebremoting.extend.MarshallException; 41 import org.directwebremoting.extend.Marshaller; 42 import org.directwebremoting.extend.PageNormalizer; 43 import org.directwebremoting.extend.RealScriptSession; 44 import org.directwebremoting.extend.EnginePrivate; 45 import org.directwebremoting.extend.Replies; 46 import org.directwebremoting.extend.Reply; 47 import org.directwebremoting.extend.ScriptBufferUtil; 48 import org.directwebremoting.extend.ScriptConduit; 49 import org.directwebremoting.extend.ServerException; 50 import org.directwebremoting.extend.TypeHintContext; 51 import org.directwebremoting.util.DebuggingPrintWriter; 52 import org.directwebremoting.util.Logger; 53 import org.directwebremoting.util.Messages; 54 55 63 public abstract class BaseCallMarshaller implements Marshaller 64 { 65 68 public Calls marshallInbound(HttpServletRequest request, HttpServletResponse response) throws IOException , ServerException 69 { 70 73 WebContext webContext = WebContextFactory.get(); 74 Batch batch = (Batch) request.getAttribute(ATTRIBUTE_BATCH); 75 if (batch == null) 76 { 77 batch = new Batch(request, crossDomainSessionSecurity, allowGetForSafariButMakeForgeryEasier, sessionCookieName); 78 79 request.setAttribute(ATTRIBUTE_BATCH, batch); 81 } 82 83 storeParsedRequest(request, webContext, batch); 85 86 Calls calls = batch.getCalls(); 87 88 if (log.isDebugEnabled() && calls.getCallCount() > 0) 90 { 91 InboundContext inctx = (InboundContext) batch.getInboundContexts().get(0); 93 StringBuffer buffer = new StringBuffer (); 94 95 for (Iterator it = inctx.getInboundVariableNames(); it.hasNext();) 96 { 97 String key = (String ) it.next(); 98 InboundVariable value = inctx.getInboundVariable(key); 99 if (key.startsWith(ProtocolConstants.INBOUND_CALLNUM_PREFIX) && 100 key.indexOf(ProtocolConstants.INBOUND_CALLNUM_SUFFIX + ProtocolConstants.INBOUND_KEY_ENV) != -1) 101 { 102 buffer.append(key); 103 buffer.append('='); 104 buffer.append(value.toString()); 105 buffer.append(", "); 106 } 107 } 108 109 if (buffer.length() > 0) 110 { 111 log.debug("Environment: " + buffer.toString()); 112 } 113 } 114 115 callLoop: 116 for (int callNum = 0; callNum < calls.getCallCount(); callNum++) 117 { 118 Call call = calls.getCall(callNum); 119 InboundContext inctx = (InboundContext) batch.getInboundContexts().get(callNum); 120 121 Creator creator = creatorManager.getCreator(call.getScriptName()); 125 126 Method method = findMethod(call, inctx); 128 if (method == null) 129 { 130 String name = call.getScriptName() + '.' + call.getMethodName(); 131 String error = Messages.getString("BaseCallMarshaller.UnknownMethod", name); 132 log.warn("Marshalling exception: " + error); 133 134 call.setMethod(null); 135 call.setParameters(null); 136 call.setException(new IllegalArgumentException (error)); 137 138 continue callLoop; 139 } 140 141 call.setMethod(method); 142 143 accessControl.assertExecutionIsPossible(creator, call.getScriptName(), method); 145 146 Object [] params = new Object [method.getParameterTypes().length]; 148 for (int j = 0; j < method.getParameterTypes().length; j++) 149 { 150 try 151 { 152 Class paramType = method.getParameterTypes()[j]; 153 InboundVariable param = inctx.getParameter(callNum, j); 154 TypeHintContext incc = new TypeHintContext(converterManager, method, j); 155 params[j] = converterManager.convertInbound(paramType, param, inctx, incc); 156 } 157 catch (MarshallException ex) 158 { 159 log.warn("Marshalling exception", ex); 160 161 call.setMethod(null); 162 call.setParameters(null); 163 call.setException(ex); 164 165 continue callLoop; 166 } 167 } 168 169 call.setParameters(params); 170 } 171 172 return calls; 173 } 174 175 181 private void storeParsedRequest(HttpServletRequest request, WebContext webContext, Batch batch) 182 { 183 String normalizedPage = pageNormalizer.normalizePage(batch.getPage()); 184 webContext.setCurrentPageInformation(normalizedPage, batch.getScriptSessionId()); 185 186 Map paramMap = batch.getSpareParameters(); 188 if (paramMap.size() != 0) 189 { 190 for (Iterator it = paramMap.entrySet().iterator(); it.hasNext();) 191 { 192 Map.Entry entry = (Map.Entry ) it.next(); 193 String key = (String ) entry.getKey(); 194 String value = (String ) entry.getValue(); 195 196 request.setAttribute(key, value); 197 log.debug("Moved param to request: " + key + "=" + value); 198 } 199 } 200 } 201 202 208 private Method findMethod(Call call, InboundContext inctx) 209 { 210 if (call.getScriptName() == null) 211 { 212 throw new IllegalArgumentException (Messages.getString("BaseCallMarshaller.MissingClassParam")); 213 } 214 215 if (call.getMethodName() == null) 216 { 217 throw new IllegalArgumentException (Messages.getString("BaseCallMarshaller.MissingMethodParam")); 218 } 219 220 Creator creator = creatorManager.getCreator(call.getScriptName()); 221 Method [] methods = creator.getType().getMethods(); 222 List available = new ArrayList (); 223 224 methods: 225 for (int i = 0; i < methods.length; i++) 226 { 227 if (methods[i].getName().equals(call.getMethodName())) 229 { 230 if (methods[i].getParameterTypes().length == inctx.getParameterCount()) 232 { 233 inctx.clearConverted(); 236 237 for (int j = 0; j < methods[i].getParameterTypes().length; j++) 239 { 240 Class paramType = methods[i].getParameterTypes()[j]; 241 if (!converterManager.isConvertable(paramType)) 242 { 243 continue methods; 245 } 246 } 247 248 available.add(methods[i]); 249 } 250 } 251 } 252 253 if (available.size() > 1) 255 { 256 log.warn("Warning multiple matching methods. Using first match."); 257 } 258 259 if (available.isEmpty()) 260 { 261 return null; 262 } 263 264 return (Method ) available.get(0); 267 } 268 269 272 public void marshallOutbound(Replies replies, HttpServletRequest request, HttpServletResponse response) throws IOException 273 { 274 response.setContentType(getOutboundMimeType()); 276 PrintWriter out; 277 if (log.isDebugEnabled()) 278 { 279 out = new DebuggingPrintWriter("", response.getWriter()); 283 } 284 else 285 { 286 out = response.getWriter(); 287 } 288 289 ScriptConduit conduit = new CallScriptConduit(out); 291 292 if (out instanceof DebuggingPrintWriter) 294 { 295 DebuggingPrintWriter dpw = (DebuggingPrintWriter) out; 296 dpw.setPrefix("out(" + conduit.hashCode() + "): "); 297 } 298 299 sendOutboundScriptPrefix(out, replies.getBatchId()); 301 302 RealScriptSession scriptSession = (RealScriptSession) WebContextFactory.get().getScriptSession(); 306 307 out.println(ProtocolConstants.SCRIPT_CALL_INSERT); 308 scriptSession.writeScripts(conduit); 309 out.println(ProtocolConstants.SCRIPT_CALL_REPLY); 310 311 String batchId = replies.getBatchId(); 312 for (int i = 0; i < replies.getReplyCount(); i++) 313 { 314 Reply reply = replies.getReply(i); 315 String callId = reply.getCallId(); 316 317 try 318 { 319 if (reply.getThrowable() != null) 321 { 322 Throwable ex = reply.getThrowable(); 323 EnginePrivate.remoteHandleException(conduit, batchId, callId, ex); 324 325 log.warn("--Erroring: batchId[" + batchId + "] message[" + ex.toString() + ']'); 326 } 327 else 328 { 329 Object data = reply.getReply(); 330 EnginePrivate.remoteHandleCallback(conduit, batchId, callId, data); 331 } 332 } 333 catch (IOException ex) 334 { 335 log.error("--Output Error: batchId[" + batchId + "] message[" + ex.toString() + ']', ex); 339 } 340 catch (MarshallException ex) 341 { 342 EnginePrivate.remoteHandleMarshallException(conduit, batchId, callId, ex); 343 log.warn("--MarshallException: batchId=" + batchId + " class=" + ex.getConversionType().getName(), ex); 344 } 345 catch (Exception ex) 346 { 347 EnginePrivate.remoteHandleException(conduit, batchId, callId, ex); 351 log.error("--MarshallException: batchId=" + batchId + " message=" + ex.toString()); 352 } 353 } 354 355 sendOutboundScriptSuffix(out, replies.getBatchId()); 356 } 357 358 361 public void marshallException(HttpServletRequest request, HttpServletResponse response, Exception ex) throws IOException 362 { 363 response.setContentType(getOutboundMimeType()); 364 PrintWriter out = response.getWriter(); 365 Batch batch = (Batch) request.getAttribute(ATTRIBUTE_BATCH); 366 367 String batchId; 368 if (batch != null && batch.getCalls() != null) 369 { 370 batchId = batch.getCalls().getBatchId(); 371 } 372 else 373 { 374 batchId = null; 375 } 376 377 sendOutboundScriptPrefix(out, batchId); 378 String script = EnginePrivate.getRemoteHandleBatchExceptionScript(batchId, ex); 379 out.print(script); 380 sendOutboundScriptSuffix(out, batchId); 381 } 382 383 389 protected abstract void sendScript(PrintWriter out, String script) throws IOException ; 390 391 395 protected abstract String getOutboundMimeType(); 396 397 403 protected abstract void sendOutboundScriptPrefix(PrintWriter out, String batchId) throws IOException ; 404 405 411 protected abstract void sendOutboundScriptSuffix(PrintWriter out, String batchId) throws IOException ; 412 413 416 public boolean isConvertable(Class paramType) 417 { 418 return converterManager.isConvertable(paramType); 419 } 420 421 425 public void setConverterManager(ConverterManager converterManager) 426 { 427 this.converterManager = converterManager; 428 } 429 430 434 public void setCreatorManager(CreatorManager creatorManager) 435 { 436 this.creatorManager = creatorManager; 437 } 438 439 443 public void setAccessControl(AccessControl accessControl) 444 { 445 this.accessControl = accessControl; 446 } 447 448 452 public void setPageNormalizer(PageNormalizer pageNormalizer) 453 { 454 this.pageNormalizer = pageNormalizer; 455 } 456 457 461 public void setCrossDomainSessionSecurity(boolean crossDomainSessionSecurity) 462 { 463 this.crossDomainSessionSecurity = crossDomainSessionSecurity; 464 } 465 466 469 public void setAllowGetForSafariButMakeForgeryEasier(boolean allowGetForSafariButMakeForgeryEasier) 470 { 471 this.allowGetForSafariButMakeForgeryEasier = allowGetForSafariButMakeForgeryEasier; 472 } 473 474 478 public void setSessionCookieName(String sessionCookieName) 479 { 480 this.sessionCookieName = sessionCookieName; 481 } 482 483 490 protected class CallScriptConduit extends ScriptConduit 491 { 492 496 protected CallScriptConduit(PrintWriter out) 497 { 498 super(RANK_SLOW); 499 if (out == null) 500 { 501 throw new NullPointerException ("out=null"); 502 } 503 504 this.out = out; 505 } 506 507 510 public boolean addScript(ScriptBuffer script) throws IOException , MarshallException 511 { 512 sendScript(out, ScriptBufferUtil.createOutput(script, converterManager)); 513 return true; 514 } 515 516 519 private final PrintWriter out; 520 } 521 522 525 protected String sessionCookieName = "JSESSIONID"; 526 527 530 private boolean allowGetForSafariButMakeForgeryEasier = false; 531 532 535 protected boolean crossDomainSessionSecurity = true; 536 537 540 protected PageNormalizer pageNormalizer = null; 541 542 545 protected ConverterManager converterManager = null; 546 547 550 protected CreatorManager creatorManager = null; 551 552 555 protected AccessControl accessControl = null; 556 557 560 protected static final String ATTRIBUTE_REQUEST = "org.directwebremoting.dwrp.request"; 561 562 565 protected static final String ATTRIBUTE_CONDUIT = "org.directwebremoting.dwrp.conduit"; 566 567 570 protected static final String ATTRIBUTE_BATCH = "org.directwebremoting.dwrp.batch"; 571 572 575 protected static final Logger log = Logger.getLogger(BaseCallMarshaller.class); 576 } 577 | Popular Tags |