mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-20 21:53:12 +00:00
Move jni interface classes from batphone repo
This commit is contained in:
parent
37e4d65b2a
commit
99fb8b6108
@ -46,7 +46,7 @@ LOCAL_SRC_FILES:= $(SERVALD_SRC_FILES) $(SERVAL_BASE)version_servald.c
|
||||
LOCAL_CFLAGS += $(SERVALD_LOCAL_CFLAGS) -Iserval-dna/nacl/include
|
||||
LOCAL_LDLIBS := $(SERVALD_LOCAL_LDLIBS)
|
||||
LOCAL_STATIC_LIBRARIES := $(SERVALD_LOCAL_STATIC_LIBRARIES)
|
||||
LOCAL_MODULE:= serval
|
||||
LOCAL_MODULE:= servald
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# Build libserval.so wrapper
|
||||
|
@ -169,16 +169,16 @@ int Throw(JNIEnv *env, const char *class, const char *msg)
|
||||
/* JNI entry point to command line. See org.servalproject.servald.ServalD class for the Java side.
|
||||
JNI method descriptor: "(Ljava/util/List;[Ljava/lang/String;)I"
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_org_servalproject_servald_ServalD_rawCommand(JNIEnv *env, jobject UNUSED(this), jobject outv, jobjectArray args)
|
||||
JNIEXPORT jint JNICALL Java_org_servalproject_servaldna_ServalDCommand_rawCommand(JNIEnv *env, jobject UNUSED(this), jobject outv, jobjectArray args)
|
||||
{
|
||||
struct cli_context context;
|
||||
bzero(&context, sizeof(context));
|
||||
|
||||
// find jni results methods
|
||||
if (!IJniResults){
|
||||
IJniResults = (*env)->FindClass(env, "org/servalproject/servald/IJniResults");
|
||||
IJniResults = (*env)->FindClass(env, "org/servalproject/servaldna/IJniResults");
|
||||
if (IJniResults==NULL)
|
||||
return Throw(env, "java/lang/IllegalStateException", "Unable to locate class org.servalproject.servald.IJniResults");
|
||||
return Throw(env, "java/lang/IllegalStateException", "Unable to locate class org.servalproject.servaldna.IJniResults");
|
||||
startResultSet = (*env)->GetMethodID(env, IJniResults, "startResultSet", "(I)V");
|
||||
if (startResultSet==NULL)
|
||||
return Throw(env, "java/lang/IllegalStateException", "Unable to locate method startResultSet");
|
||||
|
@ -1,56 +0,0 @@
|
||||
package org.servalproject.servald;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
import org.servalproject.servald.ServalD;
|
||||
|
||||
class ServalDTests
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try {
|
||||
Method m = ServalDTests.class.getMethod(args[0], String[].class);
|
||||
m.invoke(null, (Object) Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public static void repeat(String[] args)
|
||||
{
|
||||
int repeat = Integer.decode(args[0]);
|
||||
ServalD servald = new ServalD();
|
||||
for (int i = 0; i != repeat; ++i) {
|
||||
servald.command(Arrays.copyOfRange(args, 1, args.length));
|
||||
System.out.print(servald.status);
|
||||
for (byte[] a: servald.outv) {
|
||||
System.out.print(":");
|
||||
System.out.print(new String(a));
|
||||
}
|
||||
System.out.println("");
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public static void nullArg(String[] args)
|
||||
{
|
||||
ServalD servald = new ServalD();
|
||||
for (int i = 0; i != args.length; ++i)
|
||||
if ("(null)".equals(args[i]))
|
||||
args[i] = null;
|
||||
servald.command(Arrays.copyOfRange(args, 0, args.length));
|
||||
System.out.print(servald.status);
|
||||
for (byte[] a: servald.outv) {
|
||||
System.out.print(":");
|
||||
System.out.print(new String(a));
|
||||
}
|
||||
System.out.println("");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
}
|
126
java/org/servalproject/servaldna/AbstractId.java
Normal file
126
java/org/servalproject/servaldna/AbstractId.java
Normal file
@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Copyright (C) 2011 The Serval Project
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public abstract class AbstractId {
|
||||
|
||||
abstract int getBinarySize();
|
||||
|
||||
public static class InvalidHexException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private InvalidHexException(AbstractId id, String message) {
|
||||
super(id.getClass().getName() + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InvalidBinaryException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private InvalidBinaryException(AbstractId id, String message) {
|
||||
super(id.getClass().getName() + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
private final byte[] binary;
|
||||
|
||||
public AbstractId(String hex) throws InvalidHexException {
|
||||
if (hex.length() != getBinarySize())
|
||||
throw new InvalidHexException(this, "invalid length " + hex.length() + " (should be " + (getBinarySize() * 2) + ") of '" + hex + "'");
|
||||
binary = new byte[getBinarySize()];
|
||||
int j = 0;
|
||||
for (int i = 0; i != binary.length; i++) {
|
||||
int d1 = Character.digit(hex.charAt(j++), 16);
|
||||
int d2 = Character.digit(hex.charAt(j++), 16);
|
||||
if (d1 == -1 || d2 == -1)
|
||||
throw new InvalidHexException(this, "non-hex digit in '" + hex + "'");
|
||||
binary[i] = (byte) ((d1 << 4) | d2);
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractId(ByteBuffer b) throws InvalidBinaryException {
|
||||
this.binary = new byte[getBinarySize()];
|
||||
try {
|
||||
b.get(this.binary);
|
||||
}
|
||||
catch (BufferUnderflowException e) {
|
||||
throw new InvalidBinaryException(this, "not enough bytes (expecting " + getBinarySize() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractId(byte[] binary) throws InvalidBinaryException {
|
||||
if (binary.length != getBinarySize())
|
||||
throw new InvalidBinaryException(this, "invalid number of bytes (" + binary.length + "), should be " + getBinarySize());
|
||||
this.binary = binary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
// must be the exact same type with the same binary contents to be considered equal
|
||||
if (other.getClass() == this.getClass()) {
|
||||
AbstractId oBinary = (AbstractId) other;
|
||||
for (int i = 0; i < this.binary.length; i++)
|
||||
if (this.binary[i] != oBinary.binary[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = 0;
|
||||
for (int i = 0; i < this.binary.length; i++)
|
||||
hashCode = (hashCode << 8 | hashCode >>> 24) ^ this.binary[i];
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public String toHex(int offset, int len) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = offset; i < offset + len && i < binary.length; i++) {
|
||||
sb.append(Character.forDigit(((binary[i]) & 0xf0) >> 4, 16));
|
||||
sb.append(Character.forDigit((binary[i]) & 0x0f, 16));
|
||||
}
|
||||
return sb.toString().toUpperCase();
|
||||
}
|
||||
|
||||
public String toHex(int len) {
|
||||
return toHex(0, len);
|
||||
}
|
||||
|
||||
public String toHex() {
|
||||
return toHex(0, binary.length);
|
||||
}
|
||||
|
||||
public String abbreviation() {
|
||||
return toHex(0, 4);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toHex();
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.servalproject.servald;
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
public abstract class AbstractJniResults implements IJniResults {
|
||||
|
@ -18,39 +18,27 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servald;
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.LinkedList;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
class ServalD
|
||||
{
|
||||
int status;
|
||||
List<byte[]> outv;
|
||||
public class BundleId extends AbstractId {
|
||||
|
||||
static
|
||||
{
|
||||
String property = System.getProperty("java.library.path");
|
||||
System.err.println("Attempting to load libservald.so from "+property);
|
||||
System.loadLibrary("servald");
|
||||
@Override
|
||||
public int getBinarySize() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
private static native int rawCommand(IJniResults outv, String[] args);
|
||||
|
||||
public void command(String... args)
|
||||
{
|
||||
this.outv = new LinkedList<byte[]>();
|
||||
IJniResults results = new JniResultsList(outv);
|
||||
this.status = this.rawCommand(results, args);
|
||||
public BundleId(String hex) throws InvalidHexException {
|
||||
super(hex);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
ServalD servald = new ServalD();
|
||||
servald.command(args);
|
||||
for (byte[] a: servald.outv) {
|
||||
System.out.println(new String(a));
|
||||
}
|
||||
System.exit(servald.status);
|
||||
public BundleId(ByteBuffer b) throws InvalidBinaryException {
|
||||
super(b);
|
||||
}
|
||||
|
||||
public BundleId(byte[] binary) throws InvalidBinaryException {
|
||||
super(binary);
|
||||
}
|
||||
|
||||
}
|
44
java/org/servalproject/servaldna/BundleKey.java
Normal file
44
java/org/servalproject/servaldna/BundleKey.java
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (C) 2011 The Serval Project
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class BundleKey extends AbstractId {
|
||||
|
||||
@Override
|
||||
public int getBinarySize() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
public BundleKey(String hex) throws InvalidHexException {
|
||||
super(hex);
|
||||
}
|
||||
|
||||
public BundleKey(ByteBuffer b) throws InvalidBinaryException {
|
||||
super(b);
|
||||
}
|
||||
|
||||
public BundleKey(byte[] binary) throws InvalidBinaryException {
|
||||
super(binary);
|
||||
}
|
||||
|
||||
}
|
46
java/org/servalproject/servaldna/FileHash.java
Normal file
46
java/org/servalproject/servaldna/FileHash.java
Normal file
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (C) 2012 Serval Project, Inc.
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class FileHash extends AbstractId {
|
||||
|
||||
public static final int BINARY_SIZE = 64;
|
||||
|
||||
@Override
|
||||
public int getBinarySize() {
|
||||
return BINARY_SIZE;
|
||||
}
|
||||
|
||||
public FileHash(String hex) throws InvalidHexException {
|
||||
super(hex);
|
||||
}
|
||||
|
||||
public FileHash(ByteBuffer b) throws InvalidBinaryException {
|
||||
super(b);
|
||||
}
|
||||
|
||||
public FileHash(byte[] binary) throws InvalidBinaryException {
|
||||
super(binary);
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.servalproject.servald;
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
public interface IJniResults {
|
||||
public void startResultSet(int columns);
|
@ -1,11 +1,11 @@
|
||||
package org.servalproject.servald;
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JniResultsList extends AbstractJniResults implements IJniResults {
|
||||
final List<byte[]> list;
|
||||
private byte[] empty = new byte[0];
|
||||
JniResultsList(List<byte[]> list) {
|
||||
public JniResultsList(List<byte[]> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
92
java/org/servalproject/servaldna/ServalDCommand.java
Normal file
92
java/org/servalproject/servaldna/ServalDCommand.java
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (C) 2011 The Serval Project
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class ServalDCommand
|
||||
{
|
||||
private ServalDCommand(){
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
System.loadLibrary("servald");
|
||||
}
|
||||
|
||||
/**
|
||||
* Low-level JNI entry point into servald command line.
|
||||
*
|
||||
* @param results Interface that will receive each value from the command
|
||||
* @param args The words to pass on the command line (ie, argv[1]...argv[n])
|
||||
* @return The servald exit status code (normally 0 indicates success)
|
||||
*/
|
||||
private static native int rawCommand(IJniResults results, String[] args)
|
||||
throws ServalDInterfaceError;
|
||||
|
||||
/**
|
||||
* Common entry point into servald command line.
|
||||
*
|
||||
* @param callback
|
||||
* Each result will be passed to callback.result(String)
|
||||
* immediately.
|
||||
* @param args
|
||||
* The parameters as passed on the command line, eg: res =
|
||||
* servald.command("config", "set", "debug", "peers");
|
||||
* @return The servald exit status code (normally0 indicates success)
|
||||
*/
|
||||
public static synchronized int command(final IJniResults callback, String... args)
|
||||
throws ServalDInterfaceError
|
||||
{
|
||||
return ServalDCommand.rawCommand(callback, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Common entry point into servald command line.
|
||||
*
|
||||
* @param args
|
||||
* The parameters as passed on the command line, eg: res =
|
||||
* servald.command("config", "set", "debug", "peers");
|
||||
* @return An object containing the servald exit status code (normally0
|
||||
* indicates success) and zero or more output fields that it would
|
||||
* have sent to standard output if invoked via a shell command line.
|
||||
*/
|
||||
|
||||
public static synchronized ServalDResult command(String... args)
|
||||
throws ServalDInterfaceError
|
||||
{
|
||||
LinkedList<byte[]> results = new LinkedList<byte[]>();
|
||||
int status = rawCommand(new JniResultsList(results), args);
|
||||
return new ServalDResult(args, status, results.toArray(new byte[results.size()][]));
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
LinkedList<byte[]> outv = new LinkedList<byte[]>();
|
||||
IJniResults results = new JniResultsList(outv);
|
||||
int status = rawCommand(results, args);
|
||||
for (byte[] a: outv) {
|
||||
System.out.println(new String(a));
|
||||
}
|
||||
System.exit(status);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (C) 2011 The Serval Project
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import org.servalproject.servaldna.ServalDResult;
|
||||
|
||||
/**
|
||||
* Thrown when a request to a servald JNI method fails. This typically means that the returned
|
||||
* status is non-zero, or some other result was returned that indicated the operation failed.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
public class ServalDFailureException extends Exception
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ServalDFailureException(String message, ServalDResult result) {
|
||||
super(message + " for command: " + result.getCommandString());
|
||||
}
|
||||
|
||||
public ServalDFailureException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
48
java/org/servalproject/servaldna/ServalDInterfaceError.java
Normal file
48
java/org/servalproject/servaldna/ServalDInterfaceError.java
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Copyright (C) 2011 The Serval Project
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
/**
|
||||
* Indicates an internal (coding) error in the JNI interface to servald. Typically encountered when
|
||||
* unpacking the outv strings returned by a servald operation, and indicates that the C code in
|
||||
* servald that constructs the outv array is not consistent with the Java code that unpacks the outv
|
||||
* strings.
|
||||
*/
|
||||
public class ServalDInterfaceError extends Error
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ServalDInterfaceError(String message, ServalDResult result) {
|
||||
super(message + ": " + result);
|
||||
}
|
||||
|
||||
public ServalDInterfaceError(String message, ServalDResult result, Throwable cause) {
|
||||
super(message + ": " + result, cause);
|
||||
}
|
||||
|
||||
public ServalDInterfaceError(ServalDResult result, Throwable cause) {
|
||||
super("" + result, cause);
|
||||
}
|
||||
|
||||
public ServalDInterfaceError(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
217
java/org/servalproject/servaldna/ServalDResult.java
Normal file
217
java/org/servalproject/servaldna/ServalDResult.java
Normal file
@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Copyright (C) 2011 The Serval Project
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** Represents the result of invoking servald via the JNI command-line interface. The 'args'
|
||||
* attribute contains a copy of the arguments that were passed to the call that produced this
|
||||
* result, to facilitate diagnosis of failures and errors. The results of a call are an integer
|
||||
* 'status' value (normally the process exit status) and a list of strings in 'outv', called "output
|
||||
* fields". These strings must be interpreted depending on the operation that produced them.
|
||||
*
|
||||
* Many operations return information about their outcome as a sequence of key-value pairs of
|
||||
* fields. The getField() method and variants offer an order-independent means to query these
|
||||
* fields by key and optionally enforce a type on the value. If the operation produces output
|
||||
* that is not in the key-value structure, then the caller simply avoids using these methods,
|
||||
* and accesses the 'outv' array directly.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
public class ServalDResult
|
||||
{
|
||||
public static final int STATUS_ERROR = 255;
|
||||
|
||||
public final String[] args;
|
||||
public final int status;
|
||||
public final byte[][] outv;
|
||||
private HashMap<String,byte[]> keyValue;
|
||||
|
||||
public ServalDResult(String[] args, int status, byte[][] outv) {
|
||||
this.args = args;
|
||||
this.status = status;
|
||||
this.outv = outv;
|
||||
this.keyValue = null;
|
||||
}
|
||||
|
||||
public ServalDResult(ServalDResult orig) {
|
||||
this.args = orig.args;
|
||||
this.status = orig.status;
|
||||
this.outv = orig.outv;
|
||||
this.keyValue = orig.keyValue;
|
||||
}
|
||||
|
||||
public String getCommandString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
if (i > 0)
|
||||
sb.append(' ');
|
||||
sb.append(args[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
String[] outvstr = new String[this.outv.length];
|
||||
for (int i = 0; i != this.outv.length; ++i)
|
||||
outvstr[i] = new String(this.outv[i]);
|
||||
return this.getClass().getName() + "(args=" + Arrays.deepToString(this.args) + ", status=" + this.status + ", outv=" + Arrays.deepToString(outvstr) + ")";
|
||||
}
|
||||
|
||||
public void failIfStatusError() throws ServalDFailureException {
|
||||
if (this.status == STATUS_ERROR)
|
||||
throw new ServalDFailureException("error exit status", this);
|
||||
}
|
||||
|
||||
public void failIfStatusNonzero() throws ServalDFailureException {
|
||||
if (this.status != 0)
|
||||
throw new ServalDFailureException("non-zero exit status", this);
|
||||
}
|
||||
|
||||
protected void makeKeyValueMap() {
|
||||
if (this.keyValue == null) {
|
||||
if (this.outv.length % 2 != 0)
|
||||
throw new ServalDInterfaceError("odd number of fields", this);
|
||||
this.keyValue = new HashMap<String,byte[]>();
|
||||
for (int i = 0; i != this.outv.length; i += 2)
|
||||
this.keyValue.put(new String(this.outv[i]), this.outv[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String,byte[]> getKeyValueMap() {
|
||||
makeKeyValueMap();
|
||||
return new HashMap<String,byte[]>(this.keyValue);
|
||||
}
|
||||
|
||||
protected byte[] getFieldOrNull(String fieldName) {
|
||||
makeKeyValueMap();
|
||||
if (!this.keyValue.containsKey(fieldName))
|
||||
return null;
|
||||
return this.keyValue.get(fieldName);
|
||||
}
|
||||
|
||||
protected byte[] getField(String fieldName) throws ServalDInterfaceError {
|
||||
byte[] value = getFieldOrNull(fieldName);
|
||||
if (value == null)
|
||||
throw new ServalDInterfaceError("missing '" + fieldName + "' field", this);
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte[] getFieldByteArray(String fieldName, byte[] defaultValue) {
|
||||
byte[] value = getFieldOrNull(fieldName);
|
||||
if (value == null)
|
||||
return defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getFieldString(String fieldName, String defaultValue) {
|
||||
byte[] value = getFieldOrNull(fieldName);
|
||||
if (value == null)
|
||||
return defaultValue;
|
||||
return new String(value);
|
||||
}
|
||||
|
||||
public String getFieldString(String fieldName) throws ServalDInterfaceError {
|
||||
return new String(getField(fieldName));
|
||||
}
|
||||
|
||||
public String getFieldStringNonEmptyOrNull(String fieldName) throws ServalDInterfaceError {
|
||||
String value = getFieldString(fieldName, "");
|
||||
return value.length() == 0 ? null : value;
|
||||
}
|
||||
|
||||
public long getFieldLong(String fieldName) throws ServalDInterfaceError {
|
||||
String value = getFieldString(fieldName);
|
||||
try {
|
||||
return Long.valueOf(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not of type long", this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getFieldInt(String fieldName) throws ServalDInterfaceError {
|
||||
String value = getFieldString(fieldName);
|
||||
try {
|
||||
return Integer.valueOf(value);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not of type int", this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getFieldBoolean(String fieldName) throws ServalDInterfaceError {
|
||||
String value = getFieldString(fieldName);
|
||||
try {
|
||||
if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes") || value.equalsIgnoreCase("on"))
|
||||
return true;
|
||||
if (value.equalsIgnoreCase("false") || value.equalsIgnoreCase("no") || value.equalsIgnoreCase("off"))
|
||||
return false;
|
||||
return Integer.parseInt(value) != 0;
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not of type boolean", this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public SubscriberId getFieldSubscriberId(String fieldName, SubscriberId defaultValue) throws ServalDInterfaceError {
|
||||
byte[] value = getFieldOrNull(fieldName);
|
||||
if (value == null)
|
||||
return defaultValue;
|
||||
String str = new String(value);
|
||||
try {
|
||||
return new SubscriberId(str);
|
||||
}
|
||||
catch (AbstractId.InvalidHexException e) {
|
||||
throw new ServalDInterfaceError("field " + fieldName + "='" + str + "' is not a Bundle ID: " + e.getMessage(), this);
|
||||
}
|
||||
}
|
||||
|
||||
public SubscriberId getFieldSubscriberId(String fieldName) throws ServalDInterfaceError {
|
||||
SubscriberId value = getFieldSubscriberId(fieldName, null);
|
||||
if (value == null)
|
||||
throw new ServalDInterfaceError("missing '" + fieldName + "' field", this);
|
||||
return value;
|
||||
}
|
||||
|
||||
public BundleId getFieldBundleId(String fieldName) throws ServalDInterfaceError {
|
||||
String value = getFieldString(fieldName);
|
||||
try {
|
||||
return new BundleId(value);
|
||||
}
|
||||
catch (BundleId.InvalidHexException e) {
|
||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not a Bundle ID: " + e.getMessage(), this, e);
|
||||
}
|
||||
}
|
||||
|
||||
public FileHash getFieldFileHash(String fieldName) throws ServalDInterfaceError {
|
||||
String value = getFieldString(fieldName);
|
||||
try {
|
||||
return new FileHash(value);
|
||||
}
|
||||
catch (BundleId.InvalidHexException e) {
|
||||
throw new ServalDInterfaceError("field " + fieldName + "='" + value + "' is not a file hash: " + e.getMessage(), this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
72
java/org/servalproject/servaldna/SubscriberId.java
Normal file
72
java/org/servalproject/servaldna/SubscriberId.java
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (C) 2012 Serval Project, Inc.
|
||||
*
|
||||
* This file is part of Serval Software (http://www.servalproject.org)
|
||||
*
|
||||
* Serval Software is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This source code is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this source code; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package org.servalproject.servaldna;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class SubscriberId extends AbstractId {
|
||||
|
||||
public static final int BINARY_SIZE = 32;
|
||||
|
||||
@Override
|
||||
public int getBinarySize() {
|
||||
return BINARY_SIZE;
|
||||
}
|
||||
|
||||
public SubscriberId(String hex) throws InvalidHexException {
|
||||
super(hex);
|
||||
}
|
||||
|
||||
public SubscriberId(ByteBuffer b) throws InvalidBinaryException {
|
||||
super(b);
|
||||
}
|
||||
|
||||
public SubscriberId(byte[] binary) throws InvalidBinaryException {
|
||||
super(binary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String abbreviation() {
|
||||
return "sid:" + toHex(6) + "*";
|
||||
}
|
||||
|
||||
/** Return true iff this SID is a broadcast address.
|
||||
*
|
||||
* At the moment, a broadcast address is defined as one whose bits are all 1 except
|
||||
* for the final 64 bits, which could be anything. This definition may change in
|
||||
* future, so treat this code with a grain of salt.
|
||||
*/
|
||||
public boolean isBroadcast() {
|
||||
return this.equals(broadcastSid);
|
||||
}
|
||||
|
||||
public static SubscriberId broadcastSid;
|
||||
static {
|
||||
byte buff[] = new byte[BINARY_SIZE];
|
||||
for (int i = 0; i < BINARY_SIZE; i++)
|
||||
buff[i] = (byte) 0xff;
|
||||
try {
|
||||
broadcastSid = new SubscriberId(buff);
|
||||
} catch (InvalidBinaryException e) {
|
||||
// TODO log error?
|
||||
}
|
||||
}
|
||||
}
|
42
java/org/servalproject/test/ServalDTests.java
Normal file
42
java/org/servalproject/test/ServalDTests.java
Normal file
@ -0,0 +1,42 @@
|
||||
package org.servalproject.test;
|
||||
|
||||
import org.servalproject.servaldna.ServalDCommand;
|
||||
import org.servalproject.servaldna.ServalDResult;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
class ServalDTests
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try {
|
||||
for (int i = 0; i != args.length; ++i)
|
||||
if ("(null)".equals(args[i]))
|
||||
args[i] = null;
|
||||
|
||||
int repeatCount=1;
|
||||
|
||||
if (args[0].equals("repeat")){
|
||||
repeatCount = Integer.decode(args[1]);
|
||||
args = Arrays.copyOfRange(args, 2, args.length);
|
||||
}
|
||||
|
||||
while(repeatCount>0){
|
||||
ServalDResult result = ServalDCommand.command(args);
|
||||
System.out.print(result.status);
|
||||
for (byte[] a: result.outv) {
|
||||
System.out.print(":");
|
||||
System.out.print(new String(a));
|
||||
}
|
||||
System.out.println("");
|
||||
|
||||
repeatCount--;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
20
tests/jni
20
tests/jni
@ -24,7 +24,9 @@ source "${0%/*}/../testconfig.sh"
|
||||
|
||||
setup() {
|
||||
setup_servald
|
||||
executeOk_servald config set debug.verbose 1
|
||||
executeOk_servald config \
|
||||
set debug.verbose 1 \
|
||||
set log.console.level debug
|
||||
assert_echo_works
|
||||
compile_java_classes
|
||||
setup_servald_so
|
||||
@ -33,10 +35,10 @@ setup() {
|
||||
compile_java_classes() {
|
||||
assert --message='Java compiler was detected by ./configure' [ "$JAVAC" ]
|
||||
mkdir classes
|
||||
assert $JAVAC -Xlint:unchecked -d classes "$servald_source_root"/java/org/servalproject/servald/*.java
|
||||
assert [ -r classes/org/servalproject/servald/ServalD.class ]
|
||||
assert [ -r classes/org/servalproject/servald/IJniResults.class ]
|
||||
assert [ -r classes/org/servalproject/servald/ServalDTests.class ]
|
||||
assert find "$servald_source_root"/java/ -name *.java | xargs $JAVAC -Xlint:unchecked -d classes
|
||||
assert [ -r classes/org/servalproject/servaldna/ServalDCommand.class ]
|
||||
assert [ -r classes/org/servalproject/servaldna/IJniResults.class ]
|
||||
assert [ -r classes/org/servalproject/test/ServalDTests.class ]
|
||||
}
|
||||
|
||||
# Make sure that the normal echo command-line works, without JNI.
|
||||
@ -47,7 +49,7 @@ assert_echo_works() {
|
||||
|
||||
doc_Echo="Serval JNI echo Hello world"
|
||||
test_Echo() {
|
||||
executeOk java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.servald.ServalD 'echo' '-e' 'Hello,\ttab' 'world\0!'
|
||||
executeOk java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.servaldna.ServalDCommand 'echo' '-e' 'Hello,\ttab' 'world\0!'
|
||||
assertStdoutIs -e 'Hello,\ttab\nworld\0!\n'
|
||||
}
|
||||
|
||||
@ -64,14 +66,14 @@ test_Delim() {
|
||||
|
||||
doc_Repeat="Serval JNI repeated calls in same process"
|
||||
test_Repeat() {
|
||||
executeOk --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.servald.ServalDTests repeat 50 'echo' 'Hello,' 'world!'
|
||||
executeOk --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.test.ServalDTests repeat 50 'echo' 'Hello,' 'world!'
|
||||
assertStdoutLineCount '==' 50
|
||||
assertStdoutGrep --matches=50 '^0:Hello,:world!$'
|
||||
}
|
||||
|
||||
doc_NullArg="Serval JNI null arguments throw exception"
|
||||
test_NullArg() {
|
||||
execute --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.servald.ServalDTests nullArg 'echo' '(null)'
|
||||
execute --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.test.ServalDTests 'echo' '(null)'
|
||||
tfw_cat --stdout --stderr
|
||||
assertExitStatus '!=' 0
|
||||
assertStderrGrep 'NullPointerException: null element in argv'
|
||||
@ -79,7 +81,7 @@ test_NullArg() {
|
||||
|
||||
doc_help="Serval JNI returns help text"
|
||||
test_help() {
|
||||
execute --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.servald.ServalD 'help'
|
||||
execute --core-backtrace java "-Djava.library.path=$LD_LIBRARY_PATH" -classpath "$PWD/classes" org.servalproject.servaldna.ServalDCommand 'help'
|
||||
tfw_cat --stdout --stderr
|
||||
assertExitStatus '==' 0
|
||||
assertStdoutGrep 'Serval DNA version '
|
||||
|
Loading…
Reference in New Issue
Block a user