All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xsocket.connection.http.HttpUtils Maven / Gradle / Ivy

There is a newer version: 2.0-beta-1
Show newest version
/*
 *  Copyright (c) xsocket.org, 2006 - 2008. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
 * The latest copy of this software may be found on http://www.xsocket.org/
 */
package org.xsocket.connection.http;




import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.reflect.Method;
import java.nio.BufferUnderflowException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.xsocket.Execution;




/** 
 * A HTTP utility class
 *
 * @author [email protected]
 */
public final class HttpUtils {
	
	private static final Logger LOG = Logger.getLogger(HttpUtils.class.getName());
	
	@SuppressWarnings("unchecked")
	private static final Map bodyDataExecutionModeCache = newMapCache(25);
	
	@SuppressWarnings("unchecked")
	private static final Map bodyCompleteListenerExecutionModeCache = newMapCache(25);
	
	@SuppressWarnings("unchecked")
	private static final Map bodyCloseListenerExecutionModeCache = newMapCache(25);

	
	
	private static String versionInfo = null;
	
	
	
	private HttpUtils() { }
		
	
	
	/**
	 * validate, based on a leading int length field. The length field will be removed
	 * 
	 * @param connection     the connection
	 * @return the length 
	 * @throws IOException if an exception occurs
	 * @throws BufferUnderflowException if not enough data is available
	 */
	public static int validateSufficientDatasizeByIntLengthField(NonBlockingBodyDataSource stream) throws IOException, BufferUnderflowException {
		return validateSufficientDatasizeByIntLengthField(stream, true) ;
	}
		
	
	/**
	 * validate, based on a leading int length field, that enough data (getNumberOfAvailableBytes() >= length) is available. If not,
	 * an BufferUnderflowException will been thrown. 
	 * 
	 * @param connection         the connection
	 * @param removeLengthField  true, if length field should be removed
	 * @return the length 
	 * @throws IOException if an exception occurs
	 * @throws BufferUnderflowException if not enough data is available
	 */
	public static int validateSufficientDatasizeByIntLengthField(NonBlockingBodyDataSource stream, boolean removeLengthField) throws IOException, BufferUnderflowException {

		stream.resetToReadMark();
		stream.markReadPosition();
		
		// check if enough data is available
		int length = stream.readInt();
		if (stream.available() < length) {
			if (LOG.isLoggable(Level.FINE)) {
				LOG.fine("insufficient data. require " + length + " got "  + stream.available());
			}
			throw new BufferUnderflowException();
	
		} else { 
			// ...yes, remove mark
			if  (!removeLengthField) {
				stream.resetToReadMark();
			}
			stream.removeReadMark();
			return length;
		}
	}  

	
	
	/**
	 * returns the execution mode for the given body handler 
	 * 
	 * @param bodyHandler  the body handler 
	 * @return the execution mode
	 */
	static boolean isMutlithreaded(IBodyDataHandler bodyHandler) {
		Boolean isMutlithreaded = bodyDataExecutionModeCache.get(bodyHandler.getClass());
		
		if (isMutlithreaded == null) {
			int mode = IBodyDataHandler.DEFAULT_EXECUTION_MODE;
			
			Execution execution = bodyHandler.getClass().getAnnotation(Execution.class);
			if (execution != null) {
				mode = execution.value();
			}
			
			try {
				Method meth = bodyHandler.getClass().getMethod("onData", new Class[] { NonBlockingBodyDataSource.class });
				execution = meth.getAnnotation(Execution.class);
				if (execution != null) {
					mode = execution.value();
				}
				
			} catch (NoSuchMethodException nsme) {
				if (LOG.isLoggable(Level.FINE)) {
					LOG.fine("shouldn't occure because body handler has to have such a method " + nsme.toString());
				}
			}
			
			isMutlithreaded = (mode == Execution.MULTITHREADED);
			
			bodyDataExecutionModeCache.put(bodyHandler.getClass(), isMutlithreaded);
		}

		return isMutlithreaded;
	}

	
	
