or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

base-classes.mdcore-interfaces.mdfile-datasources.mdindex.mdspecialized-datasources.md

base-classes.mddocs/

0

# Base Classes

1

2

Abstract base classes providing common functionality for data source implementations, including automatic refresh capabilities and configuration parsing patterns.

3

4

## Capabilities

5

6

### AbstractDataSource Class

7

8

The `AbstractDataSource` class provides basic functionality for loading and parsing configurations, implementing the common patterns shared by most readable data sources.

9

10

```java { .api }

11

/**

12

* The abstract readable data source provides basic functionality for loading and parsing config.

13

* @param <S> source data type

14

* @param <T> target data type

15

*/

16

public abstract class AbstractDataSource<S, T> implements ReadableDataSource<S, T> {

17

18

protected final Converter<S, T> parser;

19

protected final SentinelProperty<T> property;

20

21

/**

22

* Constructor with converter/parser.

23

* @param parser the converter to transform source data to target type

24

* @throws IllegalArgumentException if parser is null

25

*/

26

public AbstractDataSource(Converter<S, T> parser);

27

28

/**

29

* Load config from readSource().

30

* @return the target data

31

* @throws Exception IO or other error occurs

32

*/

33

public T loadConfig() throws Exception;

34

35

/**

36

* Load config from provided source data.

37

* @param conf the source data

38

* @return the target data converted from source

39

* @throws Exception conversion error occurs

40

*/

41

public T loadConfig(S conf) throws Exception;

42

43

/**

44

* Get SentinelProperty of the data source.

45

* @return the property for dynamic updates

46

*/

47

public SentinelProperty<T> getProperty();

48

}

49

```

50

51

**Usage Examples:**

52

53

```java

54

// Custom implementation extending AbstractDataSource

55

public class HttpReadableDataSource<T> extends AbstractDataSource<String, T> {

56

private final String url;

57

private final Map<String, String> headers;

58

59

public HttpReadableDataSource(String url, Converter<String, T> parser) {

60

super(parser);

61

this.url = url;

62

this.headers = new HashMap<>();

63

}

64

65

@Override

66

public String readSource() throws Exception {

67

HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();

68

69

// Add headers

70

for (Map.Entry<String, String> header : headers.entrySet()) {

71

conn.setRequestProperty(header.getKey(), header.getValue());

72

}

73

74

// Read response

75

try (BufferedReader reader = new BufferedReader(

76

new InputStreamReader(conn.getInputStream()))) {

77

StringBuilder response = new StringBuilder();

78

String line;

79

while ((line = reader.readLine()) != null) {

80

response.append(line);

81

}

82

return response.toString();

83

}

84

}

85

86

@Override

87

public void close() throws Exception {

88

// Cleanup HTTP connections if needed

89

}

90

91

public void addHeader(String name, String value) {

92

headers.put(name, value);

93

}

94

}

95

96

// Usage

97

Converter<String, List<FlowRule>> converter = source ->

98

JSON.parseArray(source, FlowRule.class);

99

100

HttpReadableDataSource<List<FlowRule>> httpDs =

101

new HttpReadableDataSource<>("http://config-server/flow-rules", converter);

102

103

httpDs.addHeader("Authorization", "Bearer token123");

104

105

List<FlowRule> rules = httpDs.loadConfig();

106

```

107

108

### AutoRefreshDataSource Class

109

110

The `AutoRefreshDataSource` class extends `AbstractDataSource` to provide automatic refresh capabilities with configurable intervals.

111

112

```java { .api }

113

/**

114

* A ReadableDataSource automatically fetches the backend data.

115

* @param <S> source data type

116

* @param <T> target data type

117

*/

118

public abstract class AutoRefreshDataSource<S, T> extends AbstractDataSource<S, T> {

119

120

protected long recommendRefreshMs;

121

122

/**

123

* Constructor with default refresh interval (3000ms).

124

* @param configParser the converter to transform source data

125

*/

126

public AutoRefreshDataSource(Converter<S, T> configParser);

127

128

/**

129

* Constructor with custom refresh interval.

130

* @param configParser the converter to transform source data

131

* @param recommendRefreshMs refresh interval in milliseconds (must be > 0)

132

* @throws IllegalArgumentException if recommendRefreshMs <= 0

133

*/

134

public AutoRefreshDataSource(Converter<S, T> configParser, long recommendRefreshMs);

135

136

/**

137

* Close the data source and shutdown the refresh scheduler.

138

* @throws Exception if cleanup fails

139

*/

140

public void close() throws Exception;

141

142

/**

143

* Check if the source has been modified since last read.

144

* Override this method to implement custom modification detection.

145

* @return true if source is modified, false otherwise

146

*/

147

protected boolean isModified();

148

}

149

```

