Flex RemoteObject: Arrays with same values reference same memory - apache-flex

If I send remote data from Zend_Amf to Flex, if two array properties on the object have the same data values they are deserialized at the remote end with the same memory storage.
Example: AS3 object:
Snippet:
[RemoteClass(alias="TestVO")]
public class TestVO
{
public var test1:Array;
public var test2:Array;
}
When this receives remote data from Zend_Amf server, if the array data are identical it allocates the same storage to the two arrays.
Eg: From remote (ZendAMF) object I send:
$this->test1 = array("foo", "bar");
$this->test2 = array("foo", "bar");
When I debug the TestVO object in Flex debugger I get:
test1 Array(#597d779)
test2 Array(#597d779)
ie: they reference the same array object.
If I send from the remote server slightly different values for the 2 arrays:
$this->test1 = array("foo", "bar");
$this->test2 = array("bar", "foo");
In the Flex debugger the TestVO object now has two seperate arrays as you'd expect:
test1 Array(#54cb7e9)
test2 Array(#54cb741)
AMF output looks Ok, it always sends two seperate values for test1/test2 even if they have the same values, so I'm guessing it's the way Flex de-serializes this?
Any ideas? Thanks.

AMF does this to gain some compression over the wire. If you don't want this then you can switch to the AMF0 format instead of AMF3. But I'm not sure how to do that with ZendAMF.

Found bug ZF-7634 on Zend Framework implementation of AMF. It is serializing the arrays incorrectly.
http://framework.zend.com/issues/browse/ZF-7634

Related

faild to build body in activemq

I want use ActiveMQ in .net core,i use Apache.NMS.ActiveMQ for doing this but I have problem.
I see this error in ActiveMQ admin console:
Cannot display ObjectMessage body. Reason: Failed to build body from bytes. Reason: java.io.StreamCorruptedException: invalid stream header: 00010000
thats part of my code for doing this:
private const String QUEUE_DESTINATION = "test-queue";
private IConnection _connection;
private ISession _session;
public MessageQueue()
{
IConnectionFactory factory = new ConnectionFactory("tcp://localhost:61616?wireFormat.maxInactivityDuration=5000000");
_connection = factory.CreateConnection();
_connection.Start();
_session = _connection.CreateSession();
}
IDestination dest = _session.GetQueue(QUEUE_DESTINATION);
using (IMessageProducer producer = _session.CreateProducer(dest))
{
var objectMessage = producer.CreateObjectMessage(newDoc);
producer.Send(objectMessage);
}
The fact that the admin console can't display the body of an ObjectMessage isn't really an error. It's the expected behavior. Remember, from the broker's perspective the message body is just an array of bytes. It could be text data (encoded many different ways), image data, custom binary data, etc. The broker has no idea how to decode it. It will try to display the body as text, but if it fails it won't try anything else.
To be clear, in order to see the contents of an ObjectMessage the web console would have to have the object's definition in order to deserialize it. There is no mechanism to tell the web console about arbitrary data formats so it can deserialize message bodies reliably (other than simple text). This is one reason, among many, to avoid ObjectMessage.
I recommend you use a simple text format (e.g. JSON, XML) to represent your data and send that in your message rather than using ObjectMessage.

BizTalk Pipeline IBaseMessage IPropertyContext

When a message comes to a BizTalk pipeline , does IBaseMessage instance stands for the incoming message ? and the property , and how to understand this?
The two parts you'll be mainly interested in from the IBaseMessage will be the BodParty.GetOriginalDataStream() and the Context objects. For example
Stream originalDataStream = pInMsg.BodyPart.GetOriginalDataStream();
string msgAsString;
XDocument msgAsXDoc;
StreamReader sr = new StreamReader(originalDataStream)
msgAsString = sr.ReadToEnd();
originalDataStream.Position = 0; // important to reset this before passing the message on!
msgAsXDoc = XDocument.Load(originalDataStream); // now you have it in an XDoc
originalDataStream.Position = 0;
XmlReader xr = XmlReader.Create(originalDataStream)
originalDataStream.Position = 0;
string strProperty = (string)pInMsg.Context.Read("propertyName", "http://PropertyNameSpace");
string anotherProperty = "Testing";
pInMsg.Context.Write("anotherPropertyName", "http://PropertyNamespace", anotherProperty)
pContext.ResourceTracker.Add(xr);
pContext.ResourceTracker.Add(sr);
etc.
A couple other notes:
Avoid 'using' constructs, they will end up disposing of the underlying stream and causing errors
Add any disposable objects to the context's resource tracker, which will make sure to properly call Dispose() on those objects when the underlying stream is ready to be disposed of.
Yes, this is correct.
IBaseMessage is the Message.
A clear explanation on how to create a custom pipeline component can be found here: http://geekswithblogs.net/bosuch/archive/2012/01/24/creating-a-custom-biztalk-2010-pipeline-componentndashpart-i.aspx
This should get you started.
Well, yes and no.
For clarity, IBaseMessage is an Interface that the actual message object's (.Net) Type implements. It works because .Net allows Interfaces to be used as Types.
Properties are contained in the .Context collection.
Also, BizTalk IBaseMessage implementations can have multiple Parts.

Objects stored by riak-java-client end up as raw json when read by riak-python-client?

I might be confused about something, but when I store a custom object from the Java Riak client and then try to read that object using the Python Riak client, I end up with a raw json string instead of a dict.
However, if I store a the object in python, I am able to output a python dictionary when fetching that object.
I could simply use a json library on the python side to resolve this, but the very fact that I am experiencing this discrepancy makes me think that I am doing something wrong.
On the Java side, this is my object:
class DocObject
{
public String status; // FEEDING | PERSISTED | FAILED | DELETING
public List<String> messages = new ArrayList<String>();
}
class PdfObject extends DocObject
{
public String url;
public String base_url;
}
This is how I am storing that object in Riak:
public void feeding(IDocument doc) throws RiakRetryFailedException {
PdfObject pdfObject = new PdfObject();
pdfObject.url = doc.getElement("url").getValue().toString();
pdfObject.base_url = doc.getElement("base_url").getValue().toString();
pdfObject.status = "FEEDING";
String key = hash(pdfObject.url);
pdfBucket.store(key, pdfObject).execute();
}
And this is what I am doing in Python to fetch the data:
# Connect to Riak.
client = riak.RiakClient()
# Choose the bucket to store data in.
bucket = client.bucket('pdfBucket')
doc = bucket.get('7909aa2f84c9e0fded7d1c7bb2526f54')
doc_data = doc.get_data()
print type(doc_data)
The result of the above python is:
<type 'str'>
I am expecting that to be <type 'dict'>, just like how the example here works:
http://basho.github.com/riak-python-client/tutorial.html#getting-single-values-out
I am perplexed as to why when the object is stored from Java it is stored as a JSON string and not as an object.
I would appreciate if anybody could point out an issue with my approach that might be causing this discrepancy.
Thanks!
It would appear you've found a bug in our Python client with the HTTP protocol/transport.
Both the version you're using and the current one in master are not decoding JSON properly. Myself and another dev looked into this this morning and it appears to stem from an issue with charset parameter being returned from Riak with the content-type as Christian noted in his comment ("application/json; charset=UTF-8")
We've opened an issue on github (https://github.com/basho/riak-python-client/issues/227) and will get this corrected.
In the mean time the only suggestion I have is to decode the returned JSON string yourself, or using the 1.5.2 client (latest stable from pypy) and the Protocol Buffers transport:
client = riak.RiakClient(port=8087, transport_class=riak.RiakPbcTransport)
it will return the decoded JSON as a dict as you're expecting.

Unknown AMF type '16':issue in using arraycollection at java end recieved from flex end using AMF

while calling a java side function from flex side I am having following problem
this works
java side
//in FlexService class
public List<Car> javaFunction(String model){
return carList;
}
flex side
flexService.javaFunction("merc");
while this doesn't work
java side
//in FlexService.java class
public List<Car> javaFunction(String model, List engine){
//some code
return carList;
}
flex side
var engines:ArrayCollection= new ArrayCollection(engineList);
flexService.javaFunction("merc",engines);//function call to java side method
I am getting AMF 16 error.Why I am not able to send ArrayCollection when I can send String.
I referenced http://livedocs.adobe.com/blazeds/1/blazeds_devguide/help.html?content=serialize_data_3.html and it says arraycollection can be received in List..DO I need to create a seperate DTO.??
following is stack trace
2011-10-06 19:57:55,209 83442 [http-8080-5] DEBUG (AbstractUrlHandlerMapping.java:221)- Mapping [/amf] to HandlerExecutionChain with handler [flex.messaging.MessageBroker#13
00800] and 1 interceptor
[BlazeDS]10/06/2011 19:57:55.211 [ERROR] [Endpoint.AMF] Unknown AMF type '16'.
flex.messaging.io.UnknownTypeException: Unknown AMF type '16'.
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:219)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:132)
at flex.messaging.io.amf.Amf3Input.readArray(Amf3Input.java:371)
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:157)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:132)
at flex.messaging.io.amf.Amf3Input.readScriptObject(Amf3Input.java:473)
at flex.messaging.io.amf.Amf3Input.readObjectValue(Amf3Input.java:153)
at flex.messaging.io.amf.Amf3Input.readObject(Amf3Input.java:132)
at flex.messaging.io.amf.Amf0Input.readObjectValue(Amf0Input.java:135)
at flex.messaging.io.amf.Amf0Input.readArrayValue(Amf0Input.java:326)
at flex.messaging.io.amf.Amf0Input.readObjectValue(Amf0Input.java:139)
at flex.messaging.io.amf.Amf0Input.readObject(Amf0Input.java:95)
at flex.messaging.io.amf.AmfMessageDeserializer.readObject(AmfMessageDeserializer.java:226)
at flex.messaging.io.amf.AmfMessageDeserializer.readBody(AmfMessageDeserializer.java:205)
at flex.messaging.io.amf.AmfMessageDeserializer.readMessage(AmfMessageDeserializer.java:125)
at flex.messaging.endpoints.amf.SerializationFilter.invoke(SerializationFilter.java:114)
at flex.messaging.endpoints.BaseHTTPEndpoint.service(BaseHTTPEndpoint.java:278)
at flex.messaging.endpoints.AMFEndpoint$$EnhancerByCGLIB$$8d427d7d.service(<generated>)
at
At the first glance the error cause seems to be the usage of the Vector class. Are you sure that you are using an ArrayCollection and not a Vector on the flex side? Vector serialization was introduced only in BlazeDS 4.5
I am not 100% sure. But you may need to specify generics on the List.
//in FlexService.java class
public List<Car> javaFunction(String model, List<Engine> engine){
//some code
return carList;
}
Also be sure that all the elements in the ArrayCollection in flex have a matching java class.
ArrayCollection is a very heavy class for transfering with lots of unnecessary fields. Use Array instead.

