I'm new to Flex and BlazeDS and I'm trying to implement a simple application which uses Flex on the front end and a Spring/Hibernate application on the back end, with communication between the two going over a BlazeDS channel.
I'm seeking direction as to the best and/or simplest way to approach this. I have the UI set up in such a way that the user is presented with a file chooser in which they pick the image file they want to upload. When this is chosen and submitted (as a form submission) then the server side should receive the image file data as well as some related metadata such as a description and date, then populate a Hibernate entity/POJO with the image file data and related metadata, and then persist the entity/POJO into the database.
I have found some examples of how you would do a file upload and download using servlets here and the FileReference class (here and here) but these don't appear to address the problem in a way which leverages BlazeDS and/or Spring/Hibernate. I want to put the image file data and related metadata (description, capture date, etc.) into a value object within the Flex application and then send this over BlazeDS to a service provided by my Spring/Hibernate application running on Tomcat. In this service I want to extract the image data (both the actual JPG/PNG/GIF data and the related metadata such as description, etc.) from the value object sent from the Flex app into an entity/POJO which is then persisted via Hibernate in my database.
Can this be done, and if so what's the best way to go about it? Am I mistaken in assuming that if I use BlazeDS then I am somehow bypassing the need to provide HTTP-based services such as servlets on the server side and instead I can use my Java services as "RemoteObjects"? Is there necessarily a one-to-one mapping between Java POJO/entity class and the Flex value object class when making this sort of transfer? If so is there a tool which creates corresponding Flex value objects from Java POJOs or vice versa.
Thanks in advance for your help, comments, suggestions, etc.
--James
Update: Some code to make this more clear:
I have this as my value object in Flex:
package valueobjects
{
import flash.utils.ByteArray;
[Bindable]
[RemoteClass(alias="com.abc.example.persistence.entity.Image")]
public class Image
{
public var id:Number;
public var captureDate:Date;
public var description:String;
public var imageData:ByteArray;
public function Image() {}
}
I am assuming that this can be used as a one-to-one mapping to the POJO class used by my service and DAO classes on the server-side, which looks like this:
package com.abc.example.persistence.entity;
import java.sql.Blob;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
#Entity(name = "IMAGE")
public class Image
extends AbstractBaseEntity<Long>
{
private String description;
private Date captureDate;
private Blob imageData;
#Column(name = "CAPTURE_DATE", nullable = true)
public Date getCaptureDate()
{
return captureDate;
}
#Column(name = "DESCRIPTION", nullable = true)
public String getDescription()
{
return description;
}
#Column(name = "IMAGE_DATA", nullable = true)
public Blob getImageData()
{
return imageData;
}
public void setCaptureDate(final Date captureDate)
{
this.captureDate = captureDate;
}
public void setDescription(final String description)
{
this.description = description;
}
public void setImageData(final Blob imageData)
{
this.imageData = imageData;
}
}
In my Flex application I populate the fields of an Image object with a description string, date, and image file data (based on the user's file selection and text input for the description) and then call a method on the RemoteObject which is mapped to the service running on Tomcat. I make the RemoteObject service call within my Flex code using the Image value object as the argument, but the service method running on the servier side actually expects an argument of the POJO/entity type, and it's here that I am thinking that some sort of conversion/transformation between the Flex value object and the Java POJO will occur (by virtue of the RemoteClass alias setting on the value object's class declaration), but it doesn't seem to be happening that way because when I debug the application the Java service is only getting null values when the service call is made.
In my Flex application I have a FileReference and Image value object as public, bindable variables:
[Bindable]
public var imageToBeArchivedFileReference:FileReference = new FileReference();
[Bindable]
public var imageToBeArchivedValueObject:valueobjects.Image = new valueobjects.Image();
There is also an event handler to browse for a file when the user clicks on a file select button:
protected function imageFileSelectButton_clickHandler(event:MouseEvent):void
{
var imageFileFilter:FileFilter = new FileFilter("Images (*.jpg, *.jpeg, *.gif, *.png)", "*.jpg;*.jpeg;*.gif;*.png");
var fileTypes:Array = new Array();
fileTypes.push(imageFileFilter);
imageToBeArchivedFileReference.addEventListener(Event.SELECT, imageToBeArchived_fileSelectHandler);
imageToBeArchivedFileReference.browse(fileTypes);
}
There is an event handler which builds the value object when the image file has been selected:
private function imageToBeArchived_fileSelectHandler(event:Event):void
{
imageToBeArchivedFileReference.load();
imageToBeArchivedValueObject = new valueobjects.Image()
imageToBeArchivedValueObject.imageData = imageToBeArchivedFileReference.data;
imageToBeArchivedValueObject.description = imageToBeArchivedDescription.text;
imageToBeArchivedValueObject.captureDate = imageToBeArchivedFileReference.creationDate;
}
and there's an event handler which is invoked when the user clicks on the submit button to perform the image save/upload:
protected function archiveImageButton_clickHandler(event:MouseEvent):void
{
imageArchivalService.archiveImage(imageToBeArchived);
}
On the server side my Java class is doing a simple save of the POJO:
public void archiveImage(final Image image)
{
imageDao.saveOrUpdate(image);
}
When I set a breakpoint in the method above and look at the image variable it looks to be empty, so I'm assuming that the transformation from the Flex value object to the Java POJO did not go as expected and that there's more to it than just adding a RemoteClass alias in the Flex value object class.
Check out this example, it is all there.
http://biemond.blogspot.com/2008/08/flex-upload-and-download-with-blazeds.html
Don't use the loader class, use the readBytes call.
Make sure you go to the comments, there are valuable info there.
Cheers
Related
Recently I've started using shell and I noticed an improvement in page transitioning and a bug I was facing using NavigationPage was fixed just by replacing it with shell.
So I was excited to use it.
However soon after I realized I can't send objects from page to page through shell like I could using a constructer of a page. I searched a bit and now know that shell passes strings only. I turned the object into JSON but then faced an exception due to long URI length.
Honestly, I am disappointed. I thought something this important would be implemented in shell... but In any case, how do you guys work around this?
For Maui.
See (Xamarin) Process navigation data using a single method.
Also mentioned in maui issue. Adapting the Maui invocation there:
await Shell.Current.GoToAsync("//myAwesomeUri",
new Dictionary { {"data", new MyData(...)} });
This uses IQueryAttributable and ApplyQueryAttributes to pass an IDictionary<string, object> query.
(The Xamarin example shows IDictionary<string, string>, but its , object in Maui, so you can pass any object values.)
Thus the string parameters you pass can be used to look up corresponding objects.
From that (Xamarin) doc (modified to show looking up an object):
public class MonkeyDetailViewModel : IQueryAttributable, ...
{
public MyData Data { get; private set; }
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
Data = (MyData)query["data"];
}
...
}
For Xamarin Forms, the limitation to string values makes this a bit ugly. One approach is to have a static that holds possible objects, which you look up using a string. This is tolerable when the objects are all pre-defined, but is a bit clumsy if you are manually altering those objects.
public class MonkeyDetailViewModel : IQueryAttributable, ...
{
public static Dictionary<string, MyData> KeyedData;
// "static": One-time class constructor.
public static MonkeyDetailViewModel()
{
KeyedData = new Dictionary<string, MyData>();
KeyedData["data1"] = new MyData(...);
// ... other versions of the data ...
}
public MyData Data { get; private set; }
public void ApplyQueryAttributes(IDictionary<string, string> query)
{
string whichData = query["data"]; // In example, gets "data1".
Data = KeyedData[whichData];
}
...
}
Usage:
await Shell.Current.GoToAsync("//myAwesomeUri",
new Dictionary { {"data", "data1"} });
Xamarin NOTE: The static dictionary makes it possible to maintain multiple instances of MyData. The "hack" alternative is to have MyData Data be static, and explicitly set it before GoToAsync - but this is risky if you ever might have a MonkeyDetailView on nav stack, go to a second one, then go back to first one - you'll have overwritten the Data seen by the first view.
To avoid web service's problem of not being able to pass complex objects like dictionaries and trees, I created a small struct inside the class with a few values fields. However, the web service is in a seperate project in the solution and I'm unsure how the behind code that calls the webService function would know what the struct is. Should I copy the struct to the behind code file? Can I import it?
Here's a small example:
namespace mYWebService{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class Service1 : System.Web.Services.WebService
{
struct TreeData
{
private readonly string text;
private readonly string parent;
private string val;
public TreeData (string Text, string Parent)
{
this.text = Text;
this.parent = Parent;
this.val = "";
}
public TreeData (string Text, string Parent, string Value)
{
this.text = Text;
this.parent = Parent;
this.val = Value;
}
public string Text { get { return text; } }
public string Parent { get { return parent; } }
public string Value { get { return val; } }
}
[WebMethod]`
public TreeData getTree(){
TreeData myTree = new TreeData("1","2","3");
return myTree;
}}
When you generate the binding in the client code, all necessary complex data types will get created automatically, because they are described in the service's metadata. However, you should rather use WCF these days providing there's no hard requirement to use the old-fashioned .NET 2.0 web services (i.e. the WebService class).
You will have a hard time compiling this because you are exposing a private struct in a public method. In the very least, the struct must be made public. I also recommend that you put your struct outside of the class, since inner classes / structs /etc is bad practice (this is my personal opinion, however you do not see them used much in e.g. the .net framework, indicating that Microsoft doesn't like them much either).
Keep in mind that web services are distributed by nature, thus you should not have to rely on references to the class directly. This is a SOAP service (I think), and the framework will expose the metadata of the service. This metadata can be used by Visual Studio to auto generate a proxy client which can be used to call the service.
Here's a simple way to set up a proxy:
Start the web service project executable (not in debug mode, you will still need to be able to use Visual Studio for the next steps)
Select the project where your web service client (the code that calls the service) is located and add a service reference
This will open a dialog where you can enter the service endpoint (url). Enter the endpoint where the service is running, and you should be able to select in this dialog
Once the reference is added, some autogenerated proxy code should be generated for you. This will give you access to your Method.
Finally I do agree with Ondrej Tucny that you should look into WCF instead
I read that when working with SQLite local database in Flex (no other framework) it is considered best practice to have a singleton data access object class.
While the singleton part is clear, I am not sure what the DAO part would mean in a Flex app.
So, how do you create a data access object in Flex (for SQLite transactions)?
EDIT:
What I currently do is something like this:
public class Database
{
//constructor, instantiation of sqlConnection and others
//...
public function getPeople():Array
{
var query:SQLStatement=new SQLStatement();
query.sqlConnection=sqlConnection;//Defined in the constructor as static
query.text='select * from people order by name asc';
try
{
query.execute();
return query.getResult().data;
}
catch(e:SQLError){}
return null;
}
}
Thank you.
I have a dynamic ActionScript Class that is used to send parameters to a WebService. Some of these parameters are always present, so they are public properties of the Class:
package
{
[Bindable]
public dynamic class WebServiceCriteria
{
public var property1:int;
public var property2:String;
public var property3:String;
public var property4:String;
}
}
But, I am also adding properties at runtime that can change over time:
criteria.runTimeProperty = "1";
I'm not very familiar with using dynamic classes, so I was wondering if it is possible to "remove" the new property. Let's say the next time I call the WebService I don't want that property sent - not even as a null. How can I remove it from the Class instance without creating a new instance each time?
I believe all you'd need to do is this:
delete criteria.runTimeProperty;
or
delete criteria["runTimeProperty"];
Either should do the same thing.
See the delete documentation for specifics.
Suppose I use the [RemoteClass] tag to endow a custom Flex class with serialization intelligence.
What happens when I need to change my object (add a new field, remove a field, rename a field, etc)?
Is there a design pattern for handling this in an elegant way?
Your best bet is to do code generation against your backend classes to generation ActionScript counterparts for them. If you generate a base class with all of your object properties and then create a subclass for it which is never modified, you can still add custom code while regenerating only the parts of your class that change. Example:
java:
public class User {
public Long id;
public String firstName;
public String lastName;
}
as3:
public class UserBase {
public var id : Number;
public var firstName : String;
public var lastName : String;
}
[Bindable] [RemoteClass(...)]
public class User extends UserBase {
public function getFullName() : String {
return firstName + " " + lastName;
}
}
Check out the Granite Data Services project for Java -> AS3 code generation.
http://www.graniteds.org
Adding or removing generally works.
You'll get runtime warnings in your trace about properties either being missing or not found, but any data that is transferred and has a place to go will still get there. You need to keep this in mind while developing as not all your fields might have valid data.
Changing types, doesn't work so well and will often result in run time exceptions.
I like to use explicit data transfer objects and not to persist my actual data model that's used throughout the app. Then your translation from DTO->Model can take version differences into account.