the current AMF handler version seems to be roughly the same as in 0.5
- which had quite a few problems:
- no support for nested structures (var x:Array = []; x[0] = x;
remoteCall(x) => crash)
- no object mapping support (var test:Test <-> Test test)
- strange errors (when byte values under-run)
I fixed the 0.5 version to support all this, but won't make the effort
to adapt it unless you ensure me that it will get included...
For the flash class <> java class mapping, it involves a "Resolver"
that is a property of the client. Code then looks like this:
client.setResolver(new AMFResolver() {
// gets called from the decoder when a var test:Test is
supplied as an argument
public Wrapper decodeTypedObject(String className,
Wrapper objectData) {
Test test = new Test();
test.x = objectData.hashValue.getString("x");
return new Wrapper("Test", test); // undefined
}
// gets called from the encoder when a "Test test" is
supplied as an argument
// wrapper was created with new Wrapper(test)
public Wrapper classNameForTypedObject(Wrapper wrapper) {
return new Wrapper(wrapper.className); // return
string wrapper
}
public Wrapper encodeTypedObject(Wrapper wrapper) {
Object realObject = wrapper.value;
WrapperMap<String, Object> data = new
WrapperMap<String, Object>();
data.put("x", "Hi");
Wrapper result = new Wrapper(data);
return result;
}
});
for a simple class Test {String x;}
Fr the rest, the AMFDecoder and AMFEncoder are pretty much rewritten
(no big deal, btw, it was just a bitch testing it). Also affected are
Wrapper, WrapperList and less so Client and ClientController. I could
also send you the 0.5 code and you can check it yourself, but there's
also a bunch of other stuff in there I'm not sure of yet...
Cheers, Anjo
Cheers, Anjo
> the current AMF handler version seems to be roughly the same as in 0.5
> - which had quite a few problems:
> - no support for nested structures (var x:Array = []; x[0] = x;
> remoteCall(x) => crash)
The new version handles mixed arrays and mixed objects also
> - no object mapping support (var test:Test <-> Test test)
True. I don't need this functionality in Milenia.
> - strange errors (when byte values under-run)
Hopefully all of them are gone, i heavily reworked the encoders.
> I fixed the 0.5 version to support all this, but won't make the effort
> to adapt it unless you ensure me that it will get included...
Well, the above all i can say. But i promise that the encoders won't
be changed any more ( too badly :) ), so you can finalize your own
encoders.
Regards
Milan
Am 09.04.2008 um 00:10 schrieb Milan Toth:
>> - no support for nested structures (var x:Array = []; x[0] = x;
>> remoteCall(x) => crash)
> The new version handles mixed arrays and mixed objects also
The problem here is circles in the data structures. You need to be
able to code and re-encode references. Also, the patch handles XML and
dates.
>> - no object mapping support (var test:Test <-> Test test)
> True. I don't need this functionality in Milenia.
Whooppie for you, but I need it. I don't see me pushing around
Wrapper's in the client code, you know :)
>> - strange errors (when byte values under-run)
> Hopefully all of them are gone, i heavily reworked the encoders.
Not from what I saw. The problem was byte values > 128 (or was is <
0 ?) which wrapped.
i mean simplification and performance tuning under reworking :) Well,
i have to think about reference handling, i've never ever used it, so
i don't think its necessary in a simple server.
Milan
> <patch.txt.zip>
>
>
> The patch still runs the Data Unit test, once you apply it, I'll add
> code to test the new functionality. The only thing I don't like about
> it is the toString() of the wrapper class and that the constants in
> Wrapper are not uppercased. But you can easily do that by refactoring.
>
> Cheers, Anjo
Am 09.04.2008 um 08:16 schrieb Milan Toth:
> i mean simplification and performance tuning under reworking :) Well,
> i have to think about reference handling, i've never ever used it, so
> i don't think its necessary in a simple server.
Is this a "no" on the patch?
Try this with your code:
{
...
var mixedArrayValue:Array = [];
var arrayValue:Array = [];
var objectValue:Object = {};
objectValue["key"] = "milgra" ;
objectValue["num"] = 234235;
//objectValue["array"] = arrayValue;
testXML = XML(objectValue);
mixedArrayValue[0] = "dasfdasg";
mixedArrayValue[1] = 234235;
mixedArrayValue[2] = 223235.2351235;
mixedArrayValue[3] = true;
mixedArrayValue[4] = objectValue;
mixedArrayValue[7] = false;
//mixedArrayValue[44] = objectValue;
for(var o:* in mixedArrayValue) {
arrayValue = arrayValue.concat(o);
}
arrayValue = arrayValue.concat("Test");
connection.call( "receiveArray" , null , arrayValue );
connection.call( "receiveMixedArray" , null , mixedArrayValue );
connection.call( "receiveObject" , null , objectValue );
...
}
public function receiveArray ( value:* ):void
{
var content:String = "";
for ( var a:* in value ) content += a + " : " + value[a] + ", ";
msg( "receiveArray: [" + content.replace(/,\s+$/, "") + "]");
}
public function receiveMixedArray ( value:* ):void
{
var content:String = "";
for ( var a:* in value ) content += a + " : " + value[a] + ", ";
msg( "receiveMixedArray: [" + content.replace(/,\s+$/, "") + "]");
}
public function receiveObject ( value:* ):void
{
var content:String = "";
for ( var a:* in value ) content += a + " : " + value[a] + ", ";
msg( "receiveObject: [" + content.replace(/,\s+$/, "") + "]");
}
from what I remember you get a crash in the server. Or incorrect
results. Or both.
Cheers, Anjo
Yeah, you are right, it really fails after the second reference. I
have to deal with this, i will implement your patch, thanks.
Milan
But is important to note that you must leave the resolving stuff to
the one that actually knows about it - be it client or app. That's why
there is a resolver class, which can look up the identifier and
actually return the correct instance instead of just creating a new
one. It's not possible to do that in a factory or other patterns.
Cheers, Anjo
Can you give me an example of the usage of the Typed object/class
object? Can i simply catch a typed object in flash under its type?
regards
Milan
var test:Test;
test = new Test();
conn.call("something", null, test)
and the java client gets a real java Test object when the invoke is
called. And vice-versa. In this example, the (de)serialization is done
manually, but you can include one of several bean serializers and plug
those in. Then you would be able to do that without code.
If I remember correctly, the AmfResolver
public class AmfResolver {
public Wrapper decodeTypedObject(String className, Wrapper
objectData) {
return new Wrapper("NoClassUnderTheSun", new Wrapper(new
WrapperMap())); // undefined
}
public Wrapper classNameForTypedObject(Wrapper wrapper) {
return new Wrapper("NoClassUnderTheSun"); // return string
wrapper
}
public Wrapper encodeTypedObject(Wrapper wrapper) {
return new Wrapper(new WrapperMap()); // undefined
}
}
is written this way only in case you forget a registerClassAlias() on
the client. Otherwise one might just make an interface from it.
Test.as:
package
{
public class Test {
public var x:String;
public function toString():String {
return "<Test x:" + x + ">";
}
}
}
Data.as:
{
...
var testValue:Test = new Test();
testValue.x = "Hi";
registerClassAlias("Test", Test);
connection.call( "receiveTest" , null , testValue );
msg( "testValue sent");
...
}
public function receiveTest ( value:* ):void
{
msg( "receiveTest: " + value + " x:" + (value != null ? value.x :
null));
}
Client.java:
static class Test {
String x;
@Override
public String toString() {
return "<Test x: " + x + ">";
}
}
public void onInvoke(Map<String, Wrapper> eventX) {
// getting client
long clientID = eventX.get("clientid").longValue;
Client client = clients.get(clientID);
client.resolver(new AmfResolver() {
// simple handler, just does the "Test" class, otherwise
we would need some checks here.
public Wrapper decodeTypedObject(String className,
Wrapper objectData) {
Test test = new Test();
test.x = objectData.hashValue.getString("x");
return new Wrapper("Test", test);
}
public Wrapper classNameForTypedObject(Wrapper wrapper) {
// string wrapper for class name
return new Wrapper(wrapper.className);
}
public Wrapper encodeTypedObject(Wrapper wrapper) {
Object realObject = wrapper.value;
WrapperMap data = new WrapperMap();
// actually, we should cast realObject to Test test
and call test.x ...
data.put("x", "Hi");
Wrapper result = new Wrapper(data);
return result;
}
});
Cheers, Anjo
WrapperList list = new WrapperList()
Wrapper arg = new Wrapper(list)
list.add(arg);
and try to send this from the server. (I just wrote that in mail, but
you should get the idea)
Cheers, Anjo
Is the referencing working for you?
Cheers, Anjo
cheers
Milan
I can understand that your goal is to keep the server under 64k.
However, I planned on actually using this software and I can't do that
if you won't integrate (IMO pretty minor) patches which I need in
order to get my job done.
For me, AMF support is important, correctness is important and being
able to launch my stuff in Eclipse and debug it is important as is
RTMPT support. I don't really have the time to argue with you and re-
apply my stuff every time I send you a patch and you write your own
code.
So unless you either apply my patches or come up with equivalent ones
I won't be able to use your code. I guess I will try my luck with Red5
and see if it is more useful :/
I'll check from time to time and see how you are doing.
Thanks and I wish you good luck, Anjo
sorry about that :(
regards
Milan
> I will try my luck with Red5 and see if it is more useful :/
Famous last words... So I downloaded Red5 (again), took a deep look
into all the spring config files and thought I'd rather give you
another try :)
I created a git repository and made my changes there. Then you can do
what you please and I can still continue working.
I think I found a few problems: when you close the flash debugger
window while running the test client and playing the recorded stream
(which btw sounds like crap, at least the one I put there), I get an
NPE. The problem is that StreamBuffer.destruct() null's the arrays,
but the buffer is still accessed later on. I don't understand enough
of your stream handling to see why this is happening, but you can
prevent the NPE when you change destruct() to clear the arrays instead.
/**
*StreamBufferdestructor
**/
public void destruct ( )
{
System.out.println( System.currentTimeMillis( ) + "
StreamBuffer.destruct " );
pool.clear();
positions.clear();
durations.clear();
bodysizes.clear();
timesizes.clear();
}
If you don't, the NPE will kill the ProcessThread, which will in turn
prevent other clients from playing files. So you might want to catch
runtime exceptions when processing;
--- a/MilGraServer/src/com/milgra/server/ProcessThread.java
+++ b/MilGraServer/src/com/milgra/server/ProcessThread.java
@@ -100,7 +100,14 @@ public class ProcessThread extends Thread
// step all processes
- for ( OProcess process : processes )
process.step( );
+ for ( OProcess process : processes ) {
+ try {
+ process.step( );
+ } catch(RuntimeException ex) {
+ System.err.println(ex);
+ ex.printStackTrace(System.err);
+ }
+ }
Probably also kill the client, but what do I know...
Cheers, Anjo