Converting array of ObjectProxy objects to custom objects

I have a service which returns an Array of ObjectProxy objects. I would like to cast this to a custom object (a value object) and create an ArrayCollection. How can I do this?
Edited:
I am using Django and PyAMF for the backend. I had to write a custom SQL query and I am wrapping the resulting records in ObjectProxy and sending the whole result as an ArrayCollection.
Here is my client side code:
[ArrayElementType("SessionVO")]
[Bindable]
private var _list:ArrayCollection;
private function onSessionResultSuccess(event:ResultEvent):void
{
_list = new ArrayCollection(event.result as Array));
}
When I debug, I notice that the elements of event.result are of type ObjectProxy but the _list variable is null. Is there another than to loop over event.result and copy them into _list as SessionVO objects?
If you use the [RemoteClass] tag on your value objects, Flex remoting (Blaze, LCDS) will convert them to your value object for you when sending/returning from a remote service call.
The syntax for RemoteClass is
[RemoteClass(alias="com.co.custom.remote.class")] <--- point to the remote java/php class def
Public Class FooBar
{
public instance variable;
}
Your service can then return an array or hashtable of this class and Flex remoting will convert it for you.
There are cases where objects can become opaque, which you may need to create ObjectProxy code to do custom marshaling, but this is not common. The RemoteClass marshaling can handle very ccomplex object types, subtypes, embedded objects in objects, etc. As long as all of objects on the AS side are typed with RemoteClass, it works as expected.
I'm not sure what you mean by "ObjectProxy objects." I sounds to me like you are already getting returned an array of custom objects.
I recommend looking into some form of AMF gateway. Most serer side languages have an AMF add-on piece to them. It is built into ColdFusion, BlazeDS, and LiveCycle. PHP has ZendAMF and AMFPHP. .NET has FlourineFX and WebORB. Those are just a few examples.
AMF Gateways have a automatic conversion facility; so that the server side object can easily map to a client side object. Here is some info on the RemoteObject tag that describes this. Basically, you specify the RemoteClass metadata on your client side object, and usually specify some form of mapping on the server side object. The AMF Gateway magically handles the rest of the conversion.
In your RemoteObject result handler, you'll just have to convert the returned array to an ArrayCollection. Usually something like this:
var resultArray : Array = event.result as Array;
var resultCollection : ArrayCollection = new ArrayCollection(resultArray);
If you have no control over the server side piece of this application, you may be stuck looping over the results and manually converting them into client side Flex objects.
You can use com.adobe.serializers.utility.TypeUtility;
public function result_handler(event:ResultEvent):void{
var result:Array = TypeUtility.convertListToStrongType(event.result,YourValueObject) as Array;
}
make makeObjectsBindable="false" in the web service property, it will return object.
<s:WebService id="ws" wsdl="http://`xxxx/mobiledata/MobileDataService.asmx?wsdl" fault="fault(event)">
<s:operation
name="GetAll"
resultFormat="object"
result="GetData(event)" makeObjectsBindable="false"
/>
<s:operation
name="Create"
resultFormat="object"
result="SaveData(event)"
/>
</s:WebService>

Resources