Java 5 code style
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,10 +19,9 @@ package org.springframework.jdbc.core.namedparam;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link SqlParameterSource} implementation that holds a given Map of parameters.
|
||||
@@ -44,7 +43,7 @@ import org.springframework.jdbc.core.SqlParameterValue;
|
||||
*/
|
||||
public class MapSqlParameterSource extends AbstractSqlParameterSource {
|
||||
|
||||
private final Map values = new HashMap();
|
||||
private final Map<String, Object> values = new HashMap<String, Object>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -70,7 +69,7 @@ public class MapSqlParameterSource extends AbstractSqlParameterSource {
|
||||
* Create a new MapSqlParameterSource based on a Map.
|
||||
* @param values a Map holding existing parameter values (can be <code>null</code>)
|
||||
*/
|
||||
public MapSqlParameterSource(Map values) {
|
||||
public MapSqlParameterSource(Map<String, Object> values) {
|
||||
addValues(values);
|
||||
}
|
||||
|
||||
@@ -85,8 +84,8 @@ public class MapSqlParameterSource extends AbstractSqlParameterSource {
|
||||
public MapSqlParameterSource addValue(String paramName, Object value) {
|
||||
Assert.notNull(paramName, "Parameter name must not be null");
|
||||
this.values.put(paramName, value);
|
||||
if (value != null && value instanceof SqlParameterValue) {
|
||||
registerSqlType(paramName, ((SqlParameterValue)value).getSqlType());
|
||||
if (value instanceof SqlParameterValue) {
|
||||
registerSqlType(paramName, ((SqlParameterValue) value).getSqlType());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -129,14 +128,13 @@ public class MapSqlParameterSource extends AbstractSqlParameterSource {
|
||||
* @return a reference to this parameter source,
|
||||
* so it's possible to chain several calls together
|
||||
*/
|
||||
public MapSqlParameterSource addValues(Map values) {
|
||||
public MapSqlParameterSource addValues(Map<String, Object> values) {
|
||||
if (values != null) {
|
||||
this.values.putAll(values);
|
||||
for (Iterator iter = values.keySet().iterator(); iter.hasNext();) {
|
||||
Object k = iter.next();
|
||||
Object o = values.get(k);
|
||||
if (o != null && k instanceof String && o instanceof SqlParameterValue) {
|
||||
registerSqlType((String)k, ((SqlParameterValue)o).getSqlType());
|
||||
for (Map.Entry<String, Object> entry : values.entrySet()) {
|
||||
this.values.put(entry.getKey(), entry.getValue());
|
||||
if (entry.getValue() instanceof SqlParameterValue) {
|
||||
SqlParameterValue value = (SqlParameterValue) entry.getValue();
|
||||
registerSqlType(entry.getKey(), value.getSqlType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,7 +144,7 @@ public class MapSqlParameterSource extends AbstractSqlParameterSource {
|
||||
/**
|
||||
* Expose the current parameter values as read-only Map.
|
||||
*/
|
||||
public Map getValues() {
|
||||
public Map<String, Object> getValues() {
|
||||
return Collections.unmodifiableMap(this.values);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public abstract class NamedParameterUtils {
|
||||
public static ParsedSql parseSqlStatement(String sql) {
|
||||
Assert.notNull(sql, "SQL must not be null");
|
||||
|
||||
Set namedParameters = new HashSet();
|
||||
Set<String> namedParameters = new HashSet<String>();
|
||||
ParsedSql parsedSql = new ParsedSql(sql);
|
||||
|
||||
char[] statement = sql.toCharArray();
|
||||
@@ -249,7 +249,9 @@ public abstract class NamedParameterUtils {
|
||||
* be built into the value array in the form of SqlParameterValue objects.
|
||||
* @return the array of values
|
||||
*/
|
||||
public static Object[] buildValueArray(ParsedSql parsedSql, SqlParameterSource paramSource, List declaredParams) {
|
||||
public static Object[] buildValueArray(
|
||||
ParsedSql parsedSql, SqlParameterSource paramSource, List<SqlParameter> declaredParams) {
|
||||
|
||||
Object[] paramArray = new Object[parsedSql.getTotalParameterCount()];
|
||||
if (parsedSql.getNamedParameterCount() > 0 && parsedSql.getUnnamedParameterCount() > 0) {
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
@@ -258,9 +260,9 @@ public abstract class NamedParameterUtils {
|
||||
parsedSql.getUnnamedParameterCount() + " traditonal placeholder(s) in [" +
|
||||
parsedSql.getOriginalSql() + "]");
|
||||
}
|
||||
List paramNames = parsedSql.getParameterNames();
|
||||
List<String> paramNames = parsedSql.getParameterNames();
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
String paramName = (String) paramNames.get(i);
|
||||
String paramName = paramNames.get(i);
|
||||
try {
|
||||
Object value = paramSource.getValue(paramName);
|
||||
SqlParameter param = findParameter(declaredParams, paramName, i);
|
||||
@@ -281,18 +283,17 @@ public abstract class NamedParameterUtils {
|
||||
* @param paramIndex the index of the desired parameter
|
||||
* @return the declared SqlParameter, or <code>null</code> if none found
|
||||
*/
|
||||
private static SqlParameter findParameter(List declaredParams, String paramName, int paramIndex) {
|
||||
private static SqlParameter findParameter(List<SqlParameter> declaredParams, String paramName, int paramIndex) {
|
||||
if (declaredParams != null) {
|
||||
// First pass: Look for named parameter match.
|
||||
for (Iterator it = declaredParams.iterator(); it.hasNext();) {
|
||||
SqlParameter declaredParam = (SqlParameter) it.next();
|
||||
for (SqlParameter declaredParam : declaredParams) {
|
||||
if (paramName.equals(declaredParam.getName())) {
|
||||
return declaredParam;
|
||||
}
|
||||
}
|
||||
// Second pass: Look for parameter index match.
|
||||
if (paramIndex < declaredParams.size()) {
|
||||
SqlParameter declaredParam = (SqlParameter) declaredParams.get(paramIndex);
|
||||
SqlParameter declaredParam = declaredParams.get(paramIndex);
|
||||
// Only accept unnamed parameters for index matches.
|
||||
if (declaredParam.getName() == null) {
|
||||
return declaredParam;
|
||||
@@ -310,8 +311,8 @@ public abstract class NamedParameterUtils {
|
||||
if (Character.isWhitespace(c)) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < PARAMETER_SEPARATORS.length; i++) {
|
||||
if (c == PARAMETER_SEPARATORS[i]) {
|
||||
for (char separator : PARAMETER_SEPARATORS) {
|
||||
if (c == separator) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,9 +30,9 @@ public class ParsedSql {
|
||||
|
||||
private String originalSql;
|
||||
|
||||
private List parameterNames = new ArrayList();
|
||||
private List<String> parameterNames = new ArrayList<String>();
|
||||
|
||||
private List parameterIndexes = new ArrayList();
|
||||
private List<int[]> parameterIndexes = new ArrayList<int[]>();
|
||||
|
||||
private int namedParameterCount;
|
||||
|
||||
@@ -72,7 +72,7 @@ public class ParsedSql {
|
||||
* Return all of the parameters (bind variables) in the parsed SQL statement.
|
||||
* Repeated occurences of the same parameter name are included here.
|
||||
*/
|
||||
List getParameterNames() {
|
||||
List<String> getParameterNames() {
|
||||
return this.parameterNames;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class ParsedSql {
|
||||
* a int array of length 2
|
||||
*/
|
||||
int[] getParameterIndexes(int parameterPosition) {
|
||||
return (int[]) this.parameterIndexes.get(parameterPosition);
|
||||
return this.parameterIndexes.get(parameterPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,9 +98,7 @@ public class SqlParameterSourceUtils {
|
||||
}
|
||||
}
|
||||
else if (parameterSource instanceof MapSqlParameterSource) {
|
||||
for (Iterator it = ((MapSqlParameterSource) parameterSource).getValues().keySet().iterator(); it.hasNext();)
|
||||
{
|
||||
String name = (String) it.next();
|
||||
for (String name : ((MapSqlParameterSource) parameterSource).getValues().keySet()) {
|
||||
caseInsensitiveParameterNames.put(name.toLowerCase(), name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,7 @@ package org.springframework.jdbc.datasource.lookup;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -41,13 +39,13 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
|
||||
|
||||
private Map targetDataSources;
|
||||
private Map<Object, Object> targetDataSources;
|
||||
|
||||
private Object defaultTargetDataSource;
|
||||
|
||||
private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
|
||||
|
||||
private Map resolvedDataSources;
|
||||
private Map<Object, DataSource> resolvedDataSources;
|
||||
|
||||
private DataSource resolvedDefaultDataSource;
|
||||
|
||||
@@ -62,7 +60,7 @@ public abstract class AbstractRoutingDataSource extends AbstractDataSource imple
|
||||
* be handled by {@link #resolveSpecifiedLookupKey(Object)} and
|
||||
* {@link #determineCurrentLookupKey()}.
|
||||
*/
|
||||
public void setTargetDataSources(Map targetDataSources) {
|
||||
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
|
||||
this.targetDataSources = targetDataSources;
|
||||
}
|
||||
|
||||
@@ -92,11 +90,10 @@ public abstract class AbstractRoutingDataSource extends AbstractDataSource imple
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
if (this.targetDataSources == null) {
|
||||
throw new IllegalArgumentException("targetDataSources is required");
|
||||
throw new IllegalArgumentException("Property 'targetDataSources' is required");
|
||||
}
|
||||
this.resolvedDataSources = new HashMap(this.targetDataSources.size());
|
||||
for (Iterator it = this.targetDataSources.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
this.resolvedDataSources = new HashMap<Object, DataSource>(this.targetDataSources.size());
|
||||
for (Map.Entry entry : this.targetDataSources.entrySet()) {
|
||||
Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
|
||||
DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
|
||||
this.resolvedDataSources.put(lookupKey, dataSource);
|
||||
@@ -148,7 +145,7 @@ public abstract class AbstractRoutingDataSource extends AbstractDataSource imple
|
||||
protected DataSource determineTargetDataSource() {
|
||||
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
|
||||
Object lookupKey = determineCurrentLookupKey();
|
||||
DataSource dataSource = (DataSource) this.resolvedDataSources.get(lookupKey);
|
||||
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
|
||||
if (dataSource == null) {
|
||||
dataSource = this.resolvedDefaultDataSource;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 the original author or authors.
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
@@ -22,7 +22,6 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -56,9 +55,9 @@ public class BatchSqlUpdate extends SqlUpdate {
|
||||
|
||||
private boolean trackRowsAffected = true;
|
||||
|
||||
private final LinkedList parameterQueue = new LinkedList();
|
||||
private final LinkedList<Object[]> parameterQueue = new LinkedList<Object[]>();
|
||||
|
||||
private final List rowsAffected = new ArrayList();
|
||||
private final List<Integer> rowsAffected = new ArrayList<Integer>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -189,19 +188,18 @@ public class BatchSqlUpdate extends SqlUpdate {
|
||||
return parameterQueue.size();
|
||||
}
|
||||
public void setValues(PreparedStatement ps, int index) throws SQLException {
|
||||
Object[] params = (Object[]) parameterQueue.removeFirst();
|
||||
Object[] params = parameterQueue.removeFirst();
|
||||
newPreparedStatementSetter(params).setValues(ps);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.trackRowsAffected) {
|
||||
for (int i = 0; i < rowsAffected.length; i++) {
|
||||
this.rowsAffected.add(new Integer(rowsAffected[i]));
|
||||
for (int rowCount : rowsAffected) {
|
||||
checkRowsAffected(rowCount);
|
||||
if (this.trackRowsAffected) {
|
||||
this.rowsAffected.add(rowCount);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < rowsAffected.length; i++) {
|
||||
checkRowsAffected(rowsAffected[i]);
|
||||
}
|
||||
|
||||
return rowsAffected;
|
||||
}
|
||||
|
||||
@@ -230,9 +228,8 @@ public class BatchSqlUpdate extends SqlUpdate {
|
||||
public int[] getRowsAffected() {
|
||||
int[] result = new int[this.rowsAffected.size()];
|
||||
int i = 0;
|
||||
for (Iterator it = this.rowsAffected.iterator(); it.hasNext(); i++) {
|
||||
Integer rowCount = (Integer) it.next();
|
||||
result[i] = rowCount.intValue();
|
||||
for (Iterator<Integer> it = this.rowsAffected.iterator(); it.hasNext(); i++) {
|
||||
result[i] = it.next();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,11 @@ package org.springframework.jdbc.object;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Types;
|
||||
import java.util.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -69,11 +72,9 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
|
||||
private String[] generatedKeysColumnNames = null;
|
||||
|
||||
/** SQL statement */
|
||||
private String sql;
|
||||
|
||||
/** List of SqlParameter objects */
|
||||
private final List declaredParameters = new LinkedList();
|
||||
private final List<SqlParameter> declaredParameters = new LinkedList<SqlParameter>();
|
||||
|
||||
/**
|
||||
* Has this operation been compiled? Compilation means at
|
||||
@@ -254,8 +255,8 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot add parameters once query is compiled");
|
||||
}
|
||||
if (types != null) {
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
declareParameter(new SqlParameter(types[i]));
|
||||
for (int type : types) {
|
||||
declareParameter(new SqlParameter(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,11 +377,8 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
*/
|
||||
protected void validateParameters(Object[] parameters) throws InvalidDataAccessApiUsageException {
|
||||
checkCompiled();
|
||||
|
||||
int declaredInParameters = 0;
|
||||
Iterator it = this.declaredParameters.iterator();
|
||||
while (it.hasNext()) {
|
||||
SqlParameter param = (SqlParameter) it.next();
|
||||
for (SqlParameter param : this.declaredParameters) {
|
||||
if (param.isInputValueProvided()) {
|
||||
if (!supportsLobParameters() &&
|
||||
(param.getSqlType() == Types.BLOB || param.getSqlType() == Types.CLOB)) {
|
||||
@@ -390,7 +388,6 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
declaredInParameters++;
|
||||
}
|
||||
}
|
||||
|
||||
validateParameterCount((parameters != null ? parameters.length : 0), declaredInParameters);
|
||||
}
|
||||
|
||||
@@ -401,14 +398,11 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
* @param parameters parameter Map supplied. May be <code>null</code>.
|
||||
* @throws InvalidDataAccessApiUsageException if the parameters are invalid
|
||||
*/
|
||||
protected void validateNamedParameters(Map parameters) throws InvalidDataAccessApiUsageException {
|
||||
protected void validateNamedParameters(Map<String, Object> parameters) throws InvalidDataAccessApiUsageException {
|
||||
checkCompiled();
|
||||
Map paramsToUse = (parameters != null ? parameters : Collections.EMPTY_MAP);
|
||||
|
||||
Map paramsToUse = (parameters != null ? parameters : Collections.emptyMap());
|
||||
int declaredInParameters = 0;
|
||||
Iterator it = this.declaredParameters.iterator();
|
||||
while (it.hasNext()) {
|
||||
SqlParameter param = (SqlParameter) it.next();
|
||||
for (SqlParameter param : this.declaredParameters) {
|
||||
if (param.isInputValueProvided()) {
|
||||
if (!supportsLobParameters() &&
|
||||
(param.getSqlType() == Types.BLOB || param.getSqlType() == Types.CLOB)) {
|
||||
@@ -422,7 +416,6 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
declaredInParameters++;
|
||||
}
|
||||
}
|
||||
|
||||
validateParameterCount(paramsToUse.size(), declaredInParameters);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@ package org.springframework.jdbc.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -82,13 +80,12 @@ public class SQLErrorCodesFactory {
|
||||
* Map to hold error codes for all databases defined in the config file.
|
||||
* Key is the database product name, value is the SQLErrorCodes instance.
|
||||
*/
|
||||
private final Map errorCodesMap;
|
||||
private final Map<String, SQLErrorCodes> errorCodesMap;
|
||||
|
||||
/**
|
||||
* Map to cache the SQLErrorCodes instance per DataSource.
|
||||
* Key is the DataSource, value is the SQLErrorCodes instance.
|
||||
*/
|
||||
private final Map dataSourceCache = new HashMap(16);
|
||||
private final Map<DataSource, SQLErrorCodes> dataSourceCache = new HashMap<DataSource, SQLErrorCodes>(16);
|
||||
|
||||
|
||||
/**
|
||||
@@ -100,7 +97,7 @@ public class SQLErrorCodesFactory {
|
||||
* @see #loadResource(String)
|
||||
*/
|
||||
protected SQLErrorCodesFactory() {
|
||||
Map errorCodes = null;
|
||||
Map<String, SQLErrorCodes> errorCodes = null;
|
||||
|
||||
try {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
@@ -130,7 +127,7 @@ public class SQLErrorCodesFactory {
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
logger.warn("Error loading SQL error codes from config file", ex);
|
||||
errorCodes = Collections.EMPTY_MAP;
|
||||
errorCodes = Collections.emptyMap();
|
||||
}
|
||||
|
||||
this.errorCodesMap = errorCodes;
|
||||
@@ -162,10 +159,9 @@ public class SQLErrorCodesFactory {
|
||||
public SQLErrorCodes getErrorCodes(String dbName) {
|
||||
Assert.notNull(dbName, "Database product name must not be null");
|
||||
|
||||
SQLErrorCodes sec = (SQLErrorCodes) this.errorCodesMap.get(dbName);
|
||||
SQLErrorCodes sec = this.errorCodesMap.get(dbName);
|
||||
if (sec == null) {
|
||||
for (Iterator it = this.errorCodesMap.values().iterator(); it.hasNext();) {
|
||||
SQLErrorCodes candidate = (SQLErrorCodes) it.next();
|
||||
for (SQLErrorCodes candidate : this.errorCodesMap.values()) {
|
||||
if (PatternMatchUtils.simpleMatch(candidate.getDatabaseProductNames(), dbName)) {
|
||||
sec = candidate;
|
||||
break;
|
||||
@@ -203,7 +199,7 @@ public class SQLErrorCodesFactory {
|
||||
|
||||
synchronized (this.dataSourceCache) {
|
||||
// Let's avoid looking up database product info if we can.
|
||||
SQLErrorCodes sec = (SQLErrorCodes) this.dataSourceCache.get(dataSource);
|
||||
SQLErrorCodes sec = this.dataSourceCache.get(dataSource);
|
||||
if (sec != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SQLErrorCodes found in cache for DataSource [" +
|
||||
@@ -213,8 +209,7 @@ public class SQLErrorCodesFactory {
|
||||
}
|
||||
// We could not find it - got to look it up.
|
||||
try {
|
||||
String dbName = (String)
|
||||
JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName");
|
||||
String dbName = (String) JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName");
|
||||
if (dbName != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Database product name cached for DataSource [" +
|
||||
|
||||
Reference in New Issue
Block a user