001package gu.sql2java.store; 002 003import static gu.sql2java.store.BinaryUtils.*; 004import static gu.sql2java.store.URLInfo.wrap; 005 006import java.io.IOException; 007import java.net.URL; 008import java.net.URLStreamHandler; 009import java.net.URLStreamHandlerFactory; 010import java.util.Collections; 011import java.util.HashMap; 012import java.util.Hashtable; 013import java.util.Map; 014 015import ref.org.apache.commons.jnet.Installer; 016 017/** 018 * 基于{@link URLStreamHandler}实现二进制存储接口{@link URLStore}的抽象类<br> 019 * 实现{@link URLStreamHandlerFactory}接口,应用启动时应调用{@link #intall()}将当前实例安装到JVM 020 * @author guyadong 021 * 022 */ 023public abstract class BaseURLStore implements URLStreamHandlerFactory, URLStore { 024 025 private volatile boolean installed = false; 026 private final Map<String, Class<?>> optionalParamTypes = new Hashtable<>(); 027 protected final ThreadLocal<Map<String, Object>> additionalParams = new ThreadLocal<>(); 028 protected BaseURLStore() { 029 this(null); 030 } 031 032 protected BaseURLStore(Map<String, Class<?>> optionalParamTypes) { 033 super(); 034 if(optionalParamTypes == null){ 035 optionalParamTypes = Collections.emptyMap(); 036 } 037 this.optionalParamTypes.putAll(optionalParamTypes); 038 } 039 040 /** 041 * 存储图像数据 042 * @param binary 二进制数据字节数组 043 * @param md5 imageBytes的MD5校验码 044 * @param extension 文件后缀,可为{@code null} 045 * @param makeURLOnly 为{@code true}时不存储数据只返回存储URL 046 * @return 存储URL 047 * @throws IOException 048 */ 049 protected abstract URL doStore(byte[] binary,String md5, String extension, boolean makeURLOnly) throws IOException; 050 051 /** 052 * 判断存储 URl 是否存在 053 * @param storedURL 存储URL 054 * @return 055 */ 056 protected abstract boolean doExists(URL storedURL); 057 058 /** 059 * 查找指定MD5的二进制数据 060 * @param md5 MD5校验码 061 * @return 数据存储URL,找不到返回{@code null} 062 */ 063 protected abstract URL doFind(String md5); 064 /** 065 * 指定指定的二进制数据 066 * @param storedURL 存储的URL 067 * @return 删除成功返回{@code true},否则返回{@code false} 068 * @throws IOException 069 */ 070 protected abstract boolean doDelete(URL storedURL) throws IOException; 071 072 protected abstract URLStreamHandler doGetURLStreamHandler(); 073 074 protected final URL find(URLInfo binary){ 075 if(isStored(binary.location)){ 076 return doExists(binary.location) ? binary.location : null; 077 } 078 String md5 = binary.getMD5(); 079 return md5 == null ? null : doFind(md5); 080 } 081 082 @Override 083 public final boolean isStored(URL url){ 084 return null != url && url.getProtocol().equals(getProtocol()); 085 } 086 087 @Override 088 public final boolean exists(URL url){ 089 return null != find(wrap(url)); 090 } 091 092 @Override 093 public final <T>URL store(T input,String md5,String extension, boolean overwrite, boolean makeURLOnly) throws IOException { 094 byte[] binary; 095 if(makeURLOnly){ 096 binary = getBytes(input); 097 if(!validMd5(md5)){ 098 throw new IOException("VALID md5 required while make URL only"); 099 } 100 }else{ 101 binary = getBytesNotEmpty(input); 102 if(!validMd5(md5)){ 103 md5 = getMD5String(binary); 104 } 105 } 106 return doStore(binary,md5,extension, makeURLOnly); 107 } 108 109 @Override 110 public final boolean delete(String md5) throws IOException{ 111 if(validMd5(md5)){ 112 URL storedURL; 113 if(null != (storedURL = doFind(md5))){ 114 return doDelete(storedURL); 115 } 116 } 117 return false; 118 } 119 120 @Override 121 public final URL store(URL url, boolean overwrite, boolean makeURLOnly) throws IOException { 122 URLInfo data = wrap(url); 123 URL storedURL; 124 if(null == (storedURL = find(data)) || overwrite){ 125 storedURL = doStore( 126 getBytesNotEmpty(data.location), 127 data.getMD5(), 128 data.extension, 129 makeURLOnly); 130 } 131 return storedURL; 132 } 133 134 @Override 135 public final boolean delete(URL url) throws IOException{ 136 URL storedURL = url; 137 if(!isStored(storedURL)){ 138 if(null == (storedURL = find(wrap(url)))){ 139 return false; 140 } 141 } 142 return doDelete(storedURL); 143 } 144 145 @Override 146 public final BaseURLStore setAdditionalParam(String name,Object value){ 147 if(null != name){ 148 Class<?> type = optionalParamTypes.get(name); 149 if(null != type && null != value){ 150 if(!type.isInstance(value)){ 151 throw new IllegalArgumentException(String.format("INVALID param type for %s , %srequired",name,type)); 152 } 153 if(additionalParams.get() == null){ 154 additionalParams.set(new HashMap<String,Object>()); 155 } 156 additionalParams.get().put(name, value); 157 } 158 } 159 return this; 160 } 161 @Override 162 public final URLStreamHandler createURLStreamHandler(String protocol) { 163 if(getProtocol().equals(protocol)){ 164 return doGetURLStreamHandler(); 165 } 166 return null; 167 } 168 /** 169 * 将当前{@link URLStreamHandlerFactory}实例安装到JVM 170 * @return 当前对象 171 * @throws Exception 172 */ 173 public final BaseURLStore intall() throws Exception{ 174 // double check 175 if(!installed){ 176 synchronized(this){ 177 if(!installed){ 178 Installer.setURLStreamHandlerFactory(this); 179 installed = true; 180 } 181 } 182 } 183 return this; 184 } 185 186 @Override 187 public int hashCode() { 188 final int prime = 31; 189 int result = 1; 190 result = prime * result + ((getProtocol() == null) ? 0 : getProtocol().hashCode()); 191 return result; 192 } 193 194 @Override 195 public boolean equals(Object obj) { 196 if (this == obj) 197 return true; 198 if (obj == null) 199 return false; 200 if (!(obj instanceof BaseURLStore)) 201 return false; 202 BaseURLStore other = (BaseURLStore) obj; 203 if (getProtocol() == null) { 204 if (other.getProtocol() != null) 205 return false; 206 } else if (!getProtocol().equals(other.getProtocol())) 207 return false; 208 return true; 209 } 210 211 @Override 212 public String toString() { 213 StringBuilder builder = new StringBuilder(); 214 builder.append("BaseURLStore [protocol="); 215 builder.append(getProtocol()); 216 builder.append("]"); 217 return builder.toString(); 218 } 219 220} 221 222