HowTo: FDS-Tomcat + Datamanagement + Hibernate

8. Juli 2008 – 14:14

Einleitung

Das wird das letzte HowTo rund um die RIA-Entwicklung mit Flex, den LCDS und Hibernate auf den beiden Servern BlazeDS und FDS-Tomcat. Bisher haben wir gesehen wie man diese auf einem Linuxsystem installiert, mit Servlets Datenbankoperationen handelt und wie man dann mit Hibernate und und Flex ein Front- und Backend entwickeln kann.

Bis jetzt haben wir die Daten an den Client per RPC(HTTP Service und RemoteObject) gesendet und empfangen. Jetzt benutzen wir das wohl innovativste Element der Live Circle Data Services. Den synchronen Remote-Zugriff. Im Gegensatz dazu verlief alles bis jetzt asynchron und musste über das entspechende Result-Event gelöst werden. Jetzt werden Änderungen an den Daten zwischem dem Server und (wahlweise) allen Clients instant aktualisiert. Das heißt wenn ein Client Daten ändert wird automatisch das Backend informiert, welches sich sofort um die persistente Speicherung durch Hibernate kümmert und alle anderen Clients über die entsprechenden Änderungen informiert(push).

Wir verwenden dazu nur noch den FDS-Tomcat da dieser Service nicht im BlazeDS integriert ist. Sicherlich würde sich das nachrüsten lassen, jedoch habe ich mich damit nicht beschäftigt. Prinziepell halte ich mich an das Sample 8: Data Management Services aus dem Testdrive des FDS-Tomcat’s. Es kann also nicht schaden sich die Sachen dazu und das direkte Tutorial anzuschauen, da ich lediglich den bekannten HibernateHandler erweitere und nicht weiter auf Konfigurationen eingehe.

Im Übrigen benutzen wir auch nicht den Hibernate Assembler/Adapter sondern bleiben bei der direkten Hibernate-Implementierung. Falls ihr euch für diesen Assembler interessiert gibt es bei den Testdrive-Tutorials ebenfalls ein Beispiel. Das ist sehr ähnlich dem Sample 8 benutzt dann aber Hibernate.

Um die Umsetzung nachvollziehen zu können, möchte ich euch wieder gleich den Source geben. Darin erhalten ist dann ebenfalls gleich wieder ein SQL-Dump.

Die Umsetzung

Das Backend

Für die Umsetzung bedienen wir uns wieder der Stream-Tabelle aus dem Servlets-HowTo.

Nun werden wir ähnlich wie im Sample 8 die Tabelle auslesen und in ein DataGrid schreiben. Es wird nicht viel Arbeit, da wir nur eine neue Klasse einführen werden und ansonsten nur vorhandene Sachen erweitern.

Anfangen möchte ich mit dem sogenannten Streamassembler. Dieser implemtiert den AbstractAssembler aus dem LCDS. Das heißt wir müssen die Methoden fill(), getItem(), update() und deleteItem() überschreiben. Der Assembler ist sehr wichtig, da seine Methoden aufgerufen werden wenn es zu Änderungen am Tabelleninhalt kommt. Das heißt unsere Client arbeitet nicht mehr direkt mit dem HibernateAssembler. Das macht jetzt der Streamassembler direkt in den überschriebenen Funktionen. Da zum Aktualisieren der Daten aber erstmal nur fill() und update() wichtig ist, beschränke ich mich auf deren Implementierung. Die anderen könnt ihr sicher alleine implementieren 🙂

package flex.radioSiTY;

import java.util.List;
import java.util.Collection;
import java.util.Map;

import flex.data.DataSyncException;
import flex.data.assemblers.AbstractAssembler;

public class StreamAssembler extends AbstractAssembler {

	public Collection fill(List fillArgs) {
		HibernateHandler service = new HibernateHandler();
		return service.getStreams();
	}

	/*public Object getItem(Map identity) {
		
		}
	}*/

	public void createItem(Object item) {
		
	}

	public void updateItem(Object newVersion, Object prevVersion, List changes) {
		HibernateHandler service = new HibernateHandler();
		service.update((Stream) newVersion);		
	}

	public void deleteItem(Object item) {
		
	}
	
}

Nun kommen die Änderungen an unserem bekannten HibernateHandler. Diesem fügen wir die zwei neuen Funktionen, die der StreamAssembler benötigt, hinzu:

public List getStreams() throws DAOException {

		List list = new ArrayList();
		Session sess = null;
		Transaction trx = null;

		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			System.out.println("\nStreams:");
			List streams = sess.createQuery("from Stream").list();
			for (int i = 0; i < streams.size(); i++) {
				Stream stream = (Stream) streams.get(i);
				list.add(new Stream(stream.getId(), stream
						.getUrl(), stream.getHomepage(), stream.getName(),
						stream.getgenreId(), stream.getImage()));
			}
				trx.commit();
			} catch (HibernateException ex) {
				if (trx != null)
					try {
						trx.rollback();
					} catch (HibernateException exRb) {
					}
				throw new RuntimeException(ex.getMessage());
			} finally {
				try {
					if (sess != null)
						sess.close();
				} catch (Exception exCl) {
				}
			}
		return list;

	}
	
	public void update(Stream stream) throws DAOException {

		Session sess = null;
		Transaction trx = null;
		
		try {
			sess = sessionFactory.openSession();
			trx = sess.beginTransaction();
			
			sess.update(stream);
			trx.commit();
		} catch (HibernateException ex) {
			if (trx != null)
				try {
					trx.rollback();
				} catch (HibernateException exRb) {
					System.out.println(exRb.toString());
				}
			throw new RuntimeException(ex.getMessage());
		} finally {
			try {
				if (sess != null)
					sess.close();
			} catch (Exception exCl) {
			}
		}

	}

