PPG.java
上传用户:weisa_1
上传日期:2007-10-14
资源大小:287k
文件大小:10k
源码类别:

手机WAP编程

开发平台:

Java

  1. package push;
  2. import javax.servlet.*;
  3. import javax.servlet.http.*;
  4. import java.net.*;
  5. import java.io.*;
  6. import java.util.StringTokenizer;
  7. /**
  8.  * <code>PPG</code> class implements some push proxy gateway (PPG) functionality for 
  9.  * the purposes of this example only. This simple PPG is targeted to be used in 
  10.  * conjunction with WAP toolkit, and IPv4 type client addressing. 
  11.  *
  12.  */
  13. public final class PPG extends HttpServlet {
  14.     /* xml version */
  15.     private final static String XML_VERSION = "<?xml version="1.0"?>"; 
  16.     /* Push Access Protocol (PAP) document type */
  17.     private final static String PAP_DOCTYPE = 
  18. "<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 1.0//EN" "http://www.wapforum.org/DTD/pap_1.0.dtd" >";
  19.     /* content type of the push request multipart body */
  20.     private final static String CONTENT_TYPE = 
  21. "multipart/related; boundary=multipart-boundary; type="application/xml"";
  22.     /* WAP Push connection less service (client side). The registered port number. */
  23.     private static final int connectionlessPushPort = 2948; 
  24.     private static int transactionId = 0;
  25.     /**
  26.      * <code>doPost</code>
  27.      *
  28.      * @param request a <code>HttpServletRequest</code> value
  29.      * @param response a <code>HttpServletResponse</code> value
  30.      * @exception ServletException if an error occurs
  31.      * @exception IOException if an error occurs
  32.      */
  33.     public void doPost(HttpServletRequest request, HttpServletResponse response) 
  34. throws ServletException, IOException {
  35. String clientAddress = null;
  36. String pushId = null;
  37. int resultCode = 1001; // accepted for processing
  38. try {
  39.     // first, check the content type which should be "multipart/related"
  40.     String contentType = request.getHeader("content-type");
  41.     StringTokenizer st = new StringTokenizer(contentType, ";");
  42.     String token = st.nextToken();
  43.     String boundary = null;
  44.     if(!token.equalsIgnoreCase("multipart/related")) throw new Exception("wrong content type");
  45.     // finds the boundary string
  46.     while(st.hasMoreTokens()) {
  47. token = st.nextToken().trim();
  48. if(token.startsWith("boundary=")) {   
  49.     boundary = token.substring(9);
  50.     break;
  51. }
  52.     }
  53.     if(boundary == null) throw new Exception("no multipart boundary"); 
  54.     boundary = "--" + boundary;
  55.     String endBoundary = boundary + "--";
  56.     StringBuffer messageContent = new StringBuffer();
  57.     BufferedReader in = request.getReader();
  58.     String line;
  59.     int i=0;
  60.     boolean startContent = false;
  61.  System.out.println("boundary=" + boundary);
  62.     // extract message content part
  63.     while((line = in.readLine()) != null) {
  64. if(line.equals(boundary)) 
  65.     ++i;
  66. else if(line.equals(endBoundary))
  67.     break;
  68. if(i == 1) { // PAP control entity
  69.     int j = line.indexOf("address-value=");
  70.     if(j >= 0) {
  71. clientAddress = line.substring(j+15, line.indexOf('"', j+17));
  72.     }
  73.     j = line.indexOf("push-id=");
  74.     if(j >= 0) {
  75. pushId = line.substring(j+9, line.indexOf('"', j+11));
  76.     }
  77. }
  78. else if(i == 2) { // PAP content entity
  79.     if(startContent) 
  80. messageContent.append(line);
  81.     else if(line.trim().equals("")) // end of headers
  82. startContent = true;
  83.     else if(line.toLowerCase().startsWith("content-type:")) 
  84. contentType = line.substring(13).trim();
  85. }
  86.     }
  87.     if((i = clientAddress.indexOf("/TYPE=IPv4")) == -1) {
  88. resultCode = 2002; // address error
  89. throw new Exception("This PPG can handle only IPv4 type addresses");
  90.     }
  91.     clientAddress = clientAddress.substring(clientAddress.indexOf("WAPPUSH=")+8, i);
  92.     if(clientAddress == null) { 
  93. resultCode = 2002; // address error
  94. throw new Exception("Client address is not known");
  95.     }
  96.     System.out.println("clientAddress: " + clientAddress);
  97.     System.out.println("pushId: " + pushId);
  98.     System.out.println("message content: " + messageContent);
  99.     
  100.     unitPushRequest(clientAddress, messageContent.toString().trim(), contentType);
  101. }
  102. catch (Exception e) {
  103.     System.err.println(e);
  104.     if(resultCode < 2000) resultCode = 2000; // bad message
  105. }
  106. // start writing the result
  107. response.setStatus(202); // accepted
  108. response.setContentType("application/xml");
  109. PrintWriter out = response.getWriter();
  110. out.println(XML_VERSION);
  111. out.println(PAP_DOCTYPE);
  112. out.println("<pap product-name="MobileZoo PPG">");
  113. out.println("  <push-response push-id="" + pushId  + "">");
  114. out.println("    <response result");
  115. out.println("       code="" + resultCode + """);
  116. out.println("       desc="" + resultCodeDesc(resultCode) + "">");
  117. out.println("    </response-result>");
  118. out.println("  </push-response>");
  119. out.println("</pap>");
  120.     }
  121.     /**
  122.      * Returns description of a PAP result response code
  123.      *
  124.      * @param code an <code>int</code> value
  125.      * @return a <code>String</code> value
  126.      */
  127.     private static String resultCodeDesc(int code) {
  128. switch(code) {
  129. case 1001:
  130.     return "Accepted for Processing";
  131. case 2000:
  132.     return "Bad Request";
  133. case 2002:
  134.     return "Address Error";
  135. }
  136. return "Unknown result code";
  137.     }
  138.     /**
  139.      * <code>unitPushRequest</code> generates a connectionless mode Push request
  140.      *
  141.      * @param clientAddress a <code>String</code> value
  142.      * @param messageContent a <code>String</code> value
  143.      * @param contentType a <code>String</code> value
  144.      * @exception Exception if an error occurs
  145.      */
  146.     private void unitPushRequest(String clientAddress, String messageContent, 
  147.  String contentType) 
  148. throws Exception {
  149. ByteArrayOutputStream content = new ByteArrayOutputStream();
  150. contentType = encodeContent(messageContent, content, contentType);
  151. int wspContentType = encodeContentType(contentType);
  152. transactionId %= 127;
  153. byte[] wspPdu = wspPduPUSH(transactionId++, wspContentType, content.toByteArray());
  154. sendData(clientAddress, connectionlessPushPort, wspPdu, wspPdu.length);
  155.     }
  156.     /**
  157.      * A simplified "WBXML encoder".
  158.      * It handles only SI content type, and only href attribute within 
  159.      * SI content (others ignored).
  160.      * No well-formedness nor validity checks are performed during the encoding. 
  161.      *
  162.      * @param messageContent a <code>String</code> value
  163.      * @param content a <code>ByteArrayOutputStream</code> value
  164.      * @param contentType a <code>String</code> value
  165.      * @return a <code>String</code> value
  166.      */
  167.     private static String encodeContent(String messageContent, ByteArrayOutputStream content, 
  168. String contentType) throws Exception {
  169. if(contentType.startsWith("text/vnd.wap.si")) {
  170.     int i = messageContent.indexOf("href="http://");
  171.     if(i > 0) {
  172. try {
  173.     final byte[] bytes1 = { 0x0, 0x5, 0x4, 0x0, 0x45, (byte)0xc6, 0xc, 0x3 }; 
  174.     final byte[] bytes2 = { 0x0, 0x7, 0x1, 0x3 };
  175.     final byte[] bytes3 = { 0x0, 0x1, 0x1};
  176.     String href = messageContent.substring(i+13, messageContent.indexOf(""", i+14));
  177.     String message = messageContent.substring(messageContent.indexOf(">", i+15)+1,
  178.   messageContent.indexOf("</indication>", i+16));
  179.     content.write(bytes1);
  180.     content.write(href.getBytes());
  181.     content.write(bytes2);
  182.     content.write(message.trim().getBytes());
  183.     content.write(bytes3);
  184.     return "application/vnd.wap.sic";
  185. }
  186. catch (Exception e) {
  187.     content.reset();
  188. }
  189.     }
  190. }
  191. content.write(messageContent.getBytes());
  192. return contentType;
  193.     }
  194.     /**
  195.      * <code>encodeContentType</code> encodes mime type (cf. WSP specification WAP-203-WSP 4-May-2000)
  196.      *
  197.      * @param contentType a <code>String</code> value
  198.      * @return an <code>int</code> value
  199.      */
  200.     private static int encodeContentType(String contentType) throws Exception {
  201. contentType = contentType.toLowerCase();
  202. if(contentType.startsWith("text/vnd.wap.wml")) 
  203.     return 0x88; 
  204. else if(contentType.startsWith("text/vnd.wap.si"))
  205.     return 0xAD;
  206. else if(contentType.startsWith("text/vnd.wap.sl"))
  207.     return 0xAF;
  208. else if(contentType.startsWith("application/vnd.wap.wmlc")) 
  209.     return 0x94; 
  210. else if(contentType.startsWith("application/vnd.wap.sic"))
  211.     return 0xAE;
  212. else if(contentType.startsWith("applicavtion/vnd.wap.slc"))
  213.     return 0xB0;
  214. throw new Exception("unsupported content type:" + contentType);
  215.     }
  216.     // WSP PDU Type Assigments 
  217.     // Table 34 (page 94) in WSP specification WAP-203-WSP 4-May-2000
  218.     private static final int WSP_PUSH = 0x06;
  219.     /**
  220.      * Generate WSP PUSH PDU (note: only partial functionality provided)
  221.      *
  222.      * @param tid an <code>int</code> value
  223.      * @param contentType an <code>int</code> value
  224.      * @param content a <code>byte[]</code> value
  225.      * @return a <code>byte[]</code> value
  226.      * @exception Exception if an error occurs
  227.      */
  228.     private static byte[] wspPduPUSH(int tid, int contentType, byte[] content) throws Exception {
  229. ByteArrayOutputStream data = new ByteArrayOutputStream();
  230. data.write(tid);
  231. data.write(WSP_PUSH); 
  232. data.write(1); // contenttype size + headers size
  233. data.write(contentType);
  234. data.write(content);
  235. return data.toByteArray();
  236.     }
  237.     
  238.     /**
  239.      * <code>sendData</code> sends data to given address and port using UDP datagram socket
  240.      *
  241.      * @param addressStr a <code>String</code> value
  242.      * @param port an <code>int</code> value
  243.      * @param data a <code>byte[]</code> value
  244.      * @param dataSize an <code>int</code> value
  245.      * @return an <code>int</code> value
  246.      * @exception Exception if an error occurs
  247.      */
  248.     private static int sendData(String addressStr, int port, final byte[] data, int dataSize) 
  249. throws Exception {
  250. if(dataSize <= 0) return 0;
  251. InetAddress addr = InetAddress.getByName(addressStr);
  252. System.out.println("sendData addr = " + addr.getHostAddress() + "; port = " + port + 
  253.    "; data_size = " + dataSize);
  254. DatagramSocket s =  new DatagramSocket();
  255. // s.setSoTimeout(1000);
  256. DatagramPacket packet = new DatagramPacket(data, dataSize, addr, port);
  257. s.send(packet);
  258. int nBytes = packet.getLength();
  259. if(dataSize != nBytes) 
  260.     System.err.println("warning: not all bytes of a datagram are sent to socket!?");
  261. s.close();
  262. return nBytes;
  263.     }
  264. }