1 18 package sync4j.server.engine; 19 20 import java.io.*; 21 import java.util.Map ; 22 import java.util.logging.Logger ; 23 import java.util.logging.Level ; 24 import javax.naming.*; 25 26 import sync4j.framework.server.SyncResponse; 27 import sync4j.framework.logging.Sync4jLogger; 28 import sync4j.framework.config.ConfigurationConstants; 29 import sync4j.framework.config.ConfigClassLoader; 30 import sync4j.framework.config.ConfigurationException; 31 import sync4j.framework.core.Constants; 32 import sync4j.framework.core.StatusCode; 33 import sync4j.framework.core.SyncML; 34 import sync4j.framework.core.Sync4jException; 35 import sync4j.framework.core.Util; 36 import sync4j.framework.engine.MessageSizeCalculator; 37 import sync4j.framework.protocol.ProtocolException; 38 import sync4j.framework.protocol.ProtocolUtil; 39 import sync4j.framework.server.session.*; 40 import sync4j.framework.server.error.*; 41 import sync4j.framework.tools.WBXMLTools; 42 import sync4j.framework.tools.WBXMLSizeCalculator; 43 import sync4j.framework.tools.XMLSizeCalculator; 44 import sync4j.framework.tools.beans.*; 45 46 import sync4j.framework.engine.pipeline.PipelineManager; 47 import sync4j.framework.engine.pipeline.MessageProcessingContext; 48 49 import sync4j.server.SyncMLCanonizer; 50 import sync4j.server.config.Configuration; 51 import sync4j.server.session.SyncSessionHandler; 52 53 import org.jibx.runtime.*; 54 import org.jibx.runtime.impl.*; 55 56 71 public class SyncAdapter 72 implements ConfigurationConstants { 73 74 protected static final String CONFIG_SYNCML_CANONIZER 76 = "sync4j/server/SyncMLCanonizer.xml"; 77 78 protected static final String PARAM_SESSION_ID = "sid"; 79 80 protected static final String HEADER_CONTENT_TYPE = "content-type"; 81 82 84 protected transient Logger log = null; 85 86 protected SessionHandler sessionHandler = null; 87 88 protected Configuration config = null; 89 90 protected PipelineManager pipelineManager = null; 91 92 protected MessageProcessingContext mpc = null; 93 94 protected SyncMLCanonizer syncMLCanonizer = null; 95 96 97 99 104 public SyncAdapter(Configuration config) { 105 super(); 106 107 log = Sync4jLogger.getLogger("server"); 108 109 this.config = config; 110 111 sessionHandler = config.getSessionHandler(); 112 pipelineManager = config.getPipelineManager(); 113 114 try { 115 syncMLCanonizer = (SyncMLCanonizer)config.getBeanInstanceByName(CONFIG_SYNCML_CANONIZER); 116 } catch (Exception e) { 117 log.throwing("SyncAdapter", "constructor", e); 118 new Sync4jException("Error " 119 + e.getClass().getName() 120 + " creating the syncMLCanonizer: " 121 + e.getMessage() 122 ).printStackTrace(); 123 } 124 125 mpc = new MessageProcessingContext(); 126 } 127 128 130 135 public void beginSync(String sessionId) { 136 mpc.setSessionProperty(mpc.PROPERTY_SESSION_ID, sessionId); 137 } 138 139 142 public void endSync() { 143 int currentState = sessionHandler.getCurrentState(); 144 145 switch (currentState) { 146 case SessionHandler.STATE_END: 147 sessionHandler.commit(); 148 break; 149 150 case SessionHandler.STATE_ERROR: 151 sessionHandler.abort(StatusCode.PROCESSING_ERROR); 152 break; 153 154 default: 155 sessionHandler.abort(StatusCode.SESSION_EXPIRED); 156 break; 157 } 158 log = null; 159 } 160 161 169 public SyncResponse processXMLMessage( final byte[] msg , 170 final Map parameters, 171 final Map headers ) 172 throws ServerException { 173 SyncResponse response = null; 174 String inMessage = null; 175 SyncML syncMLIn = null, syncMLOut = null; 176 String charset = null; 177 178 charset = getCharSetOfProlog(msg); 180 if (charset == null) { charset = getCharSet(headers); 182 if (charset == null) { charset = "UTF-8"; 184 if (log.isLoggable(Level.FINEST)) { 185 log.finest("Charset (default): " + charset); 186 } 187 } else { if (log.isLoggable(Level.FINEST)) { 189 log.finest("Charset from mime-type: " + charset); 190 } 191 } 192 } else { if (log.isLoggable(Level.FINEST)) { 194 log.finest("Charset of prolog: " + charset); 195 } 196 } 197 198 try { 199 inMessage = new String (msg, charset); 200 } catch (UnsupportedEncodingException e) { 201 inMessage = new String (msg); 204 } 205 if (log.isLoggable(Level.FINEST)) { 206 log.finest("Message to translate into the SyncML object:\n" + inMessage); 207 } 208 209 inMessage = syncMLCanonizer.canonizeInput(inMessage); 210 211 syncMLIn = convert(inMessage); 212 213 mpc.setRequestProperty(mpc.PROPERTY_REQUEST_PARAMETERS, parameters); 214 mpc.setRequestProperty(mpc.PROPERTY_REQUEST_HEADERS , headers ); 215 216 if (log.isLoggable(Level.FINE)) { 217 log.fine("Calling input pipeline"); 218 } 219 220 pipelineManager.preProcessMessage(mpc, syncMLIn); 221 222 if (log.isLoggable(Level.FINEST)) { 223 log.finest("About processing message: " + Util.toXML(syncMLIn)); 224 } 225 226 syncMLOut = processInputMessage(syncMLIn); 227 228 setRespURI(syncMLOut, (String )mpc.getSessionProperty(mpc.PROPERTY_SESSION_ID)); 229 checkRespURISize(syncMLOut.getSyncHdr().getRespURI()); 230 231 if (log.isLoggable(Level.FINEST)) { 232 log.finest("Calling output pipeline"); 233 } 234 235 pipelineManager.postProcessMessage(mpc, syncMLOut); 236 237 byte[] out = convert(syncMLOut, charset); 238 239 response = new Sync4jResponse(out, syncMLOut); 240 241 return response; 242 } 243 244 252 public SyncResponse processWBXMLMessage( final byte[] msg , 253 final Map parameters, 254 final Map headers ) 255 throws ServerException { 256 SyncResponse response = null; 257 String inMessage = null; 258 SyncML syncMLIn = null, syncMLOut = null; 259 String charset = getCharSet(headers); 260 261 if (log.isLoggable(Level.FINEST)) { 265 log.finest("Convertint message from wbxml to xml"); 266 log.finest("Char-set: " + charset + " (null, means wbxml defined)"); 267 } 268 269 try { 270 inMessage = WBXMLTools.wbxmlToXml(msg, charset); 271 } catch (Sync4jException e) { 272 throw new ServerException(e); 273 } 274 275 276 if (log.isLoggable(Level.FINEST)) { 277 log.finest("Message to translate into the SyncML object:\n" + inMessage); 278 } 279 280 inMessage = syncMLCanonizer.canonizeInput(inMessage); 281 282 syncMLIn = convert(inMessage); 283 284 mpc.setRequestProperty(mpc.PROPERTY_REQUEST_PARAMETERS, parameters); 285 mpc.setRequestProperty(mpc.PROPERTY_REQUEST_HEADERS , headers ); 286 287 if (log.isLoggable(Level.FINE)) { 288 log.fine("Calling input pipeline"); 289 } 290 pipelineManager.preProcessMessage(mpc, syncMLIn); 291 292 if (log.isLoggable(Level.FINEST)) { 293 log.finest("About processing message: " + Util.toXML(syncMLIn)); 294 } 295 296 syncMLOut = processInputMessage(syncMLIn); 297 298 setRespURI(syncMLOut, (String )mpc.getSessionProperty(mpc.PROPERTY_SESSION_ID)); 299 checkRespURISize(syncMLOut.getSyncHdr().getRespURI()); 300 301 if (log.isLoggable(Level.FINEST)) { 302 log.finest("Calling output pipeline"); 303 } 304 305 pipelineManager.postProcessMessage(mpc, syncMLOut); 306 307 byte[] out = null; 308 try { 309 out = WBXMLTools.toWBXML(syncMLOut); 314 315 } catch(Exception e) { 316 if (log.isLoggable(Level.SEVERE)) { 317 log.severe("Error processing the WBXML message: " + e.getMessage()); 318 } 319 log.throwing("SyncAdapter", "processWBXMLMessage", e); 320 321 throw new ServerException(e); 322 } 323 324 response = new Sync4jResponse(out, syncMLOut); 325 326 327 return response; 328 } 329 330 335 private String getCharSetOfProlog(byte[] msg) { 336 if ((msg[0] == '<') && (msg[1] == '?') && (msg[2] == 'x') && (msg[2] == 'm') && (msg[4] == 'l')) { 338 int length = msg.length - 1; for (int i = 5; i < length; i++) { 341 if ((msg[i] == '?') && (msg[i+1] == '>')) { 342 String prolog = new String (msg, 0, i+1); 344 if (log.isLoggable(Level.FINEST)) { 345 log.finest("Message prolog: " + prolog); 346 } 347 int p = prolog.indexOf("encoding"); 349 int q1 = prolog.indexOf('"', p); 351 int q2 = prolog.indexOf('"', q1); 353 return prolog.substring(q1, q2); 354 } 355 } 356 } 357 return null; } 359 360 365 private String getCharSet(Map headers) { 366 String contentType = (String )headers.get(HEADER_CONTENT_TYPE); 367 if (log.isLoggable(Level.FINEST)) { 368 log.finest("Message has content type: " + contentType); 369 } 370 if (contentType != null) { 371 int pointer = contentType.indexOf(';'); 373 if (pointer > 0) { 374 pointer = contentType.indexOf('=', pointer); 377 if (pointer > 0) { 378 String result = contentType.substring(pointer+1); 379 return result.trim(); 381 } 382 } 383 } 384 return null; } 386 387 396 public SyncResponse processStatusCode(int statusCode, String info){ 397 if (statusCode != StatusCode.OK) { 398 sessionHandler.abort(statusCode); 399 } 400 return null; 401 } 402 403 405 413 private SyncML processInputMessage(final SyncML syncMLIn) throws ServerException { 414 try { 415 try { 416 sessionHandler.setSizeCalculator( 417 getSizeCalculator() 418 ); 419 return sessionHandler.processMessage(syncMLIn, mpc); 420 } catch (InvalidCredentialsException e) { 421 return sessionHandler.processError(syncMLIn, e); 422 } catch (ServerException e) { 423 return sessionHandler.processError(syncMLIn, e); 424 } catch (ProtocolException e) { 425 return sessionHandler.processError(syncMLIn, 426 new BadRequestException(e.getMessage())); 427 } 428 429 } catch (Sync4jException e1) { 430 throw new ServerException(e1); 434 } 435 } 436 437 446 private SyncML convert(final String msg) throws ServerException { 447 try { 448 IBindingFactory f = BindingDirectory.getFactory(SyncML.class); 449 IUnmarshallingContext c = f.createUnmarshallingContext(); 450 451 Object syncML = c.unmarshalDocument(new StringReader(msg)); 452 453 return (SyncML)syncML; 454 } catch(JiBXException e) { 455 if (log.isLoggable(Level.SEVERE)) { 456 log.severe("Error unmarshalling message:" + e.getMessage()); 457 } 458 log.throwing(getClass().getName(), "convert", e); 459 throw new ServerException(e); 460 } 461 } 462 463 473 private byte[] convert(final SyncML msg, String charset) 474 throws ServerException { 475 try { 476 if (log.isLoggable(Level.FINEST)) { 477 log.finest("Creating response with charset: " + charset); 478 } 479 480 ByteArrayOutputStream bout = new ByteArrayOutputStream(); 481 IBindingFactory f = BindingDirectory.getFactory(SyncML.class); 482 IMarshallingContext c = f.createMarshallingContext(); 483 c.setIndent(0); 484 c.marshalDocument(msg, charset, null, bout); 485 486 return syncMLCanonizer.canonizeOutput(bout.toString(charset)).getBytes(charset); 490 491 } catch(Exception e) { 492 if (log.isLoggable(Level.SEVERE)) { 493 log.severe("Error in converting the message:" + e.getMessage()); 494 } 495 log.throwing(getClass().getName(), "convert", e); 496 497 throw new ServerException(e); 498 } 499 } 500 501 507 private void setRespURI(SyncML msg, final String sessionId) { 508 msg.getSyncHdr().setRespURI( 509 config.getServerConfig().getEngineConfiguration().getServerURI() + 510 '?' + 511 PARAM_SESSION_ID + 512 '=' + 513 sessionId 514 ); 515 } 516 517 526 private void checkRespURISize(String uri) { 527 final long s = uri.length() + 20; 531 final long h = getSizeCalculator().getRespURIOverhead(); 532 533 if ((log.isLoggable(Level.WARNING)) && (h < s)) { 534 log.warning( "The RespURI element size (" 535 + s 536 + ") exeeds the reserved hoverhead (" 537 + h 538 + ')' 539 ); 540 } 541 } 542 543 549 private MessageSizeCalculator getSizeCalculator() { 550 Map headers = (Map )mpc.getRequestProperty(mpc.PROPERTY_REQUEST_HEADERS); 551 552 String contentType = (String )headers.get(HEADER_CONTENT_TYPE); 553 554 MessageSizeCalculator calculator = null; 555 556 if ((contentType != null) && Constants.MIMETYPE_SYNCMLDS_WBXML.equals(contentType)) { 557 calculator = new WBXMLSizeCalculator(); 558 } else { 559 calculator = new XMLSizeCalculator(); 560 } 561 562 return calculator; 563 } 564 565 567 private static class Sync4jResponse implements SyncResponse { 568 private byte[] msg; 569 private boolean completed; 570 571 579 private Sync4jResponse(final byte[] msg, 580 final SyncML syncML) { 581 this.msg = msg; 582 this.completed = (syncML.isLastMessage() && 583 ProtocolUtil.noMoreResponse(syncML) && 584 (ProtocolUtil.getStatusChal(syncML) == null)); 585 } 586 587 public byte[] getMessage() { 588 return this.msg; 589 } 590 591 596 public boolean isCompleted() { 597 return completed; 598 } 599 } 600 } 601 | Popular Tags |