	/**
	 * returns the execution mode for the given body complete listener 
	 * 
	 * @param bodyHandler  the body handler 
	 * @return the execution mode
	 */
	static boolean isMutlithreaded(IBodyCompleteListener completeListener) {
		Boolean isMutlithreaded = bodyCompleteListenerExecutionModeCache.get(completeListener.getClass());
		 
		if (isMutlithreaded == null) {
			int mode = IBodyDataHandler.DEFAULT_EXECUTION_MODE;
			
			Execution execution = completeListener.getClass().getAnnotation(Execution.class);
			if (execution != null) {
				mode = execution.value();
			}
			
			try {
				Method meth = completeListener.getClass().getMethod("onComplete", new Class[] { });
				execution = meth.getAnnotation(Execution.class);
				if (execution != null) {
					mode = execution.value();
				}
				
			} catch (NoSuchMethodException nsme) {
				if (LOG.isLoggable(Level.FINE)) {
					LOG.fine("shouldn't occure because body handler has to have such a method " + nsme.toString());
				}
			}
			
			isMutlithreaded = (mode == Execution.MULTITHREADED);
			
			bodyCompleteListenerExecutionModeCache.put(completeListener.getClass(), isMutlithreaded);
		}

		return isMutlithreaded;
	}

	
	
	/**
	 * returns the execution mode for the given body complete listener 
	 * 
	 * @param bodyHandler  the body handler 
	 * @return the execution mode
	 */
	static boolean isMutlithreaded(IBodyCloseListener closeListener) {
		Boolean isMutlithreaded = bodyCloseListenerExecutionModeCache.get(closeListener.getClass());
		 
		if (isMutlithreaded == null) {
			int mode = IBodyDataHandler.DEFAULT_EXECUTION_MODE;
			
			Execution execution = closeListener.getClass().getAnnotation(Execution.class);
			if (execution != null) {
				mode = execution.value();
			}
			
			try {
				Method meth = closeListener.getClass().getMethod("onClose", new Class[] { });
				execution = meth.getAnnotation(Execution.class);
				if (execution != null) {
					mode = execution.value();
				}
				
			} catch (NoSuchMethodException nsme) {
				if (LOG.isLoggable(Level.FINE)) {
					LOG.fine("shouldn't occure because body handler has to have such a method " + nsme.toString());
				}
			}
			
			isMutlithreaded = (mode == Execution.MULTITHREADED);
			
			bodyCloseListenerExecutionModeCache.put(closeListener.getClass(), isMutlithreaded);
		}

		return isMutlithreaded;
	}


	
	/**
	 * get the version info
	 * 
	 * @return the version info
	 */
	public static String getVersionInfo() {
		
		if (versionInfo == null) {
			
			versionInfo = "";
			
			try {
				InputStreamReader isr = new InputStreamReader(HttpUtils.class.getResourceAsStream("/org/xsocket/connection/http/version.txt"));
				if (isr != null) {
					LineNumberReader lnr = new LineNumberReader(isr);
					String line = null;
					do {
						line = lnr.readLine();
						if (line != null) {
							if (line.startsWith("Implementation-Version=")) {
								versionInfo = line.substring("Implementation-Version=".length(), line.length()).trim();
							}
						}
					} while (line != null);
		
					lnr.close();
				}
			} catch (Exception ignore) { }
		} 
		
		return versionInfo;
	}
	
	
	
	
	/**
	 * create a new synchronized map cache
	 *  
	 * @param        the map key type
	 * @param        the map value type
	 * @param maxSize   the max cache size (oldest elements will be removed by exceeding this size)
	 * @return the ne wcache
	 */
	public static   Map newMapCache(int maxSize) {
		return Collections.synchronizedMap(new Cache(maxSize));
	}
	

	@SuppressWarnings("unchecked")
	private static final class Cache extends LinkedHashMap {
		
		private static final long serialVersionUID = 4513864504007457500L;
		
		private int maxSize = 0;
		
		Cache(int maxSize) {
			this.maxSize = maxSize;
		}
		

		@Override
		protected boolean removeEldestEntry(Entry eldest) {
			return size() > maxSize;
		}	
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy