gu.sql2java.BaseColumnStore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sql2java-manager Show documentation
Show all versions of sql2java-manager Show documentation
sql2java manager class package for accessing database
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);
}
}
}