Damit das ganze funktionieren kann brauchen wir in der Streamklasse noch zwei Konstruktoren:

package flex.radioSiTY;

import java.util.*;

public class Stream 
{
  private int    id;
  private String url;
  private String homepage;
  private String name;
  private int genreId;
  private String image;
  private Set    user     = new HashSet();
  private Set    comments = new HashSet();
  
  public Stream() {name = "test"; }
  
  public Stream(int id, String url, String homepage, String name, int genreId, String image) {
		this.id = id;
		this.url = url;
		this.homepage = homepage;
		this.image = image;
		this.name = name;
		this.genreId = genreId;		
	}
  
  public Stream(Stream stream) {
		this.id = stream.getId();
		this.url = stream.getUrl();
		this.homepage = stream.getHomepage();
		this.image = stream.getImage();
		this.name = stream.getName();
		this.genreId = stream.getgenreId();	
	}

  public int    getId()         { return id; }
  public String getUrl()    { return url; }
  public String getHomepage()    { return homepage; }
  public String getName()      { return name; }
  public int getgenreId()    { return genreId; }
  public String getImage()      { return image; }
  public Set    getUser()     { return user; }
  public Set    getComments() { return comments; }

  public void setId(         int id         ) { this.id = id; }
  public void setUrl( String url    ) { this.url = url; }
  public void setHomepage( String homepage    ) { this.homepage = homepage; }
  public void setName( String name    ) { this.name = name; }
  public void setgenreId ( int genre    ) { this.genreId = genre; }
  public void setImage(   String image      ) { this.image = image; }
  public void setUser(     Set user     ) { this.user = user; }
  public void setComments( Set comments ) { this.comments = comments; }
}

Das waren jetzt auch schon alle Änderungen die das Backend betreffen.

Das Frontend

Für das Frontend erstellen wir einfach ein Datagrid, welches nun durch den StreamAssembler über die Methode fill() gefüllt wird. Das Datagrid liest dann die Collection automatisch ein. Ganz wichtig ist jetzt hier das wir den DataService und nicht mehr das RemoteObject benutzen. Hier der Source:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" backgroundColor="#FFFFFF" viewSourceURL="srcview/index.html">
	
	<mx:ArrayCollection id="streams"/> 
	<mx:DataService id="ds" destination="stream"/>
	<Stream/>
	
	<mx:DataGrid dataProvider="{streams}" editable="true" width="100%" height="100%">
		<mx:columns>
			<mx:DataGridColumn dataField="url" headerText="Url"/>
			<mx:DataGridColumn dataField="homepage" headerText="Homepage"/>
			<mx:DataGridColumn dataField="name" headerText="Name"/>
			<mx:DataGridColumn dataField="genreId" headerText="Genre"/>
			<mx:DataGridColumn dataField="image" headerText="Image"/>
		</mx:columns>
	</mx:DataGrid>
	
	<mx:Button label="Get Data" click="ds.fill(streams)"/> 
	
</mx:Application>

Die Methode updateItem() des StreamAssemblers muss nicht aufgerufen werden, da diese bei Änderungen an der Tabelle automatisch aufgerufen wird 🙂

Damit das ganze überhaupt funktionieren kann müssen wir natürlich noch die Destination für den DataService anlegen. Das passiert ähnlich wie bei den RemoteObjects. Nur benutzen wir jetzt nicht mehr die remoting-config.xml sondern die datamanagement-config.xml!Einfach folgenden Eintrag hinzufügen:

<destination id="stream">

        <adapter ref="java-dao" />

        <properties>
            <source>flex.radioSiTY.StreamAssembler</source>
            <scope>application</scope>

            <metadata>
                <identity property="id"/>
            </metadata>

            <network>
                <session-timeout>20</session-timeout>
                <paging enabled="false" pageSize="10" />
                <throttle-inbound policy="ERROR" max-frequency="500"/>
                <throttle-outbound policy="REPLACE" max-frequency="500"/>
            </network>
        </properties>
    </destination>

Conclusion

So das wars dann auch schon. Öffnet die Tabelle einfach mal in zwei Tab’s und ändert in der einen etwas. Siehe da die andere Tabelle wird instant aktualisiert 🙂

Leider habe ich mich nicht mit den verschiedenen Einstellungsmöglichkeiten was das Datamanagement betrifft auseinandersetzten können. Da gibt es einige Sachen die sich konfigurieren lassen. Zum Beispiel auf welchen Clients überhaupt aktualisiert werden soll etc. Dazu findet ihr aber in dem FDMS-Tutorial wenn ich micht recht entsinne einiges.

So das wars für diese How-To Reihe. Ich hoffe bei euch hat alles geklappt und hattet damit genausoviel Spass wie ich 🙂

Bei Fragen und Anregungen könnt ihr mir wie immer mailen oder ein Kommentar hinterlassen!

  1. 1 Trackback(s)

  2. Jul 15, 2008: Java News 3 | News | Programmierung & Software Entwicklung Java J2ME Android

Post a Comment