150

151

**Usage Examples:**

152

153

```java

154

// Custom auto-refresh implementation

155

public class DatabaseAutoRefreshDataSource<T> extends AutoRefreshDataSource<ResultSet, T> {

156

private final String connectionUrl;

157

private final String query;

158

private long lastChecksum = 0;

159

160

public DatabaseAutoRefreshDataSource(

161

String connectionUrl,

162

String query,

163

Converter<ResultSet, T> converter) {

164

super(converter, 5000); // Refresh every 5 seconds

165

this.connectionUrl = connectionUrl;

166

this.query = query;

167

}

168

169

@Override

170

public ResultSet readSource() throws Exception {

171

Connection conn = DriverManager.getConnection(connectionUrl);

172

PreparedStatement stmt = conn.prepareStatement(query);

173

return stmt.executeQuery();

174

}

175

176

@Override

177

protected boolean isModified() {

178

try {

179

// Check if database has updates using a checksum query

180

Connection conn = DriverManager.getConnection(connectionUrl);

181

PreparedStatement stmt = conn.prepareStatement(

182

"SELECT CHECKSUM(*) FROM configuration_table");

183

ResultSet rs = stmt.executeQuery();

184

185

if (rs.next()) {

186

long currentChecksum = rs.getLong(1);

187

if (currentChecksum != lastChecksum) {

188

lastChecksum = currentChecksum;

189

return true;

190

}

191

}

192

return false;

193

} catch (Exception e) {

194

// On error, assume modified to trigger refresh

195

return true;

196

}

197

}

198

199

@Override

200

public void close() throws Exception {

201

super.close();

202

// Close database connections

203

}

204

}

205

206

// Usage with property listener

207

Converter<ResultSet, List<FlowRule>> dbConverter = rs -> {

208

List<FlowRule> rules = new ArrayList<>();

209

while (rs.next()) {

210

FlowRule rule = new FlowRule();

211

rule.setResource(rs.getString("resource"));

212

rule.setCount(rs.getDouble("qps"));

213

rules.add(rule);

214

}

215

return rules;

216

};

217

218

DatabaseAutoRefreshDataSource<List<FlowRule>> dbDs =

219

new DatabaseAutoRefreshDataSource<>(

220

"jdbc:mysql://localhost/sentinel",

221

"SELECT * FROM flow_rules WHERE enabled = 1",

222

dbConverter

223

);

224

225

// Auto-refresh will update rules every 5 seconds

226

dbDs.getProperty().addListener(rules -> {

227

FlowRuleManager.loadRules(rules);

228

System.out.println("Rules refreshed from database: " + rules.size());

229

});

230

```

231

232

## Refresh Mechanism Details

233

234

The `AutoRefreshDataSource` uses a scheduled executor service to periodically check for updates:

235

236

- **Default refresh interval**: 3000ms (3 seconds)

237

- **Thread management**: Uses `NamedThreadFactory` for proper thread naming

238

- **Error handling**: Logs errors but continues refresh attempts

239

- **Modification detection**: Calls `isModified()` before each refresh

240

- **Property updates**: Only updates the property when new data is loaded

241

242

## Lifecycle Management

243

244

Both base classes integrate with Sentinel's property system for proper lifecycle management:

245

246

```java

247

// Proper setup and cleanup

248

ReadableDataSource<String, List<FlowRule>> ds =

249

new FileRefreshableDataSource<>("/config/rules.json", converter);

250

251

// Register for updates

252

ds.getProperty().addListener(FlowRuleManager::loadRules);

253

254

// Always close when done

255

Runtime.getRuntime().addShutdownHook(new Thread(() -> {

256

try {

257

ds.close();

258

} catch (Exception e) {

259

System.err.println("Error closing data source: " + e.getMessage());

260

}

261

}));

262

```

263

264

## Thread Safety

265

266

- **AbstractDataSource**: Thread-safe for read operations

267

- **AutoRefreshDataSource**: Uses thread-safe scheduled execution

268

- **Property updates**: Properly synchronized through Sentinel's property system

269

- **Custom implementations**: Should ensure thread safety in `readSource()` and `isModified()` methods