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

gu.sql2java.BaseColumnStore Maven / Gradle / Ivy

There is a newer version: 5.2.0
Show newest version
package gu.sql2java;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.ByteBuffer;
import java.util.Map;

import com.google.common.base.Strings;
import com.google.common.base.Throwables;

import gu.sql2java.exception.ObjectRetrievalException;
import gu.sql2java.store.BaseURLStore;
import gu.sql2java.store.ConditionChecks;
import gu.sql2java.store.DataNotFoundException;

import static com.google.common.base.URLParseChecks.checkURLParse;
import static com.google.common.base.Preconditions.*;

import static gu.sql2java.store.BinaryUtils.*;
import static gu.sql2java.store.ConditionChecks.checkNotNull;
import static gu.sql2java.store.ConditionChecks.checkTrue;

public class BaseColumnStore extends BaseURLStore {

	private final Handler handler = new Handler();

	protected final  String tablename;

	protected final String storeColumn;

	protected final TableManager manager;

	protected final RowMetaData metaData;

	protected final Class storeColumnType;

	protected final String protocol;

	protected final int extensionId;

	protected final int mimeId;

	protected final static String PKS = "PKS";
	
	public BaseColumnStore(String tablename,String storeColumn, String extensionColumn, String mimeColumn) {
		this.tablename = tablename;
		this.storeColumn = storeColumn;
		this.manager = Managers.managerOf(tablename);
		this.metaData = RowMetaData.getMetaData(tablename);
		this.extensionId = metaData.columnIDOf(extensionColumn);
		this.mimeId = metaData.columnIDOf(mimeColumn);
		this.storeColumnType = metaData.columnTypeOf(storeColumn);
		checkArgument(storeColumnType != null, "INVALID column %s", storeColumn);
		checkArgument(byte[].class.equals(storeColumnType) || ByteBuffer.class.isAssignableFrom(storeColumnType),
				"INVALID column type of %s,byte[] or java.nio.ByteBuffer required",storeColumn);
		checkArgument(extensionColumn == null || String.class.equals(metaData.columnTypeOf(this.extensionId)),
				"INVALID extensionColumn %s",extensionColumn);
		checkArgument(mimeColumn == null || String.class.equals(metaData.columnTypeOf(this.mimeId)),
				"INVALID mimeColumn %s",mimeColumn);
		this.protocol = tablename.replaceAll("_", "-");
	}

