PPG.java
资源名称:WAPpush.zip [点击查看]
上传用户:weisa_1
上传日期:2007-10-14
资源大小:287k
文件大小:10k
源码类别:
手机WAP编程
开发平台:
Java
- package push;
- import javax.servlet.*;
- import javax.servlet.http.*;
- import java.net.*;
- import java.io.*;
- import java.util.StringTokenizer;
- /**
- * <code>PPG</code> class implements some push proxy gateway (PPG) functionality for
- * the purposes of this example only. This simple PPG is targeted to be used in
- * conjunction with WAP toolkit, and IPv4 type client addressing.
- *
- */
- public final class PPG extends HttpServlet {
- /* xml version */
- private final static String XML_VERSION = "<?xml version="1.0"?>";
- /* Push Access Protocol (PAP) document type */
- private final static String PAP_DOCTYPE =
- "<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 1.0//EN" "http://www.wapforum.org/DTD/pap_1.0.dtd" >";
- /* content type of the push request multipart body */
- private final static String CONTENT_TYPE =
- "multipart/related; boundary=multipart-boundary; type="application/xml"";
- /* WAP Push connection less service (client side). The registered port number. */
- private static final int connectionlessPushPort = 2948;
- private static int transactionId = 0;
- /**
- * <code>doPost</code>
- *
- * @param request a <code>HttpServletRequest</code> value
- * @param response a <code>HttpServletResponse</code> value
- * @exception ServletException if an error occurs
- * @exception IOException if an error occurs
- */
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String clientAddress = null;
- String pushId = null;
- int resultCode = 1001; // accepted for processing
- try {
- // first, check the content type which should be "multipart/related"
- String contentType = request.getHeader("content-type");
- StringTokenizer st = new StringTokenizer(contentType, ";");
- String token = st.nextToken();
- String boundary = null;
- if(!token.equalsIgnoreCase("multipart/related")) throw new Exception("wrong content type");
- // finds the boundary string
- while(st.hasMoreTokens()) {
- token = st.nextToken().trim();
- if(token.startsWith("boundary=")) {
- boundary = token.substring(9);
- break;
- }
- }
- if(boundary == null) throw new Exception("no multipart boundary");
- boundary = "--" + boundary;
- String endBoundary = boundary + "--";
- StringBuffer messageContent = new StringBuffer();
- BufferedReader in = request.getReader();
- String line;
- int i=0;
- boolean startContent = false;
- System.out.println("boundary=" + boundary);
- // extract message content part
- while((line = in.readLine()) != null) {
- if(line.equals(boundary))
- ++i;
- else if(line.equals(endBoundary))
- break;
- if(i == 1) { // PAP control entity
- int j = line.indexOf("address-value=");
- if(j >= 0) {
- clientAddress = line.substring(j+15, line.indexOf('"', j+17));
- }
- j = line.indexOf("push-id=");
- if(j >= 0) {
- pushId = line.substring(j+9, line.indexOf('"', j+11));
- }
- }
- else if(i == 2) { // PAP content entity
- if(startContent)
- messageContent.append(line);
- else if(line.trim().equals("")) // end of headers
- startContent = true;
- else if(line.toLowerCase().startsWith("content-type:"))
- contentType = line.substring(13).trim();
- }
- }
- if((i = clientAddress.indexOf("/TYPE=IPv4")) == -1) {
- resultCode = 2002; // address error
- throw new Exception("This PPG can handle only IPv4 type addresses");
- }
- clientAddress = clientAddress.substring(clientAddress.indexOf("WAPPUSH=")+8, i);
- if(clientAddress == null) {
- resultCode = 2002; // address error
- throw new Exception("Client address is not known");
- }
- System.out.println("clientAddress: " + clientAddress);
- System.out.println("pushId: " + pushId);
- System.out.println("message content: " + messageContent);
- unitPushRequest(clientAddress, messageContent.toString().trim(), contentType);
- }
- catch (Exception e) {
- System.err.println(e);
- if(resultCode < 2000) resultCode = 2000; // bad message
- }
- // start writing the result
- response.setStatus(202); // accepted
- response.setContentType("application/xml");
- PrintWriter out = response.getWriter();
- out.println(XML_VERSION);
- out.println(PAP_DOCTYPE);
- out.println("<pap product-name="MobileZoo PPG">");
- out.println(" <push-response push-id="" + pushId + "">");
- out.println(" <response result");
- out.println(" code="" + resultCode + """);
- out.println(" desc="" + resultCodeDesc(resultCode) + "">");
- out.println(" </response-result>");
- out.println(" </push-response>");
- out.println("</pap>");
- }
- /**
- * Returns description of a PAP result response code
- *
- * @param code an <code>int</code> value
- * @return a <code>String</code> value
- */
- private static String resultCodeDesc(int code) {
- switch(code) {
- case 1001:
- return "Accepted for Processing";
- case 2000:
- return "Bad Request";
- case 2002:
- return "Address Error";
- }
- return "Unknown result code";
- }
- /**
- * <code>unitPushRequest</code> generates a connectionless mode Push request
- *
- * @param clientAddress a <code>String</code> value
- * @param messageContent a <code>String</code> value
- * @param contentType a <code>String</code> value
- * @exception Exception if an error occurs
- */
- private void unitPushRequest(String clientAddress, String messageContent,
- String contentType)
- throws Exception {
- ByteArrayOutputStream content = new ByteArrayOutputStream();
- contentType = encodeContent(messageContent, content, contentType);
- int wspContentType = encodeContentType(contentType);
- transactionId %= 127;
- byte[] wspPdu = wspPduPUSH(transactionId++, wspContentType, content.toByteArray());
- sendData(clientAddress, connectionlessPushPort, wspPdu, wspPdu.length);
- }
- /**
- * A simplified "WBXML encoder".
- * It handles only SI content type, and only href attribute within
- * SI content (others ignored).
- * No well-formedness nor validity checks are performed during the encoding.
- *
- * @param messageContent a <code>String</code> value
- * @param content a <code>ByteArrayOutputStream</code> value
- * @param contentType a <code>String</code> value
- * @return a <code>String</code> value
- */
- private static String encodeContent(String messageContent, ByteArrayOutputStream content,
- String contentType) throws Exception {
- if(contentType.startsWith("text/vnd.wap.si")) {
- int i = messageContent.indexOf("href="http://");
- if(i > 0) {
- try {
- final byte[] bytes1 = { 0x0, 0x5, 0x4, 0x0, 0x45, (byte)0xc6, 0xc, 0x3 };
- final byte[] bytes2 = { 0x0, 0x7, 0x1, 0x3 };
- final byte[] bytes3 = { 0x0, 0x1, 0x1};
- String href = messageContent.substring(i+13, messageContent.indexOf(""", i+14));
- String message = messageContent.substring(messageContent.indexOf(">", i+15)+1,
- messageContent.indexOf("</indication>", i+16));
- content.write(bytes1);
- content.write(href.getBytes());
- content.write(bytes2);
- content.write(message.trim().getBytes());
- content.write(bytes3);
- return "application/vnd.wap.sic";
- }
- catch (Exception e) {
- content.reset();
- }
- }
- }
- content.write(messageContent.getBytes());
- return contentType;
- }
- /**
- * <code>encodeContentType</code> encodes mime type (cf. WSP specification WAP-203-WSP 4-May-2000)
- *
- * @param contentType a <code>String</code> value
- * @return an <code>int</code> value
- */
- private static int encodeContentType(String contentType) throws Exception {
- contentType = contentType.toLowerCase();
- if(contentType.startsWith("text/vnd.wap.wml"))
- return 0x88;
- else if(contentType.startsWith("text/vnd.wap.si"))
- return 0xAD;
- else if(contentType.startsWith("text/vnd.wap.sl"))
- return 0xAF;
- else if(contentType.startsWith("application/vnd.wap.wmlc"))
- return 0x94;
- else if(contentType.startsWith("application/vnd.wap.sic"))
- return 0xAE;
- else if(contentType.startsWith("applicavtion/vnd.wap.slc"))
- return 0xB0;
- throw new Exception("unsupported content type:" + contentType);
- }
- // WSP PDU Type Assigments
- // Table 34 (page 94) in WSP specification WAP-203-WSP 4-May-2000
- private static final int WSP_PUSH = 0x06;
- /**
- * Generate WSP PUSH PDU (note: only partial functionality provided)
- *
- * @param tid an <code>int</code> value
- * @param contentType an <code>int</code> value
- * @param content a <code>byte[]</code> value
- * @return a <code>byte[]</code> value
- * @exception Exception if an error occurs
- */
- private static byte[] wspPduPUSH(int tid, int contentType, byte[] content) throws Exception {
- ByteArrayOutputStream data = new ByteArrayOutputStream();
- data.write(tid);
- data.write(WSP_PUSH);
- data.write(1); // contenttype size + headers size
- data.write(contentType);
- data.write(content);
- return data.toByteArray();
- }
- /**
- * <code>sendData</code> sends data to given address and port using UDP datagram socket
- *
- * @param addressStr a <code>String</code> value
- * @param port an <code>int</code> value
- * @param data a <code>byte[]</code> value
- * @param dataSize an <code>int</code> value
- * @return an <code>int</code> value
- * @exception Exception if an error occurs
- */
- private static int sendData(String addressStr, int port, final byte[] data, int dataSize)
- throws Exception {
- if(dataSize <= 0) return 0;
- InetAddress addr = InetAddress.getByName(addressStr);
- System.out.println("sendData addr = " + addr.getHostAddress() + "; port = " + port +
- "; data_size = " + dataSize);
- DatagramSocket s = new DatagramSocket();
- // s.setSoTimeout(1000);
- DatagramPacket packet = new DatagramPacket(data, dataSize, addr, port);
- s.send(packet);
- int nBytes = packet.getLength();
- if(dataSize != nBytes)
- System.err.println("warning: not all bytes of a datagram are sent to socket!?");
- s.close();
- return nBytes;
- }
- }