从 Java 以编程方式导入 XML:项目已导入但返回的列表为空
Importing XMLs programmatically from Java: items are imported but the returned list is empty
这是一个示例 Java 代码,它尝试使用 %SYSTEM.OBJ
's LoadStream
method 导入 XML 导出中可用的 类; import
指令已被省略 "brevity":
public final class Main2
{
private static final String CACHEDB_HOST = "cachedb.host";
private static final String CACHEDB_PORT = "cachedb.port";
private static final String CACHEDB_USER = "cachedb.user";
private static final String CACHEDB_PASSWORD = "cachedb.password";
private static final String CACHEDB_NAMESPACE = "cachedb.namespace";
private static final String LOADEDFILE = "loadedFile";
private static final String CACHEDB_HOST_DEFAULT = "localhost";
private static final String CACHEDB_PORT_DEFAULT = "1972";
private static final String JDBC_URL_TEMPLATE = "jdbc:Cache://%s:%s/%s";
private Main2()
{
throw new Error("instantiation not permitted");
}
public static void main(final String... args)
throws IOException, CacheException
{
if (args.length == 0)
throw new IllegalArgumentException("missing arguments");
final Properties properties = new Properties();
final Path path = Paths.get(args[0]).toRealPath();
try (
final Reader reader = Files.newBufferedReader(path);
) {
properties.load(reader);
}
final String jdbcUrl = String.format(JDBC_URL_TEMPLATE,
readProperty(properties, CACHEDB_HOST, CACHEDB_HOST_DEFAULT),
readProperty(properties, CACHEDB_PORT, CACHEDB_PORT_DEFAULT),
readProperty(properties, CACHEDB_NAMESPACE));
final String user = readProperty(properties, CACHEDB_USER);
final String password = readProperty(properties, CACHEDB_PASSWORD);
final Path loadedFile = Paths.get(readProperty(properties, LOADEDFILE))
.toRealPath();
try (
final CacheDb db = new CacheDb(jdbcUrl, user, password);
) {
final GlobalCharacterStream stream
= new GlobalCharacterStream(db.getDatabase());
loadContent(stream, loadedFile);
/*
* Arguments for class "%SYSTEM.OBJ", class method "LoadStream"
*/
final Dataholder[] arguments = new Dataholder[8];
/*
* Arguments ByRef
*
* Indices start at 1, not 0
*/
final int[] byRefArgs = new int[2];
// Arg 3: error log
final StringHolder errorlog = new StringHolder("");
byRefArgs[0] = 3;
// Arg 4: list of loaded items
final StringHolder loadedlist = new StringHolder("");
byRefArgs[1] = 4;
/*
* Fill arguments
*/
// arg 1: stream
arguments[0] = Dataholder.create(stream);
// arg 2: qspec; the default, therefore null
arguments[1] = new Dataholder((String) null);
// arg 3: errorlog
arguments[2] = Dataholder.create(errorlog.value);
// arg 4: loadedlist
arguments[3] = Dataholder.create(loadedlist.value);
// arg 5: listonly; we want true
arguments[4] = Dataholder.create(Boolean.TRUE);
// arg 6: selecteditems; nothing
arguments[5] = Dataholder.create(null);
// arg 7: displayname. For logging...
arguments[6] = Dataholder.create("IMPORT");
// arg 8: charset. Default is empty string, we'll assume UTF-8.
arguments[7] = new Dataholder((String) null);
// Now, make the call
final Dataholder[] result = db.getDatabase().runClassMethod(
"%SYSTEM.OBJ",
"LoadStream",
byRefArgs,
arguments,
Database.RET_PRIM
);
/*
* The result normally has three members:
*
* - first is the status; and we need to do that:
*/
db.getDatabase().parseStatus(result[0]);
/*
* - others are ByRef arguments
*/
// FIXME: probably not ideal
errorlog.set(result[1].getString());
System.out.println("errorlog: " + errorlog.getValue());
loadedlist.set(result[2].getString());
System.out.println("loadedlist: " + loadedlist.getValue());
}
}
private static void loadContent(final GlobalCharacterStream stream,
final Path path)
throws IOException, CacheException
{
final StringBuilder sb = new StringBuilder();
try (
final Reader reader = Files.newBufferedReader(path);
) {
final char[] buf = new char[2048];
int nrChars;
while ((nrChars = reader.read(buf)) != -1)
sb.append(buf, 0, nrChars);
}
stream._write(sb.toString());
}
private static String readProperty(final Properties properties,
final String key)
{
final String ret = properties.getProperty(key);
if (ret == null)
throw new IllegalArgumentException("required property " + key
+ " is missing");
return ret;
}
private static String readProperty(final Properties properties,
final String key, final String defaultValue)
{
return properties.getProperty(key, defaultValue);
}
}
现在,代码运行了;在 Studio 中,我看到项目也已导入。
然而输出是这样的(缓存安装是法语的,抱歉):
Inventaire démarré le 02/12/2016 11:16:38
Classement du fichier IMPORT en tant que xml
Inventaire terminé.
errorlog:
loadedlist: null
我看不到导入了哪些项目。
我做错了什么?
Java 绑定支持获取 ByRef 值,你做对了。但不幸的是,有一个限制,您可以在这里找到它。使用 Caché 中的 ByRef 我们可以传递数组,如下所示
array("name1")="value1"
array("name2")="value2"
但是在Java中我们不能得到这样的值,只有当数组在"root"中有值时。 Load
方法同时,有将数组转换为值列表的代码,我们已经可以得到这样的值。因此,作为一种解决方法,我建议将 %GlobalCharacterStream
替换为 %FileCharacterStream
,并使用一些扩展名为 xml
的临时文件名。然后我们可以在 Load
方法中使用这个文件名。因此,经过一些更改后,代码应如下所示:
final FileCharacterStream stream = new FileCharacterStream(db);
Dataholder[] args = new Dataholder[]{new Dataholder("xml")};
Dataholder res = ((SysDatabase) db).runClassMethod("%File", "TempFilename", args, 0);
stream._filenameSet(res.getString());
loadContent(stream, path);
final String remoteFileName = stream._filenameGet();
/*
* Arguments for class "%SYSTEM.OBJ", class method "Load"
*/
final Dataholder[] arguments = new Dataholder[9];
/*
* Arguments ByRef
*
* Indices start at 1, not 0
*/
final int[] byRefArgs = new int[3];
// Arg 3: error log
final StringHolder errorlog = new StringHolder("");
byRefArgs[0] = 3;
// Arg 4: list of loaded items
final StringHolder loadedlist = new StringHolder("");
byRefArgs[1] = 4;
// Arg 9: description (?)
final StringHolder description = new StringHolder("");
byRefArgs[2] = 9;
/*
* Fill arguments
*/
// arg 1: file name
arguments[0] = Dataholder.create(remoteFileName);
// arg 2: qspec; we want to ensure that compile works, at least
arguments[1] = new Dataholder("d");
// arg 3: errorlog
arguments[2] = Dataholder.create(errorlog.value);
// arg 4: loadedlist
arguments[3] = Dataholder.create(loadedlist.value);
// arg 5: listonly; no
arguments[4] = Dataholder.create(Boolean.FALSE);
// arg 6: selecteditems; nothing
arguments[5] = Dataholder.create(null);
// arg 7: displayname. For logging...
arguments[6] = Dataholder.create("IMPORT.xml");
// arg 8: charset. Default is empty string, we'll assume UTF-8.
arguments[7] = new Dataholder((String) null);
// arg 9: description (?)
arguments[8] = Dataholder.create(description.value);
// Now, make the call
final Dataholder[] result = db.runClassMethod(
"%SYSTEM.OBJ",
"Load",
byRefArgs,
arguments,
Database.RET_PRIM
);
/*
* The result normally has three members:
*
* - first is the status; and we need to do that:
*/
db.parseStatus(result[0]);
/*
* - others are ByRef arguments
*/
errorlog.set(result[1].getString());
System.out.println("errorlog: " + errorlog.getValue());
loadedlist.set(result[2].getString());
System.out.println("loadedlist: " + loadedlist.getValue());
结果
Load started on 02/12/2016 22:56:06
Loading file IMPORT.xml as xml
Imported class: Sample.Address
Imported class: Sample.Person
Load finished successfully.
errorlog:
loadedlist: Sample.Address.cls,Sample.Person.cls
这是一个示例 Java 代码,它尝试使用 %SYSTEM.OBJ
's LoadStream
method 导入 XML 导出中可用的 类; import
指令已被省略 "brevity":
public final class Main2
{
private static final String CACHEDB_HOST = "cachedb.host";
private static final String CACHEDB_PORT = "cachedb.port";
private static final String CACHEDB_USER = "cachedb.user";
private static final String CACHEDB_PASSWORD = "cachedb.password";
private static final String CACHEDB_NAMESPACE = "cachedb.namespace";
private static final String LOADEDFILE = "loadedFile";
private static final String CACHEDB_HOST_DEFAULT = "localhost";
private static final String CACHEDB_PORT_DEFAULT = "1972";
private static final String JDBC_URL_TEMPLATE = "jdbc:Cache://%s:%s/%s";
private Main2()
{
throw new Error("instantiation not permitted");
}
public static void main(final String... args)
throws IOException, CacheException
{
if (args.length == 0)
throw new IllegalArgumentException("missing arguments");
final Properties properties = new Properties();
final Path path = Paths.get(args[0]).toRealPath();
try (
final Reader reader = Files.newBufferedReader(path);
) {
properties.load(reader);
}
final String jdbcUrl = String.format(JDBC_URL_TEMPLATE,
readProperty(properties, CACHEDB_HOST, CACHEDB_HOST_DEFAULT),
readProperty(properties, CACHEDB_PORT, CACHEDB_PORT_DEFAULT),
readProperty(properties, CACHEDB_NAMESPACE));
final String user = readProperty(properties, CACHEDB_USER);
final String password = readProperty(properties, CACHEDB_PASSWORD);
final Path loadedFile = Paths.get(readProperty(properties, LOADEDFILE))
.toRealPath();
try (
final CacheDb db = new CacheDb(jdbcUrl, user, password);
) {
final GlobalCharacterStream stream
= new GlobalCharacterStream(db.getDatabase());
loadContent(stream, loadedFile);
/*
* Arguments for class "%SYSTEM.OBJ", class method "LoadStream"
*/
final Dataholder[] arguments = new Dataholder[8];
/*
* Arguments ByRef
*
* Indices start at 1, not 0
*/
final int[] byRefArgs = new int[2];
// Arg 3: error log
final StringHolder errorlog = new StringHolder("");
byRefArgs[0] = 3;
// Arg 4: list of loaded items
final StringHolder loadedlist = new StringHolder("");
byRefArgs[1] = 4;
/*
* Fill arguments
*/
// arg 1: stream
arguments[0] = Dataholder.create(stream);
// arg 2: qspec; the default, therefore null
arguments[1] = new Dataholder((String) null);
// arg 3: errorlog
arguments[2] = Dataholder.create(errorlog.value);
// arg 4: loadedlist
arguments[3] = Dataholder.create(loadedlist.value);
// arg 5: listonly; we want true
arguments[4] = Dataholder.create(Boolean.TRUE);
// arg 6: selecteditems; nothing
arguments[5] = Dataholder.create(null);
// arg 7: displayname. For logging...
arguments[6] = Dataholder.create("IMPORT");
// arg 8: charset. Default is empty string, we'll assume UTF-8.
arguments[7] = new Dataholder((String) null);
// Now, make the call
final Dataholder[] result = db.getDatabase().runClassMethod(
"%SYSTEM.OBJ",
"LoadStream",
byRefArgs,
arguments,
Database.RET_PRIM
);
/*
* The result normally has three members:
*
* - first is the status; and we need to do that:
*/
db.getDatabase().parseStatus(result[0]);
/*
* - others are ByRef arguments
*/
// FIXME: probably not ideal
errorlog.set(result[1].getString());
System.out.println("errorlog: " + errorlog.getValue());
loadedlist.set(result[2].getString());
System.out.println("loadedlist: " + loadedlist.getValue());
}
}
private static void loadContent(final GlobalCharacterStream stream,
final Path path)
throws IOException, CacheException
{
final StringBuilder sb = new StringBuilder();
try (
final Reader reader = Files.newBufferedReader(path);
) {
final char[] buf = new char[2048];
int nrChars;
while ((nrChars = reader.read(buf)) != -1)
sb.append(buf, 0, nrChars);
}
stream._write(sb.toString());
}
private static String readProperty(final Properties properties,
final String key)
{
final String ret = properties.getProperty(key);
if (ret == null)
throw new IllegalArgumentException("required property " + key
+ " is missing");
return ret;
}
private static String readProperty(final Properties properties,
final String key, final String defaultValue)
{
return properties.getProperty(key, defaultValue);
}
}
现在,代码运行了;在 Studio 中,我看到项目也已导入。
然而输出是这样的(缓存安装是法语的,抱歉):
Inventaire démarré le 02/12/2016 11:16:38
Classement du fichier IMPORT en tant que xml
Inventaire terminé.
errorlog:
loadedlist: null
我看不到导入了哪些项目。
我做错了什么?
Java 绑定支持获取 ByRef 值,你做对了。但不幸的是,有一个限制,您可以在这里找到它。使用 Caché 中的 ByRef 我们可以传递数组,如下所示
array("name1")="value1"
array("name2")="value2"
但是在Java中我们不能得到这样的值,只有当数组在"root"中有值时。 Load
方法同时,有将数组转换为值列表的代码,我们已经可以得到这样的值。因此,作为一种解决方法,我建议将 %GlobalCharacterStream
替换为 %FileCharacterStream
,并使用一些扩展名为 xml
的临时文件名。然后我们可以在 Load
方法中使用这个文件名。因此,经过一些更改后,代码应如下所示:
final FileCharacterStream stream = new FileCharacterStream(db);
Dataholder[] args = new Dataholder[]{new Dataholder("xml")};
Dataholder res = ((SysDatabase) db).runClassMethod("%File", "TempFilename", args, 0);
stream._filenameSet(res.getString());
loadContent(stream, path);
final String remoteFileName = stream._filenameGet();
/*
* Arguments for class "%SYSTEM.OBJ", class method "Load"
*/
final Dataholder[] arguments = new Dataholder[9];
/*
* Arguments ByRef
*
* Indices start at 1, not 0
*/
final int[] byRefArgs = new int[3];
// Arg 3: error log
final StringHolder errorlog = new StringHolder("");
byRefArgs[0] = 3;
// Arg 4: list of loaded items
final StringHolder loadedlist = new StringHolder("");
byRefArgs[1] = 4;
// Arg 9: description (?)
final StringHolder description = new StringHolder("");
byRefArgs[2] = 9;
/*
* Fill arguments
*/
// arg 1: file name
arguments[0] = Dataholder.create(remoteFileName);
// arg 2: qspec; we want to ensure that compile works, at least
arguments[1] = new Dataholder("d");
// arg 3: errorlog
arguments[2] = Dataholder.create(errorlog.value);
// arg 4: loadedlist
arguments[3] = Dataholder.create(loadedlist.value);
// arg 5: listonly; no
arguments[4] = Dataholder.create(Boolean.FALSE);
// arg 6: selecteditems; nothing
arguments[5] = Dataholder.create(null);
// arg 7: displayname. For logging...
arguments[6] = Dataholder.create("IMPORT.xml");
// arg 8: charset. Default is empty string, we'll assume UTF-8.
arguments[7] = new Dataholder((String) null);
// arg 9: description (?)
arguments[8] = Dataholder.create(description.value);
// Now, make the call
final Dataholder[] result = db.runClassMethod(
"%SYSTEM.OBJ",
"Load",
byRefArgs,
arguments,
Database.RET_PRIM
);
/*
* The result normally has three members:
*
* - first is the status; and we need to do that:
*/
db.parseStatus(result[0]);
/*
* - others are ByRef arguments
*/
errorlog.set(result[1].getString());
System.out.println("errorlog: " + errorlog.getValue());
loadedlist.set(result[2].getString());
System.out.println("loadedlist: " + loadedlist.getValue());
结果
Load started on 02/12/2016 22:56:06
Loading file IMPORT.xml as xml
Imported class: Sample.Address
Imported class: Sample.Person
Load finished successfully.
errorlog:
loadedlist: Sample.Address.cls,Sample.Person.cls