<?xml version="1.0" encoding="UTF-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.amf.server">
    <title>Zend_Amf_Server</title>

    <para>
        <classname>Zend_Amf_Server</classname> bietet einen <acronym>RPC</acronym>-artigen Server
        für die Behandlung der Anfragen die vom Adobe Flash Player durchgeführt werden indem das
        <acronym>AMF</acronym> Protokoll verwendet wird. Wie alle Zend Framework Serverklassen,
        folgt es der SoapServer <acronym>API</acronym>, und bietet ein einfach zu merkendes
        Interface für die Erstellung von Servern.
    </para>

    <example id="zend.amf.server.basic">
        <title>AMF Server Grundlagen</title>

        <para>
            Angenommen wir haben eine Klasse <classname>Foo</classname> mit einer Anzahl von
            öffentlichen Methoden erstellt. Man kann einen <acronym>AMF</acronym> Server erstellen
            indem der folgende Code verwendet wird:
        </para>

        <programlisting language="php"><![CDATA[
$server = new Zend_Amf_Server();
$server->setClass('Foo');
$response = $server->handle();
echo $response;
]]></programlisting>

        <para>
            Alternativ kann stattdessen man eine einfache Funktion als Callback anhängen:
        </para>

        <programlisting language="php"><![CDATA[
$server = new Zend_Amf_Server();
$server->addFunction('myUberCoolFunction');
$response = $server->handle();
echo $response;
]]></programlisting>

        <para>
            Man kann auch mehrere Klassen und Funktionen mischen und verwenden. Wenn man das macht
            wird empfohlen das jede von Ihnen einen Namespace erhält um sicherzustellen das keine
            Kollision von Methodennamen stattfindet; das kann durchgeführt werden indem man einfach
            ein zweites Stringargument entweder an <methodname>addFunction()</methodname> oder an
            <methodname>setClass()</methodname> übergibt:
        </para>

        <programlisting language="php"><![CDATA[
$server = new Zend_Amf_Server();
$server->addFunction('myUberCoolFunction', 'my')
       ->setClass('Foo', 'foo')
       ->setClass('Bar', 'bar');
$response = $server->handle();
echo $response;
]]></programlisting>

        <para>
            <classname>Zend_Amf_Server</classname> erlaubt es auch Services das Sie dynamisch
            geladen werden, basierend auf dem angegebenen Verzeichnispfad. Man kann dem Server so
            viele Verzeichnisse wie man will hinzufügen. Die Reihenfolge in der man die
            Verzeichnisse zum Server hinzufügt ist die Reihenfolge in der die
            <acronym>LIFO</acronym> Suche auf den Verzeichnissen durchgeführt wird um die Klasse
            zu finden. Das Hinzufügen von Verzeichnissen wird mit der
            <methodname>addDirectory()</methodname> Methode durchgeführt.
        </para>

        <programlisting language="php"><![CDATA[
$server->addDirectory(dirname(__FILE__) .'/../services/');
$server->addDirectory(dirname(__FILE__) .'/../package/');
]]></programlisting>

        <para>
            Wenn entfernte Services aufgerufen werden kann der Quellname einen Unterstrich ("_")
            oder Punkt (".") Begrenzer im Verzeichnis haben. Wenn ein Unterstrich verwendet wird
            werden die Namenskonventionen der <acronym>PEAR</acronym> und Zend Framework Klassen
            verwendet. Das bedeutet das wenn man das Sevice com_Foo_Bar
            aufruft wird der Server nach der Datei <filename>Bar.php</filename> suchen, und zwar in
            jedem der eingefügten Pfade unter <filename>com/Foo/Bar.php</filename>. Wenn die Punkt
            Notation für entfernte Services wie für <filename>com.Foo.Bar</filename> verwendet
            wird, wird jedem eingefügten Pfad <filename>com/Foo/Bar.php</filename> am Ende
            hinzugefügt um <filename>Bar.php</filename> automatisch zu laden.
        </para>

        <para>
            Alle <acronym>AMF</acronym> Anfragen die an das Skript gesendet werden, werden dann
            durch den Server behandelt, und eine <acronym>AMF</acronym> Antwort wird zurückgegeben.
        </para>
    </example>

    <note>
        <title>Alle angehängten Methoden und Funktionen benötigen einen Docblock</title>

        <para>
            Wie alle anderen Serverkomponenten im Zend Framework müssen die Klassenmethoden
            dokumentiert werden indem <acronym>PHP</acronym> Docblocks verwendet werden. Mindestens
            muß für jedes benötigte Argument eine Beschreibung angegeben werden sowie ein
            Rückgabewert. Als Beispiel:
        </para>

        <programlisting language="php"><![CDATA[
// Funktion zum Anhängen:

/**
 * @param  string $name
 * @param  string $greeting
 * @return string
 */
function helloWorld($name, $greeting = 'Hello')
{
    return $greeting . ', ' . $name;
}
]]></programlisting>

        <programlisting language="php"><![CDATA[
// Angehängte Klasse

class World
{
    /**
     * @param  string $name
     * @param  string $greeting
     * @return string
     */
    public function hello($name, $greeting = 'Hello')
    {
        return $greeting . ', ' . $name;
    }
}
]]></programlisting>

        <para>
            Andere anmerkungen können verwendet werden, werden aber ignoriert.
        </para>
    </note>

    <sect2 id="zend.amf.server.flex">
        <title>Zum Server von Flex aus verbinden</title>

        <para>
            Zum eigenen <classname>Zend_Amf_Server</classname> von einem Flex Projekt aus zu
            verbinden ist recht einfach; man muß zur Endpunkt <acronym>URI</acronym> des
            <classname>Zend_Amf_Server</classname> Sripts zeigen.
        </para>

        <para>
            Nehmen wir zum Beispiel an das man einen Server erstellt hat und Ihn in der
            <filename>server.php</filename> Datei im Anwendungsroot platziert, und die
            <acronym>URI</acronym> deswegen <filename>http://example.com/server.php</filename> ist.
            In diesem Fall würde man die <filename>services-config.xml</filename> Datei so
            modifizieren damit das channel endpoint uri Attribut auf diesen Wert gesetzt ist.
        </para>

        <para>
            Wenn man noch keine <filename>service-config.xml</filename> Datei erstellt hat kann man
            das tun, indem man das Projekt im Navigator Fenster öffnet. Auf dem Projektnamen
            rechts-klickt und 'properties' auswählt. Im Fenster der Projekteigenschaften muß man in
            das 'Flex Build Path' Menü, auf den 'Library path' Tab und sicherstellen das die
            '<filename>rpc.swc</filename>' Datei bei den Projektpfaden hinzugefügt ist und auf Ok
            drücken um das Fenster zu schließen.
        </para>

        <para>
            Man muß dem Compiler auch mitteilen das er die <filename>service-config.xml</filename>
            verwenden soll um den Endpunkt des RemoteObjects zu finden. Um das zu tun muß das
            Fenster der Projekteigenschaften nochmals durch einen rechts-klick auf das
            Projektverzeichnis vom Navigator aus geöffnet und Eigenschaften ausgewählt werden. Vom
            Eigenschaften-Popup muß 'Flex Compiler' aufgewählt und der String:
            <command>-services "services-config.xml"</command> hinzugefügt werden. Auf Apply
            drücken, anschließend auf OK um die Option zu aktualisieren. Was man jetzt getan hat,
            ist dem Flex Compiler zu sagen das er in der Datei
            <filename>services-config.xml</filename> nach Laufzeitvariablen schauen soll die von
            der RemotingObject Klasse verwendet werden.
        </para>

        <para>
            Jetzt müssen wir Flex mitteilen welche Konfigurationsdateien der Services für die
            Verbindung zu unseren entfernten Methoden zu verwenden sind. Aus diesem Grund muß eine
            neue '<filename>services-config.xml</filename>' Datei im Flexprojekt src Verzeichnis
            erstellt werden. Um das zu tun, muß man auf den Projektfolder rechts klicken und 'new'
            'File' auswählen was ein neues Fenster öffnet. Anschließend das Projektverzeichnis
            auswählen und dann die Datei '<filename>services-config.xml</filename>' benennen und
            auf Beenden drücken.
        </para>

        <para>
            Flex hat eine neue <filename>services-config.xml</filename> erstellt und Sie geöffnet.
            Verwende den folgenden Beispieltext für die <filename>services-config.xml</filename>
            Datei. Es muß sichergestellt werden das der Endpunkt so aktualisiert wird das er zu dem
            des eigenen Testservers passt. Anschließend sicherstellen das die Datei gespeichert
            wird.
        </para>

        <programlisting language="xml"><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
    <services>
        <service id="zend-service"
            class="flex.messaging.services.RemotingService"
            messageTypes="flex.messaging.messages.RemotingMessage">
            <destination id="zend">
                <channels>
                    <channel ref="zend-endpoint"/>
                </channels>
                <properties>
                    <source>*</source>
                </properties>
            </destination>
        </service>
    </services>
    <channels>
        <channel-definition id="zend-endpoint"
            class="mx.messaging.channels.AMFChannel">
            <endpoint uri="http://example.com/server.php"
                class="flex.messaging.endpoints.AMFEndpoint"/>
        </channel-definition>
    </channels>
</services-config>
]]></programlisting>

        <para>
            Es gibt zwei Schlüsselpunkt im Beispiel. Erstens, aber letztes im Code, erstellen wir
            einen <acronym>AMF</acronym> Kanal, und spezifizieren den Endpunt als die
            <acronym>URL</acronym> zu unserem <classname>Zend_Amf_Server</classname>:
        </para>

        <programlisting language="xml"><![CDATA[
<channel-definition id="zend-endpoint"
    <endpoint uri="http://example.com/server.php"
        class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
]]></programlisting>

        <para>
            Es ist zu beachten das wir diesem Kanal einen Identifikator, "zend-endpoint", gegeben
            haben. Das Beispiel erstellt ein Ziel für den Service auf zu diesen Kanal zeigt,
            und fügt es auch als ID hinzu -- in diesem Zall "zend".
        </para>

        <para>
            In unseren Flex <acronym>MXML</acronym> Dateien müssen wir ein RemoteObject an das
            Service binden. In <acronym>MXML</acronym> kann das wie folgt getan werden:
        </para>

        <programlisting language="xml"><![CDATA[
<mx:RemoteObject id="myservice"
    fault="faultHandler(event)"
    showBusyCursor="true"
    destination="zend">
]]></programlisting>

        <para>
            Hier haben wir ein neues entferntes Objekt definiert das durch "myservice"
            identifiziert an das Serviceziel "zend" gebunden ist das wir in der
            <filename>services-config.xml</filename> Datei definiert haben. Dann rufen wir die
            Methoden auf Ihnen in unserem ActionScript einfach durch Aufruf von
            "myservice.&lt;method&gt;" auf. Als Beispiel:
        </para>

        <programlisting language="ActionScript"><![CDATA[
myservice.hello("Wade");
]]></programlisting>

        <para>
            Wenn wir Namespaces aktivieren würden wir "myservice.&lt;namespace&gt;.&lt;method&gt;"
            verwenden:
        </para>

        <programlisting language="ActionScript"><![CDATA[
myservice.world.hello("Wade");
]]></programlisting>

        <para>
            Für weitere Informationen über den Aufruf von Flex RemoteObject, <ulink
                url="http://livedocs.adobe.com/flex/3/html/help.html?content=data_access_4.html">besuchen
            Sie die Adobe Flex 3 Hilfeseite</ulink>.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.errors">
        <title>Fehlerbehandlung</title>

        <para>
            Standardmäßig werden alle Exceptions die in den angehängten Klassen oder Funktionen
            geworfen werden gefangen und als <acronym>AMF</acronym> Fehlermeldungen zurückgegeben.
            Trotzdem wird der Inhalt des ErrorMessage Objekts variieren basierend darauf ob der
            Server im "Produktions" Modus ist (der Standardzustand) oder nicht.
        </para>

        <para>
            Wenn er in Produktionsmodus ist wird nur der Exceptioncode zurückgegeben. Wenn der
            Produktionsmodus ausgeschaltet wird -- etwas das nur für das Testen getan werden sollte
            -- werden die meisten Exceptiondetails zurückgegeben: Die Meldung der Exception, die
            Zeile, und der Backtrace werden alle angehängt.
        </para>

        <para>
            Um den Produktionsmodus auszuschalten muß das folgende getan werden:
        </para>

        <programlisting language="php"><![CDATA[
$server->setProduction(false);
]]></programlisting>

        <para>
            Um Ihn wieder einzuschalten, muß stattdessen einfach ein boolscher
            <constant>TRUE</constant> Wert übergeben werden:
        </para>

        <programlisting language="php"><![CDATA[
$server->setProduction(true);
]]></programlisting>

        <note>
            <title>Der Produktionsmode sollte sparsam deaktiviert werden!</title>

            <para>
                Wir empfehlen den Produktionsmode nur während der Entwicklung auszuschalten.
                Exceptionmeldungen und Backtraces können sensitive Systeminformationen enthalten
                auf die nicht von Aussenstehenden zugegriffen werden darf. Selbst wenn
                <acronym>AMF</acronym> ein binäres Format ist, ist die Spezifikation offen, was
                bedeutet das jeder den Payload potentiell deserialisieren kann.
            </para>
        </note>

        <para>
            Ein Feld bei dem man im speziellen Vorsichtig sein muß ist bei <acronym>PHP</acronym>
            Fehlern selbst. Wenn die <acronym>INI</acronym> Direktive
            <property>display_errors</property> aktiviert ist, wird jeder <acronym>PHP</acronym>
            Fehler für das aktuelle Error Reporting Level direkt in der Ausgabe dargestellt -- was
            den <acronym>AMF</acronym> Antwortpayload potentiell unterbrechen kann. Wir empfehlen
            die <property>display_errors</property> Direktive in der Produktion auszuschalten um
            solche Probleme zu verhindern.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.response">
        <title>AMF Antworten</title>

        <para>
            Fallweise ist es gewünscht das Antwortobjekt leicht zu manipulieren, typischerweise um
            zusätzliche Nachrichtenheader zurückzugeben. Die <methodname>handle()</methodname>
            Methode des Servers gibt das Antwortobjekt zurück, was es erlaubt das zu tun.
        </para>

        <example id="zend.amf.server.response.messageHeaderExample">
            <title>Nachrichtenheader der AMF Antwort hinzufügen</title>

            <para>
                In diesem Beispiel fügen wir einen 'foo' Nachrichtenheader mit dem Wert 'bar' zu der
                Antwort hinzu bevor sie zurückgegeben wird.
            </para>

            <programlisting language="php"><![CDATA[
$response = $server->handle();
$response->addAmfHeader(new Zend_Amf_Value_MessageHeader('foo', true, 'bar'))
echo $response;
]]></programlisting>

        </example>
    </sect2>

    <sect2 id="zend.amf.server.typedobjects">
        <title>Typ Objekte</title>

        <para>
            Ähnlich wie <acronym>SOAP</acronym>, erlaubt es <acronym>AMF</acronym> Objekte zwischen
            dem Client und dem Server zu übergeben. Das erlaubt eine große Flexibilität und Bindung
            zwischen den zwei Umgebungen.
        </para>

        <para>
            <classname>Zend_Amf</classname> bietet drei Methoden für das Mappen von ActionScript und
            <acronym>PHP</acronym> Objekten.
        </para>

        <itemizedlist>
            <listitem>
                <para>
                    Erstens kann man explizite Bindungen auf Serverlevel erstellen indem die
                    <methodname>setClassMap()</methodname> Methode verwendet wird. Das erste
                    Argument ist der ActionScript Klassenname, das zweite ist der Name der
                    <acronym>PHP</acronym> Klasse auf die gemappt wird:
                </para>

                <programlisting language="php"><![CDATA[
// Die ActionScript Klasse 'ContactVO' auf die PHP Klasse 'Contact' mappen:
$server->setClassMap('ContactVO', 'Contact');
]]></programlisting>
            </listitem>

            <listitem>
                <para>
                    Zweitens kann die öffentliche Eigenschaft <varname>$_explicitType</varname> in
                    der <acronym>PHP</acronym> Klasse gesetzt werden, wobei der Wert die
                    ActionScript Klasse repräsentiert auf die gemappt wird:
                </para>

                <programlisting language="php"><![CDATA[
class Contact
{
    public $_explicitType = 'ContactVO';
}
]]></programlisting>
            </listitem>

            <listitem>
                <para>
                    Drittens, in ähnlicher Art und Weise, kann eine öffentliche Methode
                    <methodname>getASClassName()</methodname> in der <acronym>PHP</acronym> Klasse
                    definiert werden; diese Methode sollte die passende ActionScript Klasse
                    zurückgeben:
                </para>

                <programlisting language="php"><![CDATA[
class Contact
{
    public function getASClassName()
    {
        return 'ContactVO';
    }
}
]]></programlisting>
            </listitem>
        </itemizedlist>

        <para>
            Auch wenn wir nun den ContactVO auf dem Server erstellt have müssen wir nun seine
            korrespondierende Klasse in <acronym>AS3</acronym> für das Server Objekt erstellen das
            gemappt werden soll.
        </para>

        <para>
            Einen Rechtsklick auf das src Verzeichnis des Flex Projekts und New -> ActionScript File
            auswählen. Name der Datei ContactVO und finish drücken um die neue Datei zu sehen.
            Den folgenden Code in die Datei kopieren um die Erstellung der Klasse fertigzustellen.
        </para>

        <programlisting language="as"><![CDATA[
package
{
    [Bindable]
    [RemoteClass(alias="ContactVO")]
    public class ContactVO
    {
        public var id:int;
        public var firstname:String;
        public var lastname:String;
        public var email:String;
        public var mobile:String;
        public function ProductVO():void {
        }
    }
}
]]></programlisting>

        <para>
            Die Klasse ist syntaktisch identisch zu der von <acronym>PHP</acronym> mit dem gleichen
            Namen. Die Variablennamen sind exakt die gleichen und müssen im gleichen Fall sein um
            korrekt zu arbeiten. Es gibt zwei eindeutige <acronym>AS3</acronym> Metatags in dieser
            Klasse. Das Erste kann gebunden werden was ein Änderungsevent wirft wenn es
            aktualisiert wird. Das zweite Tag ist das RemoteClass Tag welches definiert das diese
            Klasse ein gemapptes entferntes Objekt haben kann, in diesem Fall mit dem Aliasnamen
            <emphasis>ContactVO</emphasis>. Es ist erforderlich das dieses Tag und der Wert der in
            der <acronym>PHP</acronym> Klasse gesetzt wurde, strikt identisch sind.
        </para>

        <programlisting language="as"><![CDATA[
[Bindable]
private var myContact:ContactVO;

private function getContactHandler(event:ResultEvent):void {
    myContact = ContactVO(event.result);
}
]]></programlisting>

        <para>
            Das folgende Ergebnisevent vom Serviceaufruf wird sofort zu Flex ContactVO gecastet.
            Alles das bei myContact gebunden ist, wird mit den von ContactVO zurückgegebenen
            Daten aktualisiert.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.resources">
        <title>Ressourcen</title>

        <para>
            <classname>Zend_Amf</classname> bietet Tools für das Mappen von Ressource Typen die
            von Service Klassen in von ActionScript verwendbaren Daten zurückgegeben werden.
        </para>

        <para>
            Um spezielle Ressource Typen zu behandeln, muss der Benutzer eine Plugin Klasse
            erstellen die nach dem Ressource Namen benannt ist, mit großgeschriebenen Wörtern
            und entfernten Leerzeichen (ein Ressouce Typ "mysql result" wird zu MysqlResult),
            mit einem Präfix, z.B. <classname>My_MysqlResult</classname>. Diese Klasse sollte eine
            Methode implementieren, <methodname>parse()</methodname>, die ein Argument - die
            Ressource - annimmt und den Wert zurückgibt der an das ActionScript gesendet werden
            sollte. Die Klasse sollte in der Datei vorhanden sein nachdem die letzte Komponente des
            Namens benannt ist, z.B. <filename>MysqlResult.php</filename>.
        </para>

        <para>
            Das Verzeichnis das die Plugins für das Ressource Handling enthält sollte beim Typloader
            von <classname>Zend_Amf</classname> registriert sein:
        </para>

        <programlisting language="php"><![CDATA[
Zend_Amf_Parse_TypeLoader::addResourceDirectory(
    "My",
    "application/library/resources/My"
);
]]></programlisting>

        <para>
            Für eine detailierte Diskussion für das Laden von Plugins, sehen Sie bitte in das
            Kapitel <link linkend="zend.loader.pluginloader">Plugin Loader</link>.
        </para>

        <para>
            Das Standardverzeichnis für Ressourcen von <classname>Zend_Amf</classname> wird
            automatisch registriert und enthält aktuell Handler für "mysql result" und "stream"
            Ressourcen.
        </para>

        <programlisting language="php"><![CDATA[
// Beispiel für die Implementierung von Ressourcen und die Behandlung
// von Mysql Ergebnis Typen
class Zend_Amf_Parse_Resource_MysqlResult
{
    /**
     * Parse resource into array
     *
     * @param resource $resource
     * @return array
     */
    public function parse($resource) {
        $result = array();
        while($row = mysql_fetch_assoc($resource)) {
            $result[] = $row;
        }
        return $result;
    }
}
]]></programlisting>

        <para>
            Der Versuch einen unbekannten Ressource Typ zurückzugeben (z.B. einen für den kein
            Handler Plugin existiert) führt zu einer Exception.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.flash">
        <title>Von Flash aus auf den Server verbinden</title>

        <para>
            Auf den <classname>Zend_Amf_Server</classname> vom Flash Projekt aus zu verbinden ist
            etwas anders als von Flex aus. Trotzdem sind die Funktionen mit
            <classname>Zend_Amf_Server</classname> die gleichen wie mit Flex sobald die Verbindung
            erstellt wurde. Das folgende Beispiel kann auch von einer Flex <acronym>AS3</acronym>
            Datei aus verwendet werden. Wir werden die selbe <classname>Zend_Amf_Server</classname>
            Konfiguration mit der World Klasse unserer Verbindung wiederverwenden.
        </para>

        <para>
            Öffne Flash CS und erstelle eine neue Flash Datei (ActionScript 3). Benenne das
            Dokument <filename>ZendExample.fla</filename> und speichere das Dokument in einem
            Verzeichnis das wir für dieses Beispiel verwenden werden. Erstelle eine neue
            <acronym>AS3</acronym> Datei im selben Verzeichnis und benenne die Datei
            <filename>Main.as</filename>. Öffne beide Dateien im Editor. Wir werden jetzt diese
            zwei Dateien über die Document Klasse verbinden. Wähle ZendExample aus und klicke auf
            "stage". Im Eigenschaftsfenster von "stage" ändere die Document Klasse auf Main. Das
            verbindet die <filename>Main.as</filename> ActionScript Datei mit dem Benutzer
            Interface von <filename>ZendExample.fla</filename>. Wenn die Flashdatei ZendExample
            ausgeführt wird, dann wird die Klasse <filename>Main.as</filename> gestartet. Als
            nächstes werden wir ein ActionScript hinzufügen um den <acronym>AMF</acronym> Aufruf
            durchzuführen.
        </para>

        <para>
            Jetzt werden wir eine Main Klasse erstellen damit wir die Daten zum Server schicken und
            das Ergebnis anzeigen lassen können. Kopiere den folgenden Code in die
            <filename>Main.as</filename> Datei und wird werden den Code anschauen um zu erklären
            was die Rolle eines jeden Elements ist.
        </para>

        <programlisting language="as"><![CDATA[
package {
    import flash.display.MovieClip;
    import flash.events.*;
    import flash.net.NetConnection;
    import flash.net.Responder;

    public class Main extends MovieClip {
        private var gateway:String = "http://example.com/server.php";
        private var connection:NetConnection;
        private var responder:Responder;

        public function Main() {
            responder  = new Responder(onResult, onFault);
            connection = new NetConnection;
            connection.connect(gateway);
        }

        public function onComplete( e:Event ):void{
            var params = "Zum Server geschickt";
            connection.call("World.hello", responder, params);
        }

        private function onResult(result:Object):void {
            // Die zurückgegebenen Daten anzeigen
            trace(String(result));
        }

        private function onFault(fault:Object):void {
            trace(String(fault.description));
        }
    }
}
]]></programlisting>

        <para>
            Wir müssen zuerst zwei ActionScript Bibliotheken importieren die den Haufen an Arbeit
            erledigen. Das erste ist NetConnection welches wie eine Zweiwege-Leitung, zwischen dem
            Client und dem Server, funktioniert. Das zweite ist ein Responder Objekt welches die
            Rückgabewerte des Servers behandelt relativ zum Erfolg oder Mißerfolg des Aufrufs.
        </para>

        <programlisting language="as"><![CDATA[
import flash.net.NetConnection;
import flash.net.Responder;
]]></programlisting>

        <para>
            In der Klasse benötigen wir drei Variable um NetConnection, Responder, und die Gateway
            <acronym>URL</acronym> zu unserer <classname>Zend_Amf_Server</classname> Installation
            zu repräsentieren.
        </para>

        <programlisting language="as"><![CDATA[
private var gateway:String = "http://example.com/server.php";
private var connection:NetConnection;
private var responder:Responder;
]]></programlisting>

        <para>
            Im Main Contructor erstellen wir einen Responder und eine neue Verbindung zum
            <classname>Zend_Amf_Server</classname> Endpunkt. Der Responder definiert zwei
            unterschiedliche Methoden für die Behandlung des Servers. Der Einfachheit halber haben
            wir Sie onResult und onFault benannt.
        </para>

        <programlisting language="as"><![CDATA[
responder = new Responder(onResult, onFault);
connection = new NetConnection;
connection.connect(gateway);
]]></programlisting>

        <para>
            In der onComplete Funktion, welche ausgeführt wird sobald das Konstrukt fertiggestellt
            wurde, senden wir die Daten zum Server. Wird benötigen eine weitere zusätzliche Zeile
            die den Aufruf der <classname>Zend_Amf_Server</classname> World->hello Funktion
            durchführt.
        </para>

        <programlisting language="as"><![CDATA[
connection.call("World.hello", responder, params);
]]></programlisting>

        <para>
            Als wir die Responder Variable erstellt haben, haben wir auch eine onResult und eine
            onFault Funktion definiert welche die Antwort des Servers behandeln. Wir haben diese
            Funktionen für ein erfolgreiches Ergebnis der Servers hunzugefügt. Ein erfolgreicher
            Eventhandler wird immer dann ausgeführt wenn die Verbindung zum Server richtig
            handgehabt wird.
        </para>

        <programlisting language="as"><![CDATA[
private function onResult(result:Object):void {
    // Display the returned data
    trace(String(result));
}
]]></programlisting>

        <para>
            Die onFault Funktion wird aufgerufen wenn eine ungültige Antwort vom Server
            zurückgekommen ist. Das passiert wenn auf dem Server ein Fehler stattgefunden hat, die
            <acronym>URL</acronym> zum Server ungültig ist, der entfernte Service oder die Methode
            nicht existiert, und bei jedem anderen Verbindungsrelevanten Problem.
        </para>

        <programlisting language="as"><![CDATA[
private function onFault(fault:Object):void {
    trace(String(fault.description));
}
]]></programlisting>

        <para>
            Das ActionScripts für die Erstellung der entfernten Verbindung ist jetzt fertiggestellt.
            Der Aufruf der ZendExample Datei führt jetzt die Verbindung zu
            <classname>Zend_Amf</classname> aus. Rückblickend haben wir die benötigten Variablen
            hinzugefügt um eine Verbindung zum entfernten Server zu öffnen, definiert welche
            Methoden in der Anwendung verwendet werden sollen wenn die Anwendung eine Antwort vom
            Server empfängt, und schlußendlich die Anzeige der zurückgegebenen Daten über
            <methodname>trace()</methodname>.
        </para>
    </sect2>

    <sect2 id="zend.amf.server.auth">
        <title>Authentication</title>

        <para>
            <classname>Zend_Amf_Server</classname> erlaubt es Authentifizierung und Authorisierungs-
            Hooks zu spezifizieren um den Zugriff auf Services zu kontrollieren. Es wird die
            Infrastruktur verwendet die von den
            <link linkend="zend.auth"><classname>Zend_Auth</classname></link> und
            <link linkend="zend.acl"><classname>Zend_Acl</classname></link> Komponenten angeboten
            wird.
        </para>

        <para>
            Um Authentifizierung zu definieren, muß der Benutzer einen Authentifizierungs-Adapter
            anbieten der die abstrakte Klasse <classname>Zend_Amf_Auth_Abstract</classname>
            erweitert. Der Adapter sollte die <methodname>authenticate()</methodname> Methode
            implementieren so wie jeder normale
            <link linkend="zend.auth.introduction.adapters">Authentifizierungs-Adapter</link>.
        </para>

        <para>
            Der Adapter sollte die Eigenschaften <emphasis>_username</emphasis> und
            <emphasis>_password</emphasis> von der Vorgängerklasse
            <classname>Zend_Amf_Auth_Abstract</classname> verwenden um authentifizieren zu können.
            Diese Werte werden vom Server gesetzt, indem die
            <methodname>setCredentials()</methodname> Methode verwendet wird, bevor
            <methodname>authenticate()</methodname> aufgerufen wird wenn die Zugangsdaten in den
            <acronym>AMF</acronym> Anfrage-Headern empfangen wurden.
        </para>

        <para>
            Die Identität die vom Adapter zurückgegeben wird sollte ein Objekt sein das die
            Eigenschaft <property>role</property> enthält damit die Zugriffskontrolle von
            <acronym>ACL</acronym> funktioniert.
        </para>

        <para>
            Wenn das Authentifizierungs Ergebnis nicht erfolgreich war, wird die Anfrage nicht
            weiter bearbeitet und eine Fehlermeldung wird zurückgegeben mit den Gründen für den
            Fehlschlag genommen vom Ergebnis
        </para>

        <para>
            Der Adapter wird zum Server verbunden indem die <methodname>setAuth()</methodname>
            Methode verwendet wird:
        </para>

        <programlisting language="php"><![CDATA[
$server->setAuth(new My_Amf_Auth());
]]></programlisting>

        <para>
            Die Zugriffskontrolle wird durchgeführt indem das <classname>Zend_Acl</classname>
            Objekt verwendet wird das von der <methodname>setAcl()</methodname> Methode gesetzt
            wurde:
        </para>

        <programlisting language="php"><![CDATA[
$acl = new Zend_Acl();
createPermissions($acl); // Zugriffs-Struktur erstellen
$server->setAcl($acl);
]]></programlisting>

        <para>
            Wenn das <acronym>ACL</acronym> Objekt gesetzt ist, und die Klasse die aufgerufen wird
            die <methodname>initAcl()</methodname> Methode definiert wird diese Methode, mit dem
            <acronym>ACL</acronym> Objekt als Argument, aufgerufen. Die Klasse kann dann
            zusätzliche <acronym>ACL</acronym> Regeln erstellen und <constant>TRUE</constant>
            zurückgeben, oder <constant>FALSE</constant> wenn keine Zugriffskontrolle für diese
            Klasse benötigt wird.
        </para>

        <para>
            Nachdem die <acronym>ACL</acronym> gesetzt wurde, wird der Server prüfen ob mit der,
            von der Authentifizierung gesetzten, Rolle Zugriff erlaubt ist, die Ressource im
            Klassennamen ist (oder <constant>NULL</constant> für Funktionsaufrufe) und ob die
            Privilegien der Funktionsname sind. Wenn keine Authentifizierung angegeben wurde, wird
            die <emphasis>anonymous</emphasis> verwendet, wenn diese definiert wurde, andernfalls
            wird der Zugriff verweigert.
        </para>

        <programlisting language="php"><![CDATA[
if($this->_acl->isAllowed($role, $class, $function)) {
    return true;
} else {
    require_once 'Zend/Amf/Server/Exception.php';
    throw new Zend_Amf_Server_Exception("Access not allowed");
}
]]></programlisting>
    </sect2>
</sect1>
