|
|
@@ -16,7 +16,8 @@ |
|
|
|
package com.alibaba.csp.sentinel.datasource; |
|
|
|
|
|
|
|
import com.alibaba.csp.sentinel.log.RecordLog; |
|
|
|
import java.io.FileNotFoundException; |
|
|
|
import com.alibaba.csp.sentinel.util.AssertUtil; |
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
import java.io.InputStream; |
|
|
|
import java.nio.charset.Charset; |
|
|
@@ -25,65 +26,66 @@ import java.util.jar.JarFile; |
|
|
|
|
|
|
|
/** |
|
|
|
* <p> |
|
|
|
* A {@link ReadableDataSource} based on jarfile. This class can only read file when it |
|
|
|
* run but will not automatically refresh if it is changed. |
|
|
|
* A {@link ReadableDataSource} based on jar file. This class can only read file initially when it loads file. |
|
|
|
* </p> |
|
|
|
* <p> |
|
|
|
* Limitations: Default read buffer size is 1 MB. If file size is greater than |
|
|
|
* buffer size, exceeding bytes will be ignored. Default charset is UTF-8. |
|
|
|
* Limitations: Default read buffer size is 1 MB, while max allowed buffer size is 4MB. |
|
|
|
* File size should not exceed the buffer size, or exception will be thrown. Default charset is UTF-8. |
|
|
|
* </p> |
|
|
|
* |
|
|
|
* @author dingq |
|
|
|
* @date 2019-03-30 |
|
|
|
* @author Eric Zhao |
|
|
|
* @since 1.6.0 |
|
|
|
*/ |
|
|
|
public class FileInJarReadableDataSource<T> extends AutoRefreshDataSource<String, T> { |
|
|
|
public class FileInJarReadableDataSource<T> extends AbstractDataSource<String, T> { |
|
|
|
|
|
|
|
private static final int MAX_SIZE = 1024 * 1024 * 4; |
|
|
|
private static final long DEFAULT_REFRESH_MS = 3000; |
|
|
|
private static final int DEFAULT_BUF_SIZE = 1024 * 1024; |
|
|
|
private static final Charset DEFAULT_CHAR_SET = Charset.forName("utf-8"); |
|
|
|
private static final Charset DEFAULT_CHARSET = Charset.forName("utf-8"); |
|
|
|
|
|
|
|
private byte[] buf; |
|
|
|
private JarEntry jarEntry; |
|
|
|
private JarFile jarFile; |
|
|
|
private final Charset charset; |
|
|
|
private final String jarName; |
|
|
|
private final String fileInJarName; |
|
|
|
|
|
|
|
private byte[] buf; |
|
|
|
private JarEntry jarEntry; |
|
|
|
private JarFile jarFile; |
|
|
|
|
|
|
|
/** |
|
|
|
* @param jarName the jar to read |
|
|
|
* @param fileInJarName the file in jar to read |
|
|
|
* @param configParser the config decoder (parser) |
|
|
|
* @throws FileNotFoundException |
|
|
|
* @param jarName the jar to read |
|
|
|
* @param fileInJarName the file in jar to read |
|
|
|
* @param configParser the config decoder (parser) |
|
|
|
* @throws IOException if IO failure occurs |
|
|
|
*/ |
|
|
|
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser) |
|
|
|
throws IOException { |
|
|
|
this(jarName, fileInJarName, configParser, DEFAULT_REFRESH_MS, DEFAULT_BUF_SIZE, DEFAULT_CHAR_SET); |
|
|
|
throws IOException { |
|
|
|
this(jarName, fileInJarName, configParser, DEFAULT_BUF_SIZE, DEFAULT_CHARSET); |
|
|
|
} |
|
|
|
|
|
|
|
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, int bufSize) |
|
|
|
throws IOException { |
|
|
|
this(jarName, fileInJarName, configParser, DEFAULT_REFRESH_MS, bufSize, DEFAULT_CHAR_SET); |
|
|
|
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, |
|
|
|
int bufSize) throws IOException { |
|
|
|
this(jarName, fileInJarName, configParser, bufSize, DEFAULT_CHARSET); |
|
|
|
} |
|
|
|
|
|
|
|
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, Charset charset) |
|
|
|
throws IOException { |
|
|
|
this(jarName, fileInJarName, configParser, DEFAULT_REFRESH_MS, DEFAULT_BUF_SIZE, charset); |
|
|
|
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, |
|
|
|
Charset charset) throws IOException { |
|
|
|
this(jarName, fileInJarName, configParser, DEFAULT_BUF_SIZE, charset); |
|
|
|
} |
|
|
|
|
|
|
|
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, long recommendRefreshMs, int bufSize, |
|
|
|
Charset charset) throws IOException { |
|
|
|
super(configParser, recommendRefreshMs); |
|
|
|
public FileInJarReadableDataSource(String jarName, String fileInJarName, Converter<String, T> configParser, |
|
|
|
int bufSize, Charset charset) throws IOException { |
|
|
|
super(configParser); |
|
|
|
AssertUtil.assertNotBlank(jarName, "jarName cannot be blank"); |
|
|
|
AssertUtil.assertNotBlank(fileInJarName, "fileInJarName cannot be blank"); |
|
|
|
if (bufSize <= 0 || bufSize > MAX_SIZE) { |
|
|
|
throw new IllegalArgumentException("bufSize must between (0, " + MAX_SIZE + "], but " + bufSize + " get"); |
|
|
|
} |
|
|
|
if (charset == null) { |
|
|
|
throw new IllegalArgumentException("charset can't be null"); |
|
|
|
} |
|
|
|
AssertUtil.notNull(charset, "charset can't be null"); |
|
|
|
this.buf = new byte[bufSize]; |
|
|
|
this.charset = charset; |
|
|
|
this.jarName = jarName; |
|
|
|
this.fileInJarName = fileInJarName; |
|
|
|
refreshJar(); |
|
|
|
initializeJar(); |
|
|
|
firstLoad(); |
|
|
|
} |
|
|
|
|
|
|
@@ -93,29 +95,14 @@ public class FileInJarReadableDataSource<T> extends AutoRefreshDataSource<String |
|
|
|
// Will throw FileNotFoundException later. |
|
|
|
RecordLog.warn(String.format("[FileInJarReadableDataSource] File does not exist: %s", jarFile.getName())); |
|
|
|
} |
|
|
|
InputStream inputStream = null; |
|
|
|
try { |
|
|
|
inputStream = jarFile.getInputStream(jarEntry); |
|
|
|
try (InputStream inputStream = jarFile.getInputStream(jarEntry)) { |
|
|
|
if (inputStream.available() > buf.length) { |
|
|
|
throw new IllegalStateException(jarFile.getName() + " file size=" + inputStream.available() |
|
|
|
+ ", is bigger than bufSize=" + buf.length + ". Can't read"); |
|
|
|
throw new IllegalStateException(String.format("Size of file <%s> exceeds the bufSize (%d): %d", |
|
|
|
jarFile.getName(), buf.length, inputStream.available())); |
|
|
|
} |
|
|
|
int len = inputStream.read(buf); |
|
|
|
return new String(buf, 0, len, charset); |
|
|
|
} finally { |
|
|
|
if (inputStream != null) { |
|
|
|
try { |
|
|
|
inputStream.close(); |
|
|
|
} catch (Exception ignore) { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
protected boolean isModified() { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
private void firstLoad() { |
|
|
@@ -123,17 +110,16 @@ public class FileInJarReadableDataSource<T> extends AutoRefreshDataSource<String |
|
|
|
T newValue = loadConfig(); |
|
|
|
getProperty().updateValue(newValue); |
|
|
|
} catch (Throwable e) { |
|
|
|
RecordLog.info("loadConfig exception", e); |
|
|
|
RecordLog.warn("[FileInJarReadableDataSource] Error when loading config", e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public void close() throws Exception { |
|
|
|
super.close(); |
|
|
|
buf = null; |
|
|
|
} |
|
|
|
|
|
|
|
private void refreshJar() throws IOException { |
|
|
|
private void initializeJar() throws IOException { |
|
|
|
this.jarFile = new JarFile(jarName); |
|
|
|
this.jarEntry = jarFile.getJarEntry(fileInJarName); |
|
|
|
} |
|
|
|