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{ public class TorrentFile{
private String filename; 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.filename = filename;
this.length = length; this.size = size;
} }
public String getFilename() { public String getFilename() {
return filename; return filename;
} }
public void setFilename(String filename) { public long getSize() {
this.filename = filename; return size;
}
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
} }
} }

View file

@ -32,10 +32,13 @@ import zutil.parser.DataNode;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
public class TorrentMetainfo { public class TorrentMetainfo {
/** Name **/
private String name;
/** Comment (optional) **/ /** Comment (optional) **/
private String comment; private String comment;
/** Signature of the software which created the torrent (optional) **/ /** 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)); this(FileUtil.getContent(torrent));
} }
public TorrentMetainfo(String data){ public TorrentMetainfo(String data) throws ParseException {
decode(data); decode(data);
} }
private void decode(String data){ private void decode(String data) throws ParseException {
DataNode metainfo = BEncodedParser.read(data); DataNode metainfo = BEncodedParser.read(data);
// Main values // Main values
@ -91,66 +94,70 @@ public class TorrentMetainfo {
// info data // info data
DataNode info = metainfo.get("info"); DataNode info = metainfo.get("info");
String name = info.getString("name"); name = info.getString("name");
piece_length = info.getLong("piece length"); piece_length = info.getLong("piece length");
if( info.get("private") != null ) if( info.get("private") != null )
is_private = (info.getInt("private") != 0); is_private = (info.getInt("private") != 0);
// Split the hashes // Split the hashes
String hashes = info.getString("pieces"); String hashes = info.getString("pieces");
piece_hashes = new ArrayList<String>(); piece_hashes = new ArrayList<String>();
for(int i=0; i<hashes.length() ;i++){ for(int i=0; i<hashes.length(); ){
String hash = ""; StringBuilder hash = new StringBuilder(20);
for(; i%20!=0 ;i++) for(int k=0; k<20; ++i, ++k)
hash += hashes.charAt(i); hash.append(hashes.charAt(i));
piece_hashes.add(hash); piece_hashes.add(hash.toString());
} }
// File data // File data
file_list = new ArrayList<TorrentFile>(); file_list = new ArrayList<TorrentFile>();
// Single-file torrent // Single-file torrent
if( info.get("files") == null ){ if( info.get("files") == null ){
Long length = info.getLong("length"); Long fileSize = size = info.getLong("length");
file_list.add( new TorrentFile(name, length) ); file_list.add( new TorrentFile(name, fileSize) );
} }
// Multi-file torrent // Multi-file torrent
else{ else{
DataNode files = info.get("files"); DataNode files = info.get("files");
for( DataNode file : files ){ for( DataNode file : files ){
String filename = ""; StringBuilder filename = new StringBuilder();
DataNode tmp = file.get("path"); DataNode tmp = file.get("path");
// File in subdir // File in subdir
if( tmp.isList() ){ if( tmp.isList() ){
Iterator<DataNode> it = tmp.iterator(); Iterator<DataNode> it = tmp.iterator();
while( it.hasNext() ){ while( it.hasNext() ){
filename += it.next().getString(); filename.append(it.next().getString());
if(it.hasNext()) filename += File.separator; if(it.hasNext())
filename.append(File.separator);
} }
} }
// File in root dir // File in root dir
else else
filename = tmp.getString(); filename.append(tmp.getString());
Long length = file.getLong("length"); Long fileSize = file.getLong("length");
filename = name + File.separator + filename; size += fileSize;
file_list.add( new TorrentFile(filename, length) ); file_list.add( new TorrentFile(filename.toString(), fileSize) );
} }
} }
} }
public String getName() {
return name;
}
public String getComment() { public String getComment() {
return comment; return comment;
} }
public String getCreated_by() { public String getCreatedBy() {
return created_by; return created_by;
} }
public long getCreation_date() { public long getCreationDate() {
return creation_date; return creation_date;
} }
public String getAnnounce() { public String getAnnounce() {
return announce; return announce;
} }
public ArrayList<String> getAnnounce_list() { public ArrayList<String> getAnnounceList() {
return announce_list; return announce_list;
} }
public String getEncoding() { public String getEncoding() {
@ -159,31 +166,17 @@ public class TorrentMetainfo {
public long getSize() { public long getSize() {
return size; return size;
} }
public long getPiece_length() { public long getPieceLength() {
return piece_length; return piece_length;
} }
public ArrayList<String> getPiece_hashes() { public ArrayList<String> getPieceHashes() {
return piece_hashes; return piece_hashes;
} }
public boolean isIs_private() { public boolean isPrivate() {
return is_private; return is_private;
} }
public ArrayList<TorrentFile> getFile_list() { public ArrayList<TorrentFile> getFileList() {
return file_list; 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, public void respond(HttpPrintStream out, HttpHeader headers,
Map<String, Object> session, Map<String, Object> session,
Map<String, String> cookie, 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; 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: * Example:
* <pre> * <pre>
* private static class Test implements WSInterface{ * private static class Test implements WSInterface{
* public Test(){} * public Test(){}
* *
* @WSDocumentation("blabla") * @WSDocumentation("blabla")
* @WSDLParamDocumentation("olle = an variable?") * @WSDLParamDocumentation("olle = a variable?")
* public void pubZ( * public void pubZ(
* @WSParamName("olle") int lol) * @WSParamName("olle") int lol)
* throws Exception{ * throws Exception{
@ -51,7 +53,7 @@ import java.lang.annotation.Target;
* .... * ....
* } * }
* *
* @WSDisabled() * @WSIgnore()
* public void privaZ(....){ * public void privaZ(....){
* ... * ...
* } * }
@ -87,13 +89,13 @@ public interface WSInterface {
} }
/** /**
* Disables publication of the given method * Skipp publication of the given method
* *
* @author Ziver * @author Ziver
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface WSDisabled { } public @interface WSIgnore { }
/** /**
* Method or Parameter comments for the WSDL. * Method or Parameter comments for the WSDL.

10
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 obj the object the method will called on
* @param params a vector with arguments * @param params a vector with arguments
*/ */
public Object invoke(Object obj, Object[] params) throws Throwable{ public Object invoke(Object obj, Object[] params) throws Exception {
try {
return this.method.invoke(obj, params ); return this.method.invoke(obj, params );
} catch (IllegalArgumentException e) {
throw e;
} catch (IllegalAccessException e) {
throw e;
} catch (InvocationTargetException e) {
throw e.getCause();
}
} }

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()){ for(Method m : intf.getDeclaredMethods()){
// check for public methods // check for public methods
if((m.getModifiers() & Modifier.PUBLIC) > 0 && if((m.getModifiers() & Modifier.PUBLIC) > 0 &&
!m.isAnnotationPresent(WSInterface.WSDisabled.class)){ !m.isAnnotationPresent(WSInterface.WSIgnore.class)){
WSMethodDef method = new WSMethodDef(this, m); WSMethodDef method = new WSMethodDef(this, m);
methods.put(method.getName(), method); 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) ){ if( wsDef.hasMethod(targetMethod) ){
// Parse request // Parse request
WSMethodDef m = wsDef.getMethod(targetMethod); WSMethodDef m = wsDef.getMethod(targetMethod);
@ -82,6 +82,7 @@ public class RestHttpPage implements HttpPage {
// Generate Response // Generate Response
StringOutputStream dummyOut = new StringOutputStream(); StringOutputStream dummyOut = new StringOutputStream();
JSONObjectOutputStream out = new JSONObjectOutputStream(dummyOut); JSONObjectOutputStream out = new JSONObjectOutputStream(dummyOut);
out.enableMetaData(false);
out.writeObject(ret); out.writeObject(ret);
out.close(); out.close();
return dummyOut.toString(); return dummyOut.toString();
@ -103,8 +104,4 @@ public class RestHttpPage implements HttpPage {
} }
return inputParams; return inputParams;
} }
private void generateResponse(){
}
} }

View file

@ -40,19 +40,6 @@ import java.util.logging.Logger;
public class SOAPClientFactory { public class SOAPClientFactory {
private static Logger logger = LogUtil.getLogger(); 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. * 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 <T> is the class of the web service definition
* @param url is the target service url * @param url is the target service url
* @param intf is the class of the web service definition * @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 * @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, T obj = WSClientFactory.createClient( intf,
new SOAPClientInvocationHandler(url, wsDef)); new SOAPClientInvocationHandler(url, new WebServiceDef(intf)));
return obj; return obj;
} }