	@Override
	public String getProtocol() {
		return protocol;
	}
	protected Object[] primaryKeysOf(String md5, String extension){
		Map p = additionalParams.get();
		checkState(p != null && p.containsKey(PKS), "NOT PK defined");
		Object v = p.get(PKS);
		checkState(v instanceof Object[],"INVALID PK type,Object[] required");
		return (Object[])v;
	}
	protected final String pathOf(String suffix, Object... primaryKeys){
		StringBuffer buffer = new StringBuffer(storeColumn);
		for(int i=0; i < primaryKeys.length;++i){
			buffer.append("/").append(primaryKeys[i]);
		}
		if(!Strings.isNullOrEmpty(suffix)){
			buffer.append('.').append(suffix);
		}
		return buffer.toString();
	}
	protected final URL makeURL(String suffix, Object... primaryKeys){
		try {
			return new URL(getProtocol(),null,-1,pathOf(suffix,primaryKeys));
		} catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * 从数据库记录中获取当前数据的扩展名
	 * @param bean 数据库记录(不为{@code null})
	 * @return 扩展名
	 */
	protected String getExtension(BaseBean bean) {
		return bean.getValue(extensionId);
	}

	/**
	 * 从数据库记录中获取当前数据的MIME类型
	 * @param bean 数据库记录(不为{@code null})
	 * @return MIME类型
	 */
	protected String getMime(BaseBean bean) {
		String mime = bean.getValue(mimeId);
		String extension = bean.getValue(extensionId);
		if(mime != null){
			return mime;
		} else if( extension != null){
			mime = URLConnection.guessContentTypeFromName("." + extension);
			if(mime != null){
				return mime;
			}
		}
		return guessContentType(bean);
	}

	private String guessContentType(BaseBean bean) {
		try {
			if(bean == null){
				return null;
			}
			byte[] data = getBytes(bean.getValue(storeColumn));
			if(data == null){
				return null;
			}
			ByteArrayInputStream is = new ByteArrayInputStream(data);
			return URLConnection.guessContentTypeFromStream(is);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	protected final void fillStoreBean(BaseBean bean, byte[] binary, String extension) {
		if(ByteBuffer.class.equals(storeColumnType)){
			bean.setValue(storeColumn, ByteBuffer.wrap(binary));
		}else{
			bean.setValue(storeColumn, binary);	
		}
		if(extensionId >= 0){
			bean.setValue(extensionId, extension);
		}
		if(mimeId >= 0){
			bean.setValue(mimeId, getMime(bean));
		}
	}

	
	@Override
	protected URL doStore(byte[] binary, String md5, String extension, boolean overwrite, boolean makeURLOnly) throws IOException {
		try {
			Object[] pks = primaryKeysOf(md5,extension);
			BaseBean bean = manager.loadByPrimaryKeyChecked(pks);
			fillStoreBean(bean, binary, extension);
			if(!makeURLOnly){
				manager.save(bean);
			}
			return makeURL(extension, pks);
		} catch (Exception e) {
			Throwables.throwIfInstanceOf(e, IOException.class);
			throw new IOException(e);
		} finally{
			additionalParams.remove();
		}
	}

	@Override
	protected URL doFind(String md5) {
		return null;
	}

	@Override
	protected boolean doExists(URL storedURL) {
		DatabaseURLConnection connection = new DatabaseURLConnection(storedURL).parse();
		BaseBean found = manager.loadByPrimaryKey(connection.primaryKeys);
		return found != null && found.getValue(storeColumn) != null;
	}

	@Override
	protected boolean doDelete(URL storedURL) throws IOException {
		try {
			DatabaseURLConnection bean = new DatabaseURLConnection(storedURL).parse();
			return manager.deleteByPrimaryKey(bean.primaryKeys) == 1;
		} catch (Exception e) {
			Throwables.throwIfInstanceOf(e, IOException.class);
			throw new IOException(e);
		}
	}

	@Override
	protected URLStreamHandler doGetURLStreamHandler() {
		return handler;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + extensionId;
		result = prime * result + mimeId;
		result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
		result = prime * result + ((storeColumn == null) ? 0 : storeColumn.hashCode());
		result = prime * result + ((tablename == null) ? 0 : tablename.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (!(obj instanceof BaseColumnStore))
			return false;
		BaseColumnStore other = (BaseColumnStore) obj;
		if (extensionId != other.extensionId)
			return false;
		if (mimeId != other.mimeId)
			return false;
		if (protocol == null) {
			if (other.protocol != null)
				return false;
		} else if (!protocol.equals(other.protocol))
			return false;
		if (storeColumn == null) {
			if (other.storeColumn != null)
				return false;
		} else if (!storeColumn.equals(other.storeColumn))
			return false;
		if (tablename == null) {
			if (other.tablename != null)
				return false;
		} else if (!tablename.equals(other.tablename))
			return false;
		return true;
	}

	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append(getClass().getSimpleName() + " [tablename=");
		builder.append(tablename);
		builder.append(", storeColumn=");
		builder.append(storeColumn);
		builder.append(", extensionColumn=");
		builder.append(metaData.columnNameOf(extensionId));
		builder.append(", mimeColumn=");
		builder.append(metaData.columnNameOf(mimeId));
		builder.append(", protocol=");
		builder.append(protocol);
		builder.append("]");
		return builder.toString();
	}

	protected class Handler extends URLStreamHandler{
	
		@Override
		protected URLConnection openConnection(URL u) throws IOException {
				return new DatabaseURLConnection(u);	
		}
		
	}
	protected class DatabaseURLConnection extends URLConnection{
		
		Object[] primaryKeys;

		protected DatabaseURLConnection(URL url) {
			super(url);
		}
		/**
		 * 解析URL为数据访问信息
* 要求的URL格式 ${tablename}://${storeColumn}/${pk}...[/${pkN}] * @return * @throws URLParseException */ DatabaseURLConnection parse() throws URLParseException{ checkTrue(getProtocol().equals(getURL().getProtocol()), URLParseException.class, "INVALID protocol ,%s reqired",getProtocol()); String[] components = url.getPath().split("/"); try { checkTrue(components[0].equals(storeColumn), URLParseException.class, "INVALID URL,the URL's path be reqired to start with '%s'",storeColumn); checkTrue(components.length == metaData.primaryKeyCount+1, URLParseException.class, "MISMATCH path components acount, %s required",metaData.primaryKeyCount+1); String last = components[components.length-1]; int lastDot = last.lastIndexOf("."); if(lastDot >= 0){ // remove suffix if exists components[components.length-1] = last.substring(0, lastDot); } primaryKeys = new Object[metaData.primaryKeyTypes.length]; for(int i = 0; i < metaData.primaryKeyTypes.length;++i){ primaryKeys[i] = valueOf(components[i+1], metaData.primaryKeyTypes[i]); } } catch (IndexOutOfBoundsException e) { throw new URLParseException("URL's path lack the necessary components /${storeColumn}/${pk}...[/${pkN}]", e); } catch (StringCastException e) { throw new URLParseException("FAIL TO get primary key from URL's path", e); } checkURLParse(url != null, "NOT DEFINED store column name in ref(#)"); Class columnType = checkNotNull(metaData.columnTypeOf(storeColumn),URLParseException.class,"INVALID column %s",storeColumn); checkURLParse(byte[].class.equals(columnType) || ByteBuffer.class.isAssignableFrom(columnType), "INVALID column type of %s, binary type ( byte[] or java.nio.ByteBuffer) required",storeColumn); return this; } @Override public void connect() throws IOException { try { parse(); connected = true; } catch (Exception e) { Throwables.throwIfInstanceOf(e, IOException.class); throw new IOException(e); } } @Override public InputStream getInputStream() throws IOException{ connect(); try { BaseBean bean = manager.loadByPrimaryKeyChecked(primaryKeys); Object data = bean.getValue(storeColumn); ConditionChecks.checkTrue(data != null, DataNotFoundException.class, "column %s of %s is null", storeColumn, url.toString()); return new ByteArrayInputStream(getBytes(data)); } catch (ObjectRetrievalException e) { throw new DataNotFoundException(url,e); }catch (Exception e) { Throwables.throwIfInstanceOf(e, IOException.class); throw new IOException(e); } } } @SuppressWarnings("unchecked") private static T valueOf(String input,Class targetType)throws StringCastException{ if(Strings.isNullOrEmpty(input) || String.class.equals(targetType)){ return (T) input; } checkNotNull(targetType != null, StringCastException.class,"target is null"); try { return (T) targetType.getMethod("valueOf", String.class).invoke(null, input); } catch (IllegalAccessException | NoSuchMethodException | SecurityException e) { } catch (InvocationTargetException e) { throw new StringCastException(e.getTargetException()); } throw new StringCastException(String.format("INVALID target type %s",targetType)); } public static class URLParseException extends RuntimeException{ private static final long serialVersionUID = 1L; public URLParseException(Throwable cause) { super(cause); } public URLParseException(String message, Throwable cause) { super(message, cause); } public URLParseException(String message) { super(message); } } public static class StringCastException extends RuntimeException{ private static final long serialVersionUID = 1L; public StringCastException(Throwable cause) { super(cause); } public StringCastException(String message) { super(message); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy