czwartek, 19 listopada 2009

Grails + Flex + App engine cz. 2

W poprzednim wpisie udało nam się stworzyć aplikacje w Grails i Flex oraz uruchomić ją w środowisku testowym App Engine. Teraz czas zdeployować ją w chmurze.
Jeśli nasza aplikacja nazywa się inaczej niż aplikacja utworzona w Google App Engine należy w pliku grails-app/conf/Config.groovy dodać następujący wpis:
google.appengine.application="nazwa aplikacji"

Google App Engine nie lubi wersji zawierających kropki dlatego poleceniem:
grails set-version 1
ustawiamy wersje aplikacji na jeden.

Kolejnym krokiem jest spakowanie aplikacji do pliku war:
grails app-engine package

Nie pozostaje nam nic innego jak tylko wysłać aplikacje na serwer Google:

grails app-engine deploy

Bywa że pierwsze logowanie do usługi zakończy się niepowodzeniem! Jest to spowodowane błędem w skrypcie Antowym. W takim wypadku należy użyć polecienia:

$APPENGINE_HOME/bin/appcfg.cmd update ./target/war

Aplikacja dostępna pod adresem:
http://todo-flex.appspot.com/main.swf

środa, 18 listopada 2009

Grails + Flex + App engine

Spróbujmy dziś stworzyć aplikacje w której back-end zostanie napisany w Groovy i Grails front-end zostanie stworzony w Flexie a całość będzie hostowana w Google App Engine.
Najpierw musimy stworzyć nową aplikacje w App Engine. Podajemy nazwę (w moim przypadku wolna okazała się dopiero nazwa 'todo-flex') oraz krótki opis.
Gdy w chmurze mamy już stworzoną aplikacje możemy przejść do tworzenia aplikacji w Grails.
Tworzymy aplikacje:


grails create-app todo-flex


Po przejściu do katalogu zaczynamy konfigurcje pluginów.
App Engine używa JDO lub JPA dlatego dla pewności usuwamy plugin Hibernate:

grails uninstall-plugin hibernate


Instalujemy plugin App Engine:

grails install-plugin app-engine

wybieramy JPA.

Instalujemy plugin umożliwiający korzystanie z GORM wraz z JPA:

grails install-plugin gorm-jpa


Ostatnim pluginem jest plugin dla Flexa:

grails install-plugin flex

Projekt mamy skonfigurowany czas na implementację.
Najpierw tworzymy klasę domenową:

grails create-domain-class com.mcz.ToDo


Kolejnym krokiem jest stworzenie serwisu:

grails create-service com.mcz.ToDo


W tym momencie możemy zaimportować projekt do Eclipse wybierając File/Import/General/Existing Projects into Workspace.

Wypełniamy klasę domenową kodem, w naszym przykładzie klasa com.mcz.ToDo bedzie miała nastepującą postać:

@Entity
class ToDo implements Serializable {

@Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 Long id

 @Basic
 String Title

 @Basic
 String text

}

Jak widać jest to zwykłe ziarno JPA.

Serwis ToDoService ma następującą postać:
class ToDoService {

 static expose = ['flex-remoting']

    boolean transactional = true

    def getToDosList() {
     ToDo.list(sort:"dateInserted", order:"desc")
    }

    def save(todo){
     todo.id = null
     todo.dateInserted = new Date()
     todo.save()
    }

   def deleteToDo(id){
     def todo = ToDo.get(id);
     todo.delete()
    }
}
Jest to standardowy serwis grailsowy, jedyne co jest w nim warte odnotowania, to statyczna lista  expose = ['flex-remoting'] mówiąca to tym, że ten serwis będzie dostępny poprzez Flex RemoteObject.

To tyle jeśli chodzi o stronę serwerową czas na widok.
Nadajemy projektowi Flex Project Nature, pozostawiamy wszystkie ustawienia na default.
Tworzymy w ActionScript klasę odpowiedzialną za mapowanie obiektów ToDo tak aby mogły być przesyłane z serwera do widoku.Kod klasy powinien wyglądać tak:
package com.mcz
{
 [Bindable]
    [RemoteClass(alias="com.mcz.ToDo")]
 public class ToDo
 {
  public function ToDo()
  {
  }
  public var id:Number;
  public var title:String;
  public var text:String;
  public var dateInserted:Date;

 }
}
W klasie nie ma nic specjalnego oprócz dwóch elementów:
1. [Bindable] - dzięki elementowi MetaData, jeśli wartość któregoś z pól zostanie zmieniona, nastąpi wygenerowanie zdarzenia.
2. [RemoteClass(alias="com.mcz.ToDo")] - wskazuje na który obiekt znajdujący się po stronie serwerowej dana klasa ma być mapowana.


W katalogu src znajduje się plik main.mxml to w nim tworzymy widok. Najciekawszym elementem jest konfiguracja RemoteObject pozwalająca wywoływać metody na serwisie ToDoService:
<mx:RemoteObject id="ro" destination="toDoService" fault="faultHandler(event)">
<mx:method name="getToDosList" result="getToDosListHandler(event)"/>
</mx:RemoteObject>
<mx:Script>
<![CDATA[
...

[Bindable]
private var todoList:ArrayCollection;

private function getToDosListHandler(event:ResultEvent):void{
    todoList = event.result as ArrayCollection;
}
...
]]>
</mx:Script>
Mamy już stworzoną stronę serwerową oraz widok potrzebne jest jeszcze tylko kilka zmian w konfiguracji:
1. W pliku grails-app/conf/Config.groovy dodajemy linie flex.webtier.compiler.enabled = false, wyłączamy w ten sposób kompilację w runtimie dla plików mxml. W przeciwnym wypadku podczas uruchamiania aplikacji dostaniemy informację o tym, że serwlet próbuje zapisu na dysku co w App Engine jest niedozwolone.
2. W pliku web-app/WEB-INF/flex/service-config.xml:
a)Dodajemy
<system>
 <manageable>false</manageable> </system>
b) Aplikacje w App Engine hostowane są bez kontekstu dlatego musimy usunąć {context.root} z channel-definition

Ostatnią rzeczą jeśli chodzi o ustawienia projektu jest wskazanie kompilatorowi Flexa zmodyfikowanego pliku service-config.xml. Aby to zrobić klikamy prawym przyciskiem na projekcie i wybieramy Properies/Flex Compiler/ Additional compiler arguments dodajemy -services [ścieżka względna dla pliku main.mxml]/services-config.xml u mnie ten wpis ma postać -services ../web-app/WEB-INF/flex/services-config.xml.

Kompilujemy projekt do kartoteki web-app za pomocą Export Release Build i gotowe!
Teraz wystarczy tylko przetestować naszą aplikacje.
W konsoli będąc w kartotece projektu wpisujemy
grails app-engine run

W kolejnym wpisie pokaże jak wersjonować oraz umieszczać aplikacje w App Engine.
Kod aplikacji dostępny pod adresem:
http://svn.xp-dev.com/svn/blog_svn/