View file

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

View file

@ -200,10 +200,16 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
} }
public void flush() throws IOException { public void flush() throws IOException {
super.flush();
out.flush(); out.flush();
} }
public void close() throws IOException {
if (out != null) {
out.flush();
out.close();
}
}
@Override public void writeBoolean(boolean v) throws IOException { @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 { public class SOAPTest {
/************************* TEST CASES ************************/ /************************* TEST CASES ************************/
public static void main(String[] args){ public static void main(String[] args){
new SOAPTest();
}
public SOAPTest(){
WebServiceDef wsDef = new WebServiceDef( MainSOAPClass.class ); WebServiceDef wsDef = new WebServiceDef( MainSOAPClass.class );
SOAPHttpPage soap = new SOAPHttpPage( wsDef ); SOAPHttpPage soap = new SOAPHttpPage( wsDef );
@ -84,7 +80,7 @@ public class SOAPTest {
public static class SpecialReturnClass extends WSReturnObject{ public static class SpecialReturnClass extends WSReturnObject{
@WSValueName(value="otherValue1") @WSValueName(value="otherValue1")
public String param1 = "otherValue1"; public String param1 = "otherValue1";
@WSValueName("otherValue2") @WSValueName("otherName2")
public String param2 = "otherValue2"; public String param2 = "otherValue2";
public byte[] b = new byte[]{0x12, 0x23}; public byte[] b = new byte[]{0x12, 0x23};
public InnerClass inner = new InnerClass(); public InnerClass inner = new InnerClass();
@ -147,7 +143,7 @@ public class SOAPTest {
@WSParamDocumentation("void method documentation") @WSParamDocumentation("void method documentation")
public void voidMethod (){ } public void voidMethod (){ }
@WSDisabled() @WSIgnore()
public void disabledMethod(){ } public void disabledMethod(){ }
protected void protectedMethod(){ } protected void protectedMethod(){ }