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

org.nervousync.commons.http.entity.HttpEntity Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Licensed to the Nervousync Studio (NSYC) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.nervousync.commons.http.entity;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import org.nervousync.enumerations.web.HttpMethodOption;
import org.nervousync.utils.FileUtils;
import org.nervousync.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.nervousync.commons.core.Globals;

/**
 * Http Entity
 * @author Steven Wee	[email protected]
 * @version $Revision: 1.0 $ $Date: Jan 2, 2018 2:05:04 PM $
 */
public final class HttpEntity {

	//	Boundary string used characters
	private static final char[] BOUNDARY_CHAR_ARRAY = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
	
	//	TEXT content type
	private static final String TEXT_CONTENT_TYPE = "text/plain";
	//	Encoded content type
	private static final String ENCODED_CONTENT_TYPE = "application/x-www-form-urlencoded";
	//	Multipart content type
	private static final String MULTIPART_CONTENT_TYPE = "multipart/form-data";
	//	Mixed content type
	private static final String MIXED_CONTENT_TYPE = "multipart/mixed";
	//	Binary content type
	private static final String BINARY_CONTENT_TYPE = "application/octet-stream";
	//	Content disposition
	private static final String CONTENT_DISPOSITION = "form-data";
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	
	/**
	 * Boundary value, generated by system
	 */
	private String boundary = null;
	/**
	 * List of entity info
	 * @see HttpEntity.EntityInfo
	 */
	private final List entityList;
	/**
	 * Is multipart request
	 */
	private boolean multipart = Boolean.FALSE;
	/**
	 * Is mixed parameters, means include form field and upload files
	 */
	private boolean mixed = Boolean.FALSE;
	
	/**
	 * Constructor
	 */
	private HttpEntity() {
		this.entityList = new ArrayList<>();
	}
	
	/**
	 * Generate a new HttpEntity
	 * @return		HttpEntity instance
	 */
	public static HttpEntity newInstance() {
		return new HttpEntity();
	}
	
	/**
	 * Add text parameter
	 * @param name		Parameter name
	 * @param value		Parameter value
	 */
	public void addTextEntity(String name, String value) {
		this.entityList.add(EntityInfo.generateTextEntity(name, value));
	}

