Unverified 提交 f97a3dcc authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1223 from katzyn/tests

Fix issues with testing on latest Java versions
...@@ -24,6 +24,14 @@ public class MetaRecord implements Comparable<MetaRecord> { ...@@ -24,6 +24,14 @@ public class MetaRecord implements Comparable<MetaRecord> {
private final int objectType; private final int objectType;
private final String sql; private final String sql;
/**
* Copy metadata from the specified object into specified search row.
*
* @param obj
* database object
* @param r
* search row
*/
public static void populateRowFromDBObject(DbObject obj, SearchRow r) { public static void populateRowFromDBObject(DbObject obj, SearchRow r) {
r.setValue(0, ValueInt.get(obj.getId())); r.setValue(0, ValueInt.get(obj.getId()));
r.setValue(1, ValueInt.get(0)); r.setValue(1, ValueInt.get(0));
......
...@@ -311,7 +311,8 @@ public class DbException extends RuntimeException { ...@@ -311,7 +311,8 @@ public class DbException extends RuntimeException {
return get(ErrorCode.GENERAL_ERROR_1, e, e.toString()); return get(ErrorCode.GENERAL_ERROR_1, e, e.toString());
} catch (Throwable ex) { } catch (Throwable ex) {
try { try {
DbException dbException = new DbException(new SQLException("GeneralError", "HY000", ErrorCode.GENERAL_ERROR_1, e)); DbException dbException = new DbException(
new SQLException("GeneralError", "HY000", ErrorCode.GENERAL_ERROR_1, e));
dbException.addSuppressed(ex); dbException.addSuppressed(ex);
return dbException; return dbException;
} catch (OutOfMemoryError ignore) { } catch (OutOfMemoryError ignore) {
......
...@@ -49,16 +49,19 @@ public abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue ...@@ -49,16 +49,19 @@ public abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue
// because a tree root has definitely been changed. // because a tree root has definitely been changed.
logIt(existingValue.value == null ? null : VersionedValue.getInstance(existingValue.value)); logIt(existingValue.value == null ? null : VersionedValue.getInstance(existingValue.value));
decision = MVMap.Decision.PUT; decision = MVMap.Decision.PUT;
} else if(fetchTransaction(blockingId) != null) { } else if (fetchTransaction(blockingId) != null) {
// this entry comes from a different transaction, and this transaction is not committed yet // this entry comes from a different transaction, and this
// transaction is not committed yet
// should wait on blockingTransaction that was determined earlier // should wait on blockingTransaction that was determined earlier
decision = MVMap.Decision.ABORT; decision = MVMap.Decision.ABORT;
} else if(id == lastOperationId) { } else if (id == lastOperationId) {
// There is no transaction with that id, and we've tried it just before, // There is no transaction with that id, and we've tried it just
// but map root has not changed (which must be the case if we just missed a closed transaction), // before, but map root has not changed (which must be the case if
// therefore we came back here again. // we just missed a closed transaction), therefore we came back here
// Now we assume it's a leftover after unclean shutdown (map update was written but not undo log), // again.
// and will effectively roll it back (just assume committed value and overwrite). // Now we assume it's a leftover after unclean shutdown (map update
// was written but not undo log), and will effectively roll it back
// (just assume committed value and overwrite).
Object committedValue = existingValue.getCommittedValue(); Object committedValue = existingValue.getCommittedValue();
logIt(committedValue == null ? null : VersionedValue.getInstance(committedValue)); logIt(committedValue == null ? null : VersionedValue.getInstance(committedValue));
decision = MVMap.Decision.PUT; decision = MVMap.Decision.PUT;
...@@ -164,26 +167,31 @@ public abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue ...@@ -164,26 +167,31 @@ public abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue
// and therefore will be committed soon // and therefore will be committed soon
logIt(null); logIt(null);
return setDecision(MVMap.Decision.PUT); return setDecision(MVMap.Decision.PUT);
} else if(fetchTransaction(blockingId) != null) { } else if (fetchTransaction(blockingId) != null) {
// this entry comes from a different transaction, and this transaction is not committed yet // this entry comes from a different transaction, and this
// should wait on blockingTransaction that was determined earlier and then try again // transaction is not committed yet
// should wait on blockingTransaction that was determined
// earlier and then try again
return setDecision(MVMap.Decision.ABORT); return setDecision(MVMap.Decision.ABORT);
} else if(id == lastOperationId) { } else if (id == lastOperationId) {
// There is no transaction with that id, and we've tried it just before, // There is no transaction with that id, and we've tried it
// but map root has not changed (which must be the case if we just missed a closed transaction), // just before, but map root has not changed (which must be
// the case if we just missed a closed transaction),
// therefore we came back here again. // therefore we came back here again.
// Now we assume it's a leftover after unclean shutdown (map update was written but not undo log), // Now we assume it's a leftover after unclean shutdown (map
// and will effectively roll it back (just assume committed value and overwrite). // update was written but not undo log), and will
// effectively roll it back (just assume committed value and
// overwrite).
Object committedValue = existingValue.getCommittedValue(); Object committedValue = existingValue.getCommittedValue();
if(committedValue != null) { if (committedValue != null) {
return setDecision(MVMap.Decision.ABORT); return setDecision(MVMap.Decision.ABORT);
} }
logIt(null); logIt(null);
return setDecision(MVMap.Decision.PUT); return setDecision(MVMap.Decision.PUT);
} else { } else {
// transaction has been committed/rolled back and is closed by now, so // transaction has been committed/rolled back and is closed
// we can retry immediately and either that entry become committed // by now, so we can retry immediately and either that entry
// or we'll hit case above // become committed or we'll hit case above
lastOperationId = id; lastOperationId = id;
return setDecision(MVMap.Decision.REPEAT); return setDecision(MVMap.Decision.REPEAT);
} }
......
...@@ -22,7 +22,7 @@ public class H2AuthConfig { ...@@ -22,7 +22,7 @@ public class H2AuthConfig {
public void setAllowUserRegistration(boolean allowUserRegistration) { public void setAllowUserRegistration(boolean allowUserRegistration) {
this.allowUserRegistration = allowUserRegistration; this.allowUserRegistration = allowUserRegistration;
} }
boolean createMissingRoles=true; boolean createMissingRoles=true;
public boolean isCreateMissingRoles() { public boolean isCreateMissingRoles() {
......
...@@ -58,7 +58,7 @@ public class H2AuthConfigXml extends DefaultHandler{ ...@@ -58,7 +58,7 @@ public class H2AuthConfigXml extends DefaultHandler{
default: default:
throw new SAXException("unexpected element "+qName); throw new SAXException("unexpected element "+qName);
} }
} }
@Override @Override
...@@ -74,7 +74,7 @@ public class H2AuthConfigXml extends DefaultHandler{ ...@@ -74,7 +74,7 @@ public class H2AuthConfigXml extends DefaultHandler{
throw new SAXException("missing attribute "+attributeName); throw new SAXException("missing attribute "+attributeName);
} }
return attributeValue; return attributeValue;
} }
static String getAttributeValueOr(String attributeName, Attributes attributes, String defaultValue) { static String getAttributeValueOr(String attributeName, Attributes attributes, String defaultValue) {
...@@ -90,7 +90,7 @@ public class H2AuthConfigXml extends DefaultHandler{ ...@@ -90,7 +90,7 @@ public class H2AuthConfigXml extends DefaultHandler{
} }
/** /**
* Parse the xml * Parse the xml
* @param url * @param url
* @return * @return
* @throws Exception * @throws Exception
...@@ -102,7 +102,7 @@ public class H2AuthConfigXml extends DefaultHandler{ ...@@ -102,7 +102,7 @@ public class H2AuthConfigXml extends DefaultHandler{
} }
public static H2AuthConfig parseFrom(InputStream inputStream) throws Exception{ public static H2AuthConfig parseFrom(InputStream inputStream) throws Exception{
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
H2AuthConfigXml xmlHandler = new H2AuthConfigXml(); H2AuthConfigXml xmlHandler = new H2AuthConfigXml();
saxParser.parse(inputStream,xmlHandler); saxParser.parse(inputStream,xmlHandler);
return xmlHandler.getResult(); return xmlHandler.getResult();
......
...@@ -7,6 +7,9 @@ package org.h2.security.auth; ...@@ -7,6 +7,9 @@ package org.h2.security.auth;
import java.util.List; import java.util.List;
/**
* Interface for objects with configuration properties.
*/
public interface HasConfigProperties { public interface HasConfigProperties {
List<PropertyConfig> getProperties(); List<PropertyConfig> getProperties();
} }
...@@ -8,7 +8,10 @@ package org.h2.security.auth; ...@@ -8,7 +8,10 @@ package org.h2.security.auth;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class RealmConfig implements HasConfigProperties{ /**
* Configuration for authentication realm.
*/
public class RealmConfig implements HasConfigProperties {
private String name; private String name;
...@@ -32,6 +35,7 @@ public class RealmConfig implements HasConfigProperties{ ...@@ -32,6 +35,7 @@ public class RealmConfig implements HasConfigProperties{
List<PropertyConfig> properties; List<PropertyConfig> properties;
@Override
public List<PropertyConfig> getProperties() { public List<PropertyConfig> getProperties() {
if (properties == null) { if (properties == null) {
properties = new ArrayList<>(); properties = new ArrayList<>();
......
...@@ -8,7 +8,10 @@ package org.h2.security.auth; ...@@ -8,7 +8,10 @@ package org.h2.security.auth;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class UserToRolesMapperConfig implements HasConfigProperties{ /**
* Configuration for class that maps users to their roles.
*/
public class UserToRolesMapperConfig implements HasConfigProperties {
private String className; private String className;
...@@ -22,6 +25,7 @@ public class UserToRolesMapperConfig implements HasConfigProperties{ ...@@ -22,6 +25,7 @@ public class UserToRolesMapperConfig implements HasConfigProperties{
this.className = className; this.className = className;
} }
@Override
public List<PropertyConfig> getProperties() { public List<PropertyConfig> getProperties() {
if (properties == null) { if (properties == null) {
properties = new ArrayList<>(); properties = new ArrayList<>();
......
...@@ -889,7 +889,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -889,7 +889,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
*/ */
private void testAdditional() { private void testAdditional() {
if (networked) { if (networked) {
throw new RuntimeException("testAditional() is not allowed in networked mode"); throw new RuntimeException("testAdditional() is not allowed in networked mode");
} }
addTest(new TestMVTableEngine()); addTest(new TestMVTableEngine());
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.test; package org.h2.test;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
...@@ -1317,6 +1318,16 @@ public abstract class TestBase { ...@@ -1317,6 +1318,16 @@ public abstract class TestBase {
return System.getProperty("java.class.path"); return System.getProperty("java.class.path");
} }
/**
* Get the path to a java executable of the current process
*
* @return the path to java
*/
public static String getJVM() {
return System.getProperty("java.home") + File.separatorChar + "bin"
+ File.separator + "java";
}
/** /**
* Use up almost all memory. * Use up almost all memory.
* *
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
*/ */
package org.h2.test; package org.h2.test;
import java.io.File;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
...@@ -191,16 +190,6 @@ public abstract class TestDb extends TestBase { ...@@ -191,16 +190,6 @@ public abstract class TestDb extends TestBase {
// } // }
} }
/**
* Get the path to a java executable of the current process
*
* @return the path to java
*/
private static String getJVM() {
return System.getProperty("java.home") + File.separatorChar + "bin"
+ File.separator + "java";
}
/** /**
* Build a child process. * Build a child process.
* *
......
...@@ -278,7 +278,7 @@ public class TestAuthentication extends TestBase { ...@@ -278,7 +278,7 @@ public class TestAuthentication extends TestBase {
} }
testExternalUser(); testExternalUser();
} }
static final String TESTXML="<h2Auth allowUserRegistration=\"true\" createMissingRoles=\"false\">" static final String TESTXML="<h2Auth allowUserRegistration=\"true\" createMissingRoles=\"false\">"
+ "<realm name=\"ciao\" validatorClass=\"myclass\"/>" + "<realm name=\"ciao\" validatorClass=\"myclass\"/>"
+ "<realm name=\"miao\" validatorClass=\"myclass1\">" + "<realm name=\"miao\" validatorClass=\"myclass1\">"
...@@ -288,7 +288,7 @@ public class TestAuthentication extends TestBase { ...@@ -288,7 +288,7 @@ public class TestAuthentication extends TestBase {
+ "</userToRolesMapper>" + "</userToRolesMapper>"
+ "</realm>" + "</realm>"
+ "</h2Auth>"; + "</h2Auth>";
protected void testXmlConfig() throws Exception { protected void testXmlConfig() throws Exception {
ByteArrayInputStream inputStream = new ByteArrayInputStream(TESTXML.getBytes()); ByteArrayInputStream inputStream = new ByteArrayInputStream(TESTXML.getBytes());
H2AuthConfig config = H2AuthConfigXml.parseFrom(inputStream); H2AuthConfig config = H2AuthConfigXml.parseFrom(inputStream);
......
...@@ -15,6 +15,8 @@ import java.io.OutputStream; ...@@ -15,6 +15,8 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import org.h2.test.TestBase;
import org.h2.test.utils.SelfDestructor; import org.h2.test.utils.SelfDestructor;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.util.Task; import org.h2.util.Task;
...@@ -48,7 +50,7 @@ public class TaskProcess { ...@@ -48,7 +50,7 @@ public class TaskProcess {
try { try {
String selfDestruct = SelfDestructor.getPropertyString(60); String selfDestruct = SelfDestructor.getPropertyString(60);
ArrayList<String> list = new ArrayList<>(); ArrayList<String> list = new ArrayList<>();
list.add("java"); list.add(TestBase.getJVM());
list.add(selfDestruct); list.add(selfDestruct);
list.add("-cp"); list.add("-cp");
list.add("bin" + File.pathSeparator + "."); list.add("bin" + File.pathSeparator + ".");
......
...@@ -37,7 +37,7 @@ public class TestRecoverKillLoop extends TestBase { ...@@ -37,7 +37,7 @@ public class TestRecoverKillLoop extends TestBase {
Random random = new Random(1); Random random = new Random(1);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
String[] procDef = { String[] procDef = {
"java", "-cp", getClassPath(), getJVM(), "-cp", getClassPath(),
"-Dtest.dir=data/db", "-Dtest.dir=data/db",
TestRecover.class.getName() TestRecover.class.getName()
}; };
......
...@@ -421,9 +421,9 @@ public class TestTransactionStore extends TestBase { ...@@ -421,9 +421,9 @@ public class TestTransactionStore extends TestBase {
} }
} }
private boolean hasDataUndoLog(MVStore s) { private static boolean hasDataUndoLog(MVStore s) {
for (int i = 0; i < 255; i++) { for (int i = 0; i < 255; i++) {
if(s.hasData(TransactionStore.getUndoLogName(true, 1))) { if (s.hasData(TransactionStore.getUndoLogName(true, 1))) {
return true; return true;
} }
} }
......
...@@ -226,7 +226,7 @@ public abstract class TestHalt extends TestBase { ...@@ -226,7 +226,7 @@ public abstract class TestHalt extends TestBase {
// String classPath = "-cp // String classPath = "-cp
// .;D:/data/java/hsqldb.jar;D:/data/java/derby.jar"; // .;D:/data/java/hsqldb.jar;D:/data/java/derby.jar";
String selfDestruct = SelfDestructor.getPropertyString(60); String selfDestruct = SelfDestructor.getPropertyString(60);
String[] procDef = { "java", selfDestruct, String[] procDef = { getJVM(), selfDestruct,
"-cp", getClassPath(), "-cp", getClassPath(),
getClass().getName(), "" + operations, "" + flags, "" + testValue}; getClass().getName(), "" + operations, "" + flags, "" + testValue};
traceOperation("start: " + StringUtils.arrayCombine(procDef, ' ')); traceOperation("start: " + StringUtils.arrayCombine(procDef, ' '));
......
...@@ -50,7 +50,7 @@ public class TestKill extends TestDb { ...@@ -50,7 +50,7 @@ public class TestKill extends TestDb {
String password = getPassword(); String password = getPassword();
String selfDestruct = SelfDestructor.getPropertyString(60); String selfDestruct = SelfDestructor.getPropertyString(60);
String[] procDef = { String[] procDef = {
"java", selfDestruct, getJVM(), selfDestruct,
"-cp", getClassPath(), "-cp", getClassPath(),
"org.h2.test.synth.TestKillProcess", url, user, "org.h2.test.synth.TestKillProcess", url, user,
password, getBaseDir(), "" + ACCOUNTS }; password, getBaseDir(), "" + ACCOUNTS };
......
...@@ -16,7 +16,6 @@ import java.sql.Statement; ...@@ -16,7 +16,6 @@ import java.sql.Statement;
import java.util.Random; import java.util.Random;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.h2.test.TestBase;
import org.h2.test.TestDb; import org.h2.test.TestDb;
import org.h2.test.utils.SelfDestructor; import org.h2.test.utils.SelfDestructor;
...@@ -40,7 +39,7 @@ public class TestKillRestart extends TestDb { ...@@ -40,7 +39,7 @@ public class TestKillRestart extends TestDb {
// "killRestart;CACHE_SIZE=2048;WRITE_DELAY=0", true); // "killRestart;CACHE_SIZE=2048;WRITE_DELAY=0", true);
String user = getUser(), password = getPassword(); String user = getUser(), password = getPassword();
String selfDestruct = SelfDestructor.getPropertyString(60); String selfDestruct = SelfDestructor.getPropertyString(60);
String[] procDef = { "java", selfDestruct, String[] procDef = { getJVM(), selfDestruct,
"-cp", getClassPath(), "-cp", getClassPath(),
getClass().getName(), "-url", url, "-user", user, getClass().getName(), "-url", url, "-user", user,
"-password", password }; "-password", password };
......
...@@ -83,7 +83,7 @@ public class TestKillRestartMulti extends TestDb { ...@@ -83,7 +83,7 @@ public class TestKillRestartMulti extends TestDb {
// Inherit error so that the stacktraces reported from SelfDestructor // Inherit error so that the stacktraces reported from SelfDestructor
// show up in our log. // show up in our log.
ProcessBuilder pb = new ProcessBuilder().redirectError(Redirect.INHERIT) ProcessBuilder pb = new ProcessBuilder().redirectError(Redirect.INHERIT)
.command("java", selfDestruct, "-cp", getClassPath(), .command(getJVM(), selfDestruct, "-cp", getClassPath(),
"-ea", "-ea",
getClass().getName(), "-url", url, "-user", user, getClass().getName(), "-url", url, "-user", user,
"-password", password); "-password", password);
......
...@@ -37,7 +37,7 @@ public class TestExit extends TestDb { ...@@ -37,7 +37,7 @@ public class TestExit extends TestDb {
deleteDb("exit"); deleteDb("exit");
String url = getURL(OPEN_WITH_CLOSE_ON_EXIT); String url = getURL(OPEN_WITH_CLOSE_ON_EXIT);
String selfDestruct = SelfDestructor.getPropertyString(60); String selfDestruct = SelfDestructor.getPropertyString(60);
String[] procDef = { "java", selfDestruct, "-cp", getClassPath(), String[] procDef = { getJVM(), selfDestruct, "-cp", getClassPath(),
getClass().getName(), url }; getClass().getName(), url };
Process proc = Runtime.getRuntime().exec(procDef); Process proc = Runtime.getRuntime().exec(procDef);
while (true) { while (true) {
...@@ -60,7 +60,7 @@ public class TestExit extends TestDb { ...@@ -60,7 +60,7 @@ public class TestExit extends TestDb {
fail("did not close database"); fail("did not close database");
} }
url = getURL(OPEN_WITHOUT_CLOSE_ON_EXIT); url = getURL(OPEN_WITHOUT_CLOSE_ON_EXIT);
procDef = new String[] { "java", "-cp", getClassPath(), procDef = new String[] { getJVM(), "-cp", getClassPath(),
getClass().getName(), url }; getClass().getName(), url };
proc = Runtime.getRuntime().exec(procDef); proc = Runtime.getRuntime().exec(procDef);
proc.waitFor(); proc.waitFor();
......
...@@ -74,7 +74,7 @@ public class TestFileLockProcess extends TestDb { ...@@ -74,7 +74,7 @@ public class TestFileLockProcess extends TestDb {
url = getURL(url, true); url = getURL(url, true);
Connection conn = getConnection(url); Connection conn = getConnection(url);
String selfDestruct = SelfDestructor.getPropertyString(60); String selfDestruct = SelfDestructor.getPropertyString(60);
String[] procDef = { "java", selfDestruct, String[] procDef = { getJVM(), selfDestruct,
"-cp", getClassPath(), "-cp", getClassPath(),
getClass().getName(), url }; getClass().getName(), url };
ArrayList<Process> processes = new ArrayList<>(count); ArrayList<Process> processes = new ArrayList<>(count);
......
...@@ -1013,6 +1013,10 @@ public class Build extends BuildBase { ...@@ -1013,6 +1013,10 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/slf4j-api-1.6.0.jar" + File.pathSeparator + "ext/slf4j-api-1.6.0.jar" +
File.pathSeparator + "ext/slf4j-nop-1.6.0.jar" + File.pathSeparator + "ext/slf4j-nop-1.6.0.jar" +
File.pathSeparator + javaToolsJar; File.pathSeparator + javaToolsJar;
int version = getJavaVersion();
if (version >= 9) {
cp = "src/java9/precompiled" + File.pathSeparator + cp;
}
int ret; int ret;
if (travis) { if (travis) {
ret = execJava(args( ret = execJava(args(
......
...@@ -925,6 +925,25 @@ public class BuildBase { ...@@ -925,6 +925,25 @@ public class BuildBase {
return System.getProperty("java.specification.version"); return System.getProperty("java.specification.version");
} }
/**
* Get the current Java version as integer value.
*
* @return the Java version (7, 8, 9, 10, 11, etc)
*/
protected static int getJavaVersion() {
int version = 7;
String v = getJavaSpecVersion();
if (v != null) {
int idx = v.indexOf('.');
if (idx >= 0) {
// 1.7, 1.8
v = v.substring(idx + 1);
}
version = Integer.parseInt(v);
}
return version;
}
private static List<String> getPaths(FileList files) { private static List<String> getPaths(FileList files) {
StringList list = new StringList(); StringList list = new StringList();
for (File f : files) { for (File f : files) {
......
...@@ -783,3 +783,4 @@ intentionally authenticator authrealm ventura credentials alessandro validator a ...@@ -783,3 +783,4 @@ intentionally authenticator authrealm ventura credentials alessandro validator a
ewkt ewkb informations authzpwd realms mappers jaxb realmname configurationfile unmarshal jaas externals customize ewkt ewkb informations authzpwd realms mappers jaxb realmname configurationfile unmarshal jaas externals customize
authenticators appname interrogate metatable barrier preliminary staticuser staticpassword unregistered inquiry authenticators appname interrogate metatable barrier preliminary staticuser staticpassword unregistered inquiry
ldapexample remoteuser assignments djava validators mock relate mapid tighten ldapexample remoteuser assignments djava validators mock relate mapid tighten
retried helpers unclean missed parsers sax myclass suppose mandatory testxml miao ciao
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论