Some refactoring and added some JUnit tests

This commit is contained in:
Ziver Koc 2016-09-27 16:56:51 +02:00
parent d107cd504c
commit 24c4fac26d
13 changed files with 168 additions and 100 deletions

View file

@ -31,24 +31,18 @@ package zutil.net.torrent;
*/
public class TorrentFile{
private String filename;
private long length;
private long size;
public TorrentFile(String filename, long length){
public TorrentFile(String filename, long size){
this.filename = filename;
this.length = length;
this.size = size;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
public long getSize() {
return size;
}
}

View file

@ -32,10 +32,13 @@ import zutil.parser.DataNode;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
public class TorrentMetainfo {
/** Name **/
private String name;
/** Comment (optional) **/
private String comment;
/** Signature of the software which created the torrent (optional) **/
@ -63,16 +66,16 @@ public class TorrentMetainfo {
public TorrentMetainfo(File torrent) throws IOException{
public TorrentMetainfo(File torrent) throws IOException, ParseException {
this(FileUtil.getContent(torrent));
}
public TorrentMetainfo(String data){
public TorrentMetainfo(String data) throws ParseException {
decode(data);
}
private void decode(String data){
private void decode(String data) throws ParseException {
DataNode metainfo = BEncodedParser.read(data);
// Main values
@ -91,66 +94,70 @@ public class TorrentMetainfo {
// info data
DataNode info = metainfo.get("info");
String name = info.getString("name");
name = info.getString("name");
piece_length = info.getLong("piece length");
if( info.get("private") != null )
is_private = (info.getInt("private") != 0);
// Split the hashes
String hashes = info.getString("pieces");
piece_hashes = new ArrayList<String>();
for(int i=0; i<hashes.length() ;i++){
String hash = "";
for(; i%20!=0 ;i++)
hash += hashes.charAt(i);
piece_hashes.add(hash);
for(int i=0; i<hashes.length(); ){
StringBuilder hash = new StringBuilder(20);
for(int k=0; k<20; ++i, ++k)
hash.append(hashes.charAt(i));
piece_hashes.add(hash.toString());
}
// File data
file_list = new ArrayList<TorrentFile>();
// Single-file torrent
if( info.get("files") == null ){
Long length = info.getLong("length");
file_list.add( new TorrentFile(name, length) );
Long fileSize = size = info.getLong("length");
file_list.add( new TorrentFile(name, fileSize) );
}
// Multi-file torrent
else{
DataNode files = info.get("files");
for( DataNode file : files ){
String filename = "";
StringBuilder filename = new StringBuilder();
DataNode tmp = file.get("path");
// File in subdir
if( tmp.isList() ){
Iterator<DataNode> it = tmp.iterator();
while( it.hasNext() ){
filename += it.next().getString();
if(it.hasNext()) filename += File.separator;
filename.append(it.next().getString());
if(it.hasNext())
filename.append(File.separator);
}
}
// File in root dir
else
filename = tmp.getString();
Long length = file.getLong("length");
filename = name + File.separator + filename;
file_list.add( new TorrentFile(filename, length) );
filename.append(tmp.getString());
Long fileSize = file.getLong("length");
size += fileSize;
file_list.add( new TorrentFile(filename.toString(), fileSize) );
}
}
}
public String getName() {
return name;
}
public String getComment() {
return comment;
}
public String getCreated_by() {
public String getCreatedBy() {
return created_by;
}
public long getCreation_date() {
public long getCreationDate() {
return creation_date;
}
public String getAnnounce() {
return announce;
}
public ArrayList<String> getAnnounce_list() {
public ArrayList<String> getAnnounceList() {
return announce_list;
}
public String getEncoding() {
@ -159,31 +166,17 @@ public class TorrentMetainfo {
public long getSize() {
return size;
}
public long getPiece_length() {
public long getPieceLength() {
return piece_length;
}
public ArrayList<String> getPiece_hashes() {
public ArrayList<String> getPieceHashes() {
return piece_hashes;
}
public boolean isIs_private() {
public boolean isPrivate() {
return is_private;
}
public ArrayList<TorrentFile> getFile_list() {
public ArrayList<TorrentFile> getFileList() {
return file_list;
}
/**
* Example use
*/
public static void main(String[] args){
try {
TorrentMetainfo tmp = new TorrentMetainfo(FileUtil.find("test.torrent"));
MultiPrintStream.out.dump(tmp);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View file

@ -153,7 +153,7 @@ public class UPnPContentDirectory implements UPnPService, HttpPage, WSInterface
}
@WSDisabled
@WSIgnore
public void respond(HttpPrintStream out, HttpHeader headers,
Map<String, Object> session,
Map<String, String> cookie,

12
src/zutil/net/ws/WSInterface.java Normal file → Executable file
View file

@ -30,14 +30,16 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* Specifies web service parameter names and other things.
* Specifies web service definitions. Which methods that will
* be published and other related metadata.
*
* Example:
* <pre>
* private static class Test implements WSInterface{
* public Test(){}
*
* @WSDocumentation("blabla")
* @WSDLParamDocumentation("olle = an variable?")
* @WSDLParamDocumentation("olle = a variable?")
* public void pubZ(
* @WSParamName("olle") int lol)
* throws Exception{
@ -51,7 +53,7 @@ import java.lang.annotation.Target;
* ....
* }
*
* @WSDisabled()
* @WSIgnore()
* public void privaZ(....){
* ...
* }
@ -87,13 +89,13 @@ public interface WSInterface {
}
/**
* Disables publication of the given method
* Skipp publication of the given method
*
* @author Ziver
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface WSDisabled { }
public @interface WSIgnore { }
/**
* Method or Parameter comments for the WSDL.

12
src/zutil/net/ws/WSMethodDef.java Normal file → Executable file
View file

@ -228,16 +228,8 @@ public class WSMethodDef {
* @param obj the object the method will called on
* @param params a vector with arguments
*/
public Object invoke(Object obj, Object[] params) throws Throwable{
try {
return this.method.invoke(obj, params );
} catch (IllegalArgumentException e) {
throw e;
} catch (IllegalAccessException e) {
throw e;
} catch (InvocationTargetException e) {
throw e.getCause();
}
public Object invoke(Object obj, Object[] params) throws Exception {
return this.method.invoke(obj, params );
}

2
src/zutil/net/ws/WebServiceDef.java Normal file → Executable file
View file

@ -57,7 +57,7 @@ public class WebServiceDef {
for(Method m : intf.getDeclaredMethods()){
// check for public methods
if((m.getModifiers() & Modifier.PUBLIC) > 0 &&
!m.isAnnotationPresent(WSInterface.WSDisabled.class)){
!m.isAnnotationPresent(WSInterface.WSIgnore.class)){
WSMethodDef method = new WSMethodDef(this, m);
methods.put(method.getName(), method);
}

View file

@ -70,7 +70,7 @@ public class RestHttpPage implements HttpPage {
}
private String execute(String targetMethod, Map<String, String> input) throws Throwable {
protected String execute(String targetMethod, Map<String, String> input) throws Exception {
if( wsDef.hasMethod(targetMethod) ){
// Parse request
WSMethodDef m = wsDef.getMethod(targetMethod);
@ -82,6 +82,7 @@ public class RestHttpPage implements HttpPage {
// Generate Response
StringOutputStream dummyOut = new StringOutputStream();
JSONObjectOutputStream out = new JSONObjectOutputStream(dummyOut);
out.enableMetaData(false);
out.writeObject(ret);
out.close();
return dummyOut.toString();
@ -103,8 +104,4 @@ public class RestHttpPage implements HttpPage {
}
return inputParams;
}
private void generateResponse(){
}
}

View file

@ -40,19 +40,6 @@ import java.util.logging.Logger;
public class SOAPClientFactory {
private static Logger logger = LogUtil.getLogger();
/**
* Generates a Client Object for the web service.
*
* @param <T> is the class of the web service definition
* @param url is the target service url
* @param intf is the class of the web service definition
* @return a client Object
*/
@SuppressWarnings("unchecked")
public static <T> T createClient(URL url, Class<T> intf){
return createClient(url, intf,
new WebServiceDef((Class<? extends WSInterface>)intf) );
}
/**
* Generates a Client Object for the web service.
@ -60,12 +47,11 @@ public class SOAPClientFactory {
* @param <T> is the class of the web service definition
* @param url is the target service url
* @param intf is the class of the web service definition
* @param wsDef is the web service definition of the intf parameter
* @return a client Object
*/
public static <T> T createClient(URL url, Class<T> intf, WebServiceDef wsDef){
public static <T extends WSInterface> T createClient(URL url, Class<T> intf){
T obj = WSClientFactory.createClient( intf,
new SOAPClientInvocationHandler(url, wsDef));
new SOAPClientInvocationHandler(url, new WebServiceDef(intf)));
return obj;
}

View file

@ -27,6 +27,9 @@ package zutil.parser;
import zutil.parser.DataNode.DataType;
import zutil.struct.MutableInt;
import java.nio.charset.MalformedInputException;
import java.text.ParseException;
/**
* http://wiki.theory.org/BitTorrentSpecification
* @author Ziver
@ -40,7 +43,7 @@ public class BEncodedParser {
* @param data is the data to be decoded
* @return
*/
public static DataNode read(String data){
public static DataNode read(String data) throws ParseException {
return decode_BEncoded(new MutableInt(), new StringBuilder(data));
}
@ -51,9 +54,10 @@ public class BEncodedParser {
* @param index is the index in data to start from
* @return
*/
private static DataNode decode_BEncoded(MutableInt index, StringBuilder data){
private static DataNode decode_BEncoded(MutableInt index, StringBuilder data) throws ParseException {
String tmp;
char c = ' ';
int end;
switch (data.charAt(index.i)) {
/**
@ -63,7 +67,10 @@ public class BEncodedParser {
*/
case 'i':
index.i++;
tmp = data.substring(index.i, data.indexOf("e"));
end = data.indexOf("e", index.i);
if (end < 0)
throw new ParseException("Corrupt bEncoding", index.i);
tmp = data.substring(index.i, end);
index.i += tmp.length() + 1;
return new DataNode( new Long(tmp));
/**
@ -97,6 +104,8 @@ public class BEncodedParser {
while(c != 'e'){
DataNode tmp2 = decode_BEncoded(index, data);
map.set(tmp2.getString(), decode_BEncoded(index, data));
if (index.i >= data.length())
throw new ParseException("Incorrect bEncoding ending of element", index.i);
c = data.charAt(index.i);
}
index.i++;
@ -107,10 +116,13 @@ public class BEncodedParser {
* would bEncode to 11:BitTorrents.
*/
default:
tmp = data.substring(index.i, data.indexOf(":"));
end = data.indexOf(":", index.i);
if (end < 0)
throw new ParseException("Corrupt bEncoding", index.i);
tmp = data.substring(index.i, end);
int length = Integer.parseInt(tmp);
index.i += tmp.length() + 1;
String ret = data.substring(index.i, length);
String ret = data.substring(index.i, index.i+length);
index.i += length;
return new DataNode( ret );
}

View file

@ -200,10 +200,16 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
}
public void flush() throws IOException {
super.flush();
out.flush();
}
public void close() throws IOException {
if (out != null) {
out.flush();
out.close();
}
}
@Override public void writeBoolean(boolean v) throws IOException {

View file

@ -0,0 +1,41 @@
package zutil.net.torrent;
import org.junit.Test;
import java.text.ParseException;
import static org.junit.Assert.*;
/**
* Created by Ziver on 2016-09-27.
*/
public class TorrentMetainfoTest {
@Test
public void decode() throws ParseException {
TorrentMetainfo tmp = new TorrentMetainfo(
"d8:announce39:http://torrent.ubuntu.com:6969/announce13:announce-listll" +
"39:http://torrent.ubuntu.com:6969/announceel44:http://ipv6.torrent.ubuntu.com:6969/announceee" +
"7:comment29:Ubuntu CD releases.ubuntu.com13:creation datei1469103218e4:infod" +
"6:lengthi1513308160e4:name32:ubuntu-16.04.1-desktop-amd64.iso12:piece lengthi524288e" +
"6:pieces60:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaee");
assertEquals("http://torrent.ubuntu.com:6969/announce", tmp.getAnnounce());
assertArrayEquals(new String[]{
"http://torrent.ubuntu.com:6969/announce",
"http://ipv6.torrent.ubuntu.com:6969/announce"},
tmp.getAnnounceList().toArray());
assertEquals("Ubuntu CD releases.ubuntu.com", tmp.getComment());
assertEquals(1469103218, tmp.getCreationDate());
assertEquals(1513308160, tmp.getSize());
assertEquals("ubuntu-16.04.1-desktop-amd64.iso", tmp.getName());
assertEquals(1, tmp.getFileList().size());
assertEquals("ubuntu-16.04.1-desktop-amd64.iso", tmp.getFileList().get(0).getFilename());
assertEquals(524288, tmp.getPieceLength());
assertEquals(3, tmp.getPieceHashes().size());
assertEquals("aaaaaaaaaaaaaaaaaaaa", tmp.getPieceHashes().get(0));
assertEquals("aaaaaaaaaaaaaaaaaaaa", tmp.getPieceHashes().get(1));
assertEquals("aaaaaaaaaaaaaaaaaaaa", tmp.getPieceHashes().get(2));
}
}

View file

@ -0,0 +1,49 @@
package zutil.net.ws.rest;
import org.junit.Test;
import zutil.net.ws.WSInterface;
import java.util.HashMap;
import static org.junit.Assert.*;
/**
* Created by Ziver on 2016-09-27.
*/
public class RestHttpPageTest {
public static class TestClass implements WSInterface{
public String hello(){
return "hello world";
}
}
@Test
public void noInput() throws Throwable {
RestHttpPage rest = new RestHttpPage(new TestClass());
HashMap<String,String> input = new HashMap<>();
String output = rest.execute("hello", input);
assertEquals("\"hello world\"\n", output);
}
public static class TestEchoClass implements WSInterface{
public String echo(@WSParamName("input") String input){
return "echo: "+input;
}
}
@Test
public void oneInput() throws Throwable {
RestHttpPage rest = new RestHttpPage(new TestEchoClass());
HashMap<String,String> input = new HashMap<>();
input.put("input", "test input");
String output = rest.execute("echo", input);
assertEquals("\"echo: test input\"\n", output);
}
}

View file

@ -38,10 +38,6 @@ import zutil.parser.wsdl.WSDLWriter;
public class SOAPTest {
/************************* TEST CASES ************************/
public static void main(String[] args){
new SOAPTest();
}
public SOAPTest(){
WebServiceDef wsDef = new WebServiceDef( MainSOAPClass.class );
SOAPHttpPage soap = new SOAPHttpPage( wsDef );
@ -84,7 +80,7 @@ public class SOAPTest {
public static class SpecialReturnClass extends WSReturnObject{
@WSValueName(value="otherValue1")
public String param1 = "otherValue1";
@WSValueName("otherValue2")
@WSValueName("otherName2")
public String param2 = "otherValue2";
public byte[] b = new byte[]{0x12, 0x23};
public InnerClass inner = new InnerClass();
@ -147,7 +143,7 @@ public class SOAPTest {
@WSParamDocumentation("void method documentation")
public void voidMethod (){ }
@WSDisabled()
@WSIgnore()
public void disabledMethod(){ }
protected void protectedMethod(){ }