	/**
	 * Add binary parameter
	 * @param name		Parameter name
	 * @param value		The upload file path
	 */
	public void addBinaryEntity(String name, String value) {
		try {
			this.entityList.add(EntityInfo.generateBinaryEntity(name, value));
			if (this.boundary == null) {
				this.boundary = this.generateBoundary();
			}
		} catch (FileNotFoundException e) {
			this.logger.error("Upload file not found! ");
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Stack message: ", e);
			}
		}
	}
	
	/**
	 * Generate content type value
	 * @param charset			Charset encoding
	 * @param methodOption		Http method type
	 * @see HttpMethodOption
	 * @return					Content type
	 * @throws UnsupportedEncodingException		Charset encoding is not supported
	 */
	public String generateContentType(String charset, HttpMethodOption methodOption) 
			throws UnsupportedEncodingException {
		if (charset == null || charset.trim().length() == 0) {
			charset = "ISO-8859-1";
		}
		String contentType;
		switch (methodOption) {
		case POST: case PUT:
			this.checkType();
			if (this.multipart) {
				if (this.mixed) {
					contentType = MIXED_CONTENT_TYPE + ";boundary=" + this.boundary;
				} else {
					contentType = MULTIPART_CONTENT_TYPE + ";boundary=" + this.boundary;
				}
			} else {
				contentType = ENCODED_CONTENT_TYPE + ";charset=" + charset;
			}
			break;
		case GET: case TRACE: case HEAD: case DELETE: case OPTIONS:
			contentType = TEXT_CONTENT_TYPE + ";charset=" + charset;
			break;
		default:
			throw new UnsupportedEncodingException("Unknown Request Method");
		}
		
		return contentType;
	}
	
	/**
	 * Write data to output stream
	 * @param charset			Charset encoding
	 * @param outputStream		Target output stream
	 * @throws IOException		Write data to output stream error
	 */
	public void writeData(String charset, OutputStream outputStream) throws IOException {
		if (this.entityList.isEmpty()) {
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Entity list is empty");
			}
			return;
		}
		
		if (charset == null || charset.trim().length() == 0) {
			charset = Globals.DEFAULT_ENCODING;
		}
		this.checkType();
		if (this.multipart) {
			StringBuilder stringBuilder;
			for (EntityInfo entityInfo : this.entityList) {
				stringBuilder = new StringBuilder();
				stringBuilder.append("--").append(this.boundary).append(FileUtils.CRLF);
				stringBuilder.append("Content-Disposition:" + CONTENT_DISPOSITION + ";");
				stringBuilder.append("name=\"").append(entityInfo.getEntityName()).append("\"");
				String value = entityInfo.getEntityValue();
				if (entityInfo.isBinary()) {
					stringBuilder.append(";filename=\"").append(StringUtils.getFilename(value)).append("\"");
					stringBuilder.append(FileUtils.CRLF);
					stringBuilder.append("Content-Type:" + BINARY_CONTENT_TYPE);
				}
				stringBuilder.append(FileUtils.CRLF);
				stringBuilder.append(FileUtils.CRLF);
				
				outputStream.write(stringBuilder.toString().getBytes(Globals.DEFAULT_ENCODING));
				if (entityInfo.isBinary()) {
					outputStream.write(FileUtils.readFileBytes(value));
				} else {
					outputStream.write(value.getBytes(charset));
				}
				outputStream.write(FileUtils.CRLF.getBytes(charset));
			}
			outputStream.write(("--" + this.boundary).getBytes(charset));
		} else {
			StringBuilder stringBuilder = new StringBuilder();
			for (EntityInfo entityInfo : this.entityList) {
				stringBuilder.append("&");
				stringBuilder.append(URLEncoder.encode(entityInfo.getEntityName(), charset));
				stringBuilder.append("=");
				stringBuilder.append(URLEncoder.encode(entityInfo.getEntityValue(), charset));
			}
			
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Write data: {}", stringBuilder);
			}
			outputStream.write(stringBuilder.substring(1).getBytes(charset));
		}
	}
	
	/**
	 * Setting value for field multipart and mixed
	 */
	private void checkType() {
		int formItemCount = 0;
		int fileItemCount = 0;
		for (EntityInfo entityInfo : this.entityList) {
			if (entityInfo.isBinary()) {
				fileItemCount++;
			} else {
				formItemCount++;
			}
		}
		
		if (fileItemCount > 0) {
			this.multipart = true;
			if (formItemCount > 0) {
				this.mixed = true;
			}
		}
	}
	
	/**
	 * Generate boundary value
	 * @return  Generated boundary
	 */
	private String generateBoundary() {
		StringBuilder stringBuilder = new StringBuilder();
		final Random random = new Random();
		for (int i = 0 ; i < 32 ; i++) {
			stringBuilder.append(BOUNDARY_CHAR_ARRAY[random.nextInt(BOUNDARY_CHAR_ARRAY.length)]);
		}
		return stringBuilder.toString();
	}
	
	/**
	 * Entity information
	 * @author Steven Wee	[email protected]
	 * @version $Revision: 1.0 $ $Date: Jul 2, 2018 $
	 */
	private static final class EntityInfo {
		
		/**
		 * Entity is binary
		 */
		private final boolean binary;
		/**
		 * Entity name
		 */
		private final String entityName;
		/**
		 * Entity value
		 */
		private final String entityValue;
		
		private EntityInfo(boolean binary, String name, String value) {
			this.binary = binary;
			this.entityName = name;
			this.entityValue = value;
		}
		
		public static EntityInfo generateTextEntity(String name, String value) {
			return new EntityInfo(Boolean.FALSE, name, value);
		}

		public static EntityInfo generateBinaryEntity(String name, String value) 
				throws FileNotFoundException {
			if (FileUtils.isExists(value)) {
				return new EntityInfo(true, name, value);
			}
			throw new FileNotFoundException("File not exists");
		}
		
		/**
		 * @return the binary
		 */
		public boolean isBinary() {
			return binary;
		}

		/**
		 * @return the entityName
		 */
		public String getEntityName() {
			return entityName;
		}

		/**
		 * @return the entityValue
		 */
		public String getEntityValue() {
			return entityValue;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy