📄 clusterablesync4jservlet.java
字号:
/** * Copyright (C) 2003-2004 Funambol * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package sync4j.transport.http.server;import java.io.*;import java.net.InetAddress;import java.net.UnknownHostException;import java.util.logging.Logger;import java.util.logging.Level;import javax.servlet.*;import javax.servlet.http.*;import sync4j.framework.core.*;import sync4j.framework.tools.Base64;import sync4j.framework.server.*;import sync4j.framework.tools.WBXMLTools;import sync4j.framework.transport.http.SyncHolder;import sync4j.framework.protocol.ProtocolException;import org.apache.commons.lang.StringUtils;import sync4j.transport.http.server.Constants;import org.jibx.runtime.*;import org.jibx.runtime.impl.*;/** * Receives the HTTP request and does session management. * * <b>Session Management</b> * <p> * If the url contains a parameter {PARAM_SESSION_ID}={SESSION_ID}, the session * id is used to lookup in the <i>handlerCache</i> if there is already a * <i>SyncHolder</i> associated with it; the found handler is then used to process * the incoming request. Otherwise, (either if the session parameter is not * specified or no cached handler is found), a new session id is created and a * new <i>SyncHolder</i> object is instantiated and stored in the cache.<br> * The session id is created as followed: * <p> * <ol> * <li> the first four bytes contains the IP address of the remote client * <li> a dash ('-') is appended * <li> the creation timestamp is appended * <li> the resulting string is encoded base 64 * </ol> * Note that no session expiration is handled by this class. That is delegated * to the <i>SyncHandler</i> object. * * @author Stefano Fornari * * @version $Id: ClusterableSync4jServlet.java,v 1.6 2004/05/20 16:21:06 luigiafassina Exp $ * */public final class ClusterableSync4jServletextends HttpServletimplements Constants { // ------------------------------------------------------------ Private data public static final String PARAM_SERVER_URI = "server-uri"; private static String serverUri = null; private String jndiAddress = DEFAULT_JNDI_ADDRESS; private RemoteHolderCache holderCache = null; private Logger log = Logger.getLogger(LOG_NAME); // ---------------------------------------------------------- Public methods public void init() throws ServletException { String value; ServletConfig config = getServletConfig(); value = config.getInitParameter(PARAM_CHANNEL_PROPERTIES); if (StringUtils.isEmpty(value)) { String msg = "The servlet configuration parameter " + PARAM_CHANNEL_PROPERTIES + " cannot be empty (" + value + ")" ; log.severe(msg); throw new ServletException(msg); } value = config.getInitParameter(PARAM_SESSION_TTL); if (!StringUtils.isEmpty(value)) { try { Long.parseLong(value); } catch (NumberFormatException e) { String msg = "The servlet configuration parameter " + PARAM_SESSION_TTL + " is not an integer number (" + value + ")" ; log.severe(msg); throw new ServletException(msg); } } value = config.getInitParameter(PARAM_JNDI_ADDRESS); if (StringUtils.isEmpty(value)) { String msg = "Missing optional parameter " + PARAM_JNDI_ADDRESS + ", default value (" + jndiAddress + ") used." ; log.warning(msg); } else { jndiAddress = value; } holderCache = new RemoteHolderCache(config); value = config.getInitParameter(PARAM_SERVER_URI); if (StringUtils.isEmpty(value)) { String msg = "The servlet configuration parameter " + PARAM_SERVER_URI + " cannot be empty (" + value + ")" ; log(msg); throw new ServletException(msg); } serverUri = value; } public void doPost( final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { final String contentType = request.getContentType().split(";")[0]; final int contentLength = request.getContentLength(); if (log.isLoggable(Level.FINE)) { log.fine("contentType: " + contentType); log.fine("contentLength: " + contentLength); } if (contentLength < 1) { throw new Error("Content length < 1 (" + contentLength + ")"); } byte[] requestData = new byte[contentLength]; InputStream in = request.getInputStream(); int n = 0; int bytesRead = 0; try { do { n = in.read(requestData, bytesRead, requestData.length - bytesRead); if (n > 0) { bytesRead += n; } } while (n != -1); } catch (IOException ex) { handleError(request, response, "Error reading the request", ex); return; } finally { try { if (in != null) { in.close(); } } catch (Exception ex) { handleError(request, response, ex.getClass().getName(), ex); return; } in = null; } if (bytesRead != contentLength) { handleError(request, response, "bytesRead != contentLength", null); return; } // // If the session id is not specified in the URL, a new remote object // will be created. Otherwise the session id specifies which remote // object shall handles the request. // RemoteEJBSyncHolder holder = null; try { holder = createHolder(request); } catch (Exception e) { handleError(request, response, "Error creating SyncBean", e); return; } SyncResponse resp = null; try { resp = holder.processMessage(requestData, contentType); } catch (Exception e) { Throwable cause = e.getCause(); if ( (cause != null) && ( (cause instanceof ProtocolException) || (cause instanceof Sync4jException ) ) ) { handleError(request, response, "Protocol error", cause); return; } else { throw new ServletException(e); } } finally { // // Now we can store the handler into the distributed cache. Note // that when the holder is put in the cache a serialized copy is // actually stored, not the simple local reference. // if (holder.isNew()) { holderCache.put(holder); } } // // Set the <RespURI> tag to the server uri plus the session id parameter // SyncML responseMessage = resp.getMessage(); responseMessage.getSyncHdr().setRespURI( serverUri + request.getContextPath() + request.getServletPath() + '?' + PARAM_SESSION_ID + '=' + holder.getSessionId() ); OutputStream out = null; try { out = response.getOutputStream(); response.setContentType(resp.getMimeType()); byte[] buf = null; if (sync4j.framework.core.Constants.MIMETYPE_SYNCML_XML.equals(resp.getMimeType())) { if (log.isLoggable(Level.FINE)) { log.fine("Sending back XML"); } try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); IBindingFactory f = BindingDirectory.getFactory(SyncML.class); IMarshallingContext c = f.createMarshallingContext(); c.setIndent(0); c.marshalDocument(responseMessage, "UTF-8", null, bout); buf = bout.toByteArray(); } catch(Exception e) { e.printStackTrace(); } response.setContentLength(buf.length); out.write(buf); } else if (sync4j.framework.core.Constants.MIMETYPE_SYNCML_WBXML.equals(resp.getMimeType())){ if (log.isLoggable(Level.FINE)) { log.fine("Sending back WBXML"); } try { buf = WBXMLTools.toWBXML(responseMessage); } catch (Sync4jException e) { handleError(request, response, "Encoding error", e); } response.setContentLength(buf.length); out.write(buf); } out.flush(); } finally { if (log.isLoggable(Level.FINE)) { log.fine("Finally"); } if (out != null) out.close(); } // // If the message completed the SyncML communication, the holder // must be closed and discarded. // if (resp.isCompleted()) { releaseHolder(holder); } } public void doGet( final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { log.info("holderCache: " + holderCache); super.doGet(request, response); } // --------------------------------------------------------- Private methods /** * Factory method for <i>SyncHolder</i> objects. If the session id is * passed as a CGI parameter, it is transformed in a EJB handle. If the * handle is not valid, it is considered expired. If the session id is not * specified, a new EJB is created * * @param request the associated HTTP request object * * @return a new <i>SyncHolder</i> * */ private RemoteEJBSyncHolder createHolder(HttpServletRequest request) throws Exception { String sessionId = request.getParameter(PARAM_SESSION_ID); RemoteEJBSyncHolder holder = null; if (log.isLoggable(Level.FINE)) { log.fine("holderCache: " + holderCache); } if (!StringUtils.isEmpty(sessionId)) { holder = (RemoteEJBSyncHolder)holderCache.get(sessionId); } if (holder == null) { holder = new RemoteEJBSyncHolder(true); holder.setSessionId(createSessionId(request)); holder.setJndiAddress(jndiAddress); } return holder; } /** * Closes the given <i>SyncHolder</i> and removes it from the cache. * * @param holder the holder to releases */ private void releaseHolder(SyncHolder holder) { try { holder.close(); } catch (Exception e) { log.severe(e.getMessage()); log.throwing(getClass().getName(), "releaseHolder", e.getCause()); } holderCache.remove(holder.getSessionId()); } /** * Handles errors conditions returning an appropriate content to the client. * * @param request the request object * @param response the response object * @msg a desctiptive message * @t a throwable object * */ private void handleError(final HttpServletRequest request, final HttpServletResponse response, String msg, final Throwable t) { if (msg == null) { msg = ""; } if (t == null) { log.severe(msg); } else { log.severe(msg); log.throwing(getClass().getName(), "handleError", t); } try { response.sendError(response.SC_BAD_REQUEST, msg); } catch (IOException e) { log.severe(e.getMessage()); log.throwing(getClass().getName(), "handleError", e); } } /** * Creates the session id (see the class description for details). * * @param request the HTTP request object * * @return a newly created session id */ private String createSessionId(HttpServletRequest request) { String clientIP = request.getRemoteAddr() ; long timestamp = System.currentTimeMillis(); StringBuffer sb = new StringBuffer(); byte[] ip = null; try { ip = InetAddress.getByName(clientIP).getAddress(); } catch (UnknownHostException e) { ip = new byte[] {0, 0, 0, 0}; } sb.append(ip).append('-').append(timestamp); String stringSessionId = new String(Base64.encode(sb.toString().getBytes())); // // strips out tailing '=' // int i = stringSessionId.lastIndexOf('='); return ((i>0) ? stringSessionId.substring(0, i-1) : stringSessionId); } /** * The same as <i>handleError(reqest, response, msg, t, null)</i>. * * @param request the request object * @param response the response object * @msg a desctiptive message * @t a throwable object * */ private void handleError(final HttpServletRequest request, final HttpServletResponse response, final String msg) { this.handleError(request, response, msg, null); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -