<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Christoph Bünte &nbsp;&raquo; Software Entwicklung Berlin</title>
	<atom:link href="http://www.christophbuente.de/tag/tutorial/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.christophbuente.de</link>
	<description>Software Entwicklung</description>
	<lastBuildDate>Tue, 07 Dec 2010 11:30:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.5</generator>
		<item>
		<title>Opensocial Gadgets &#8211; Apps für StudiVZ selbst entwickeln</title>
		<link>http://www.christophbuente.de/2009-10-29-opensocial-gadgets-apps-fur-studivz-selbst-entwickeln/</link>
		<comments>http://www.christophbuente.de/2009-10-29-opensocial-gadgets-apps-fur-studivz-selbst-entwickeln/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 19:39:51 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Web Entwicklung]]></category>
		<category><![CDATA[backend]]></category>
		<category><![CDATA[beispiel]]></category>
		<category><![CDATA[example]]></category>
		<category><![CDATA[gadgets]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[meinvz]]></category>
		<category><![CDATA[opensocial]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[schuelervz]]></category>
		<category><![CDATA[studivz]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[widgets]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/?p=399</guid>
		<description><![CDATA[Wie StudiVZ bereits angekündigt hat, werden die ersten opensocial Anwendungen für ihre Plattform bald live gehen. Entwickler können sich schon jetzt registrieren und ihre so genannten Gadgets in einer Sandbox ausprobieren. Ich habe das Vergnügen für meinen aktuellen Kunden DaWanda ein Gadget für StudiVZ zu entwickeln. Ein Gadget besteht aus einer XML Datei, die definiert, [...]]]></description>
			<content:encoded><![CDATA[<p>Wie <a href="http://developer.studivz.net/2009/09/24/opensocial-is-now-available-in-our-vz-sandbox/">StudiVZ</a> bereits angekündigt hat, werden die ersten <a href="http://code.google.com/intl/de-DE/apis/opensocial/">opensocial</a> Anwendungen für ihre Plattform bald live gehen. Entwickler können sich schon jetzt registrieren und ihre so genannten Gadgets in einer Sandbox ausprobieren.</p>
<p>Ich habe das Vergnügen für meinen aktuellen Kunden <a href="http://www.dawanda.com">DaWanda</a> ein Gadget für StudiVZ zu entwickeln. Ein Gadget besteht aus einer XML Datei, die definiert, um welche Anwendung es sich handelt, wer der Author ist usw. Dazu gehören wahlweise mehrere CSS und Javascript Dateien. Nachdem man alles in eine Zip Datei, die den gleichen namen wie die XML Datei trägt, gepackt hat, kann man die Anwendung in die Sandbox hochladen und ausprobieren. Eine Beispiel Datei könnte so aussehen:</p>
<pre escaped="true" lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Module&gt;
  &lt;ModulePrefs
    title="Example StudiVZ Gadget"
    title_url="http://www.christophbuente.de"
    author="Christoph Bünte"
    author_email="info@christophbuente.de"
    description="Example description"
    screenshot="http://www.christophbuente.de/images/screenshot.jpg"
    thumbnail="http://www.christophbuente.de/images/thumbnail.jpg"&gt;
    &lt;Require feature="opensocial-0.8" /&gt;
    &lt;Require feature="views" /&gt;
  &lt;/ModulePrefs&gt;
  &lt;Content type="html" &gt;
    &lt;![CDATA[
      &lt;script&gt;
        function init() {
          // Put initialization code here
        }
        gadgets.util.registerOnLoadHandler(init);
      &lt;/script&gt;
    &lt;div id='container'&gt;&lt;/div&gt;
    ]]&gt;
  &lt;/Content&gt;
&lt;/Module&gt;</pre>
<p><span id="more-399"></span><br />
Jede Interaktion des Benutzers mit der Anwendung wird mit Hilfe weiterer Javascript Funktionen behandelt. Dazu stehen eine Reihe eingebauter Funktionen aus dem Opensocial Container bereit. Darüber hinaus haben die Entwickler von StudiVZ eine <a href="http://developer.studivz.net/wiki/index.php/Gadgets_API">API Beschreibung</a> der zusätzlichen Funktionen bereit gestellt. Was aber, wenn man nun nicht mit Javascript entwickeln möchte bzw. kann? Es besteht die Möglichkeit Flash Content einzubinden. Man kann aber auch ein beliebiges Backend einbinden. Dieses Backend muss nur 2 Bedingungen erfüllen:</p>
<ul>
<li>Es muss auf <acronym title="Hypertext Transfer Protocol">HTTP</acronym> Requests reagieren können und beliebiges <acronym title="Hypertext Markup Language">HTML</acronym>,<acronym title="Cascading Style Sheet">CSS</acronym> und JavaScript zurück liefern</li>
<li>Es muss im Namen des Applikationsbenutzers einen OAuth signierten Request an die StudiVZ <acronym title="Representational State Transfer">REST</acronym> <acronym title="Application Programming Interface">API</acronym> schicken können.</li>
</ul>
<p><a href="http://www.christophbuente.de/wp-content/uploads/Bild-7.png"><img class="size-full wp-image-419 alignleft" title="Request Opensocial Backend" src="http://www.christophbuente.de/wp-content/uploads/Bild-7.png" alt="Schema: Request Opensocial Backend" width="348" height="376" /></a><br />
Wie im Schema zu sehen, sendet der User einen Request, um die Applikation zu benutzen. Der Container liest darauf hin den Inhalt der XML Datei aus. Dort ist neben einem DIV Container lediglich ein externes Javascript referenziert. In dem Javascript sind einfache Methoden zum Navigieren und Interagieren definiert. Das rendern des HTML übernimmt ein Ruby Backend. Das braucht zum Render unter Umständen noch zusätzliche Informationen wie zum Beispiel Name und Foto des Benuter usw. Diese Informationen holt es sich mit einem OAuth signierten Request von der abgebildeten REST API. Das vom Ruby Backend erzeugte HTML rendert der Opensocial Container in einem IFrame im Browser des Benutzers. Für eine bessere Übersicht definieren wir im XML einzelne Views, die jeweils einen eigenen Endpunkt im Backend haben. Eine einfache gadget.xml mit 2 definierten Views für Profil und Vollansicht mit Backend Anbindung:</p>
<pre escaped="true" lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;Module&gt;
  &lt;ModulePrefs
    title="Spitzenmässiges StudiVZ Gadget mit Backendanbindung"
    title_url="http://www.christophbuente.de"
    author="Christoph Bünte"
    author_email="info@christophbuente.de"&gt;
    &lt;Require feature="opensocial-0.8" /&gt;
    &lt;Require feature="views" /&gt;
  &lt;/ModulePrefs&gt;
  &lt;Content type="html" view="profile" &gt;
    &lt;![CDATA[
      &lt;script type="text/javascript" src="http://www.yourbackend.com/profile.js" &gt;&lt;/script&gt;
      &lt;div id='profile'&gt;&lt;/div&gt;
    ]]&gt;
  &lt;/Content&gt;
  &lt;Content type="html" view="canvas" &gt;
    &lt;![CDATA[
      &lt;script type="text/javascript" src="http://www.yourbackend.com/canvas.js" &gt;&lt;/script&gt;
      &lt;div id='canvas'&gt;&lt;/div&gt;
    ]]&gt;
  &lt;/Content&gt;
&lt;/Module&gt;</pre>
<p>Das referenzierte Javascript ist ebenfalls sehr schlank. Darin wird lediglich eine Backend URL aufgerufen und deren Response Body in das profile bzw. canvas div geschrieben.</p>
<pre>function init{
  var url = 'http://www.yourbackend.com/profile/'
  var params = {};
  params[gadgets.io.RequestParameters.AUTHORIZATION]=gadgets.io.AuthorizationType.SIGNED;
  gadgets.io.makeRequest(url, requestCallback, params);

}

function requestCallback(obj) {
	document.getElementById('profile').innerHTML = obj.data;
}</pre>
<p>Damit die REST API benutzt werden kann, muss man sich an ihr Authentifizieren. Da das Backend aber dumm ist, hat es keine Userdaten, um sich dort anzumelden. Glücklicherweise ist der Request aus dem Javascript mit dem verschlüsselten Authentifierungsdaten des angemeldeten Anwendungsbenutzers signiert. Mit deren Hilfe können wir einen neuen, signierten Request erzeugen, den die API akzeptieren wird. Doch zuerst muss die Glültigkeit der Signatur überprüft werden:</p>
<p><code>sudo gem install oauth --source http://gemcutter.org</code></p>
<pre lang="ruby">
require 'oauth'
require 'oauth/consumer'
require 'oauth/request_proxy/action_controller_request'
require 'oauth/signature/rsa/sha1'
require 'oauth/signature/hmac/sha1'

class ApplicationController < ActionController::Base

  before_filter <img src='http://www.christophbuente.de/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> auth_required

  def oauth_required
    cert_file = File.join(RAILS_ROOT, 'public', 'public.cer')
    cert_str = File.read(cert_file)
    consumer = OAuth::Consumer.new(ConsumerToken, cert_str)

    begin
      pass = OAuth::Signature.build(request, :consumer => consumer).verify
      logger.info "Signature verification returned: #{pass}"
    rescue OAuth::Signature::UnknownSignatureMethod => e
      logger.error "ERROR "+ e.message
    end

    render :text => "OAuth access denied", :status => :unauthorized  unless pass
  end
</pre>
<p>Die URL für das öffentliche Zertifikat wird mit jedem Request mit geschickt. Einmal runterladen sollte reichen. Ich denke, man muss es nicht bei jedem Request erneut vom StudiVZ Server laden. Den Consumer Token findet ihr in der OAuth Section eurer Gadget Sandbox (http://www.meinvz.net/GadgetDeveloper/GadgetOAuth/xxx). xxx ist deine Gadget ID.</p>
<p>Sollte der before_filter nicht abbrechen war die Signatur korrekt und der Request kann bearbeitet werden. Aus einem mir nicht bekannten Grund ist der Request des Containers an das Backend mit der RSA-SHA1 Methode signiert. Dafür wird das Zertifikat benötigt. Für den Request an die API muss die HMAC-SHA1 Methode verwendet werden. Dafür wird ein neuer Consumer benötigt:</p>
<pre lang="ruby">def get_owner
  consumer = OAuth::Consumer.new(ConsumerToken, ConsumerSecret,
      :signature_method => 'HMAC-SHA1',
      :site => "http://sandbox.gadgets.apivz.net",
      :scheme => :query_string,
      :http_method => :get)
  requestor_param = {:xoauth_requestor_id => params[:opensocial_owner_id]}.to_param
  access_token = OAuth::AccessToken.new(consumer)
  response = access_token.get("/social/rest/people/#{params[:opensocial_owner_id]}/@self?#{requestor_param}")
  owner_attributes = JSON.parse(response.body)['entry']
end</pre>
<p>Feedback, Fragen und Kritik sind immer gerne willkommen.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-11-10-paypal-subscriptions-abonnements-in-java-integrieren/" rel="bookmark" class="crp_title">Paypal subscriptions &#8211; Abonnements in Java integrieren</a></li><li><a href="http://www.christophbuente.de/2010-07-20-rails-hosting-bei-rocket-rentals-auch-mit-staging-umgebung/" rel="bookmark" class="crp_title">Rails Hosting bei Rocket Rentals &#8211; auch mit Staging Umgebung</a></li><li><a href="http://www.christophbuente.de/2007-10-23-bots-aussperren-mit-captcha/" rel="bookmark" class="crp_title">captcha tutorial &#8211; Bots aussperren</a></li><li><a href="http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/" rel="bookmark" class="crp_title">VoiceGlue Installation &#8211; Interactive Voice Response leicht gemacht</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2009-10-29-opensocial-gadgets-apps-fur-studivz-selbst-entwickeln/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Stripes Framework &#8211; Tests für ActionBeans im Wizard Modus</title>
		<link>http://www.christophbuente.de/2008-01-24-stripes-framework-tests-fur-actionbeans-im-wizard-modus/</link>
		<comments>http://www.christophbuente.de/2008-01-24-stripes-framework-tests-fur-actionbeans-im-wizard-modus/#comments</comments>
		<pubDate>Thu, 24 Jan 2008 22:44:17 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Java JEE]]></category>
		<category><![CDATA[Web Entwicklung]]></category>
		<category><![CDATA[actionBean]]></category>
		<category><![CDATA[anleitung]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JEE]]></category>
		<category><![CDATA[junit]]></category>
		<category><![CDATA[mock]]></category>
		<category><![CDATA[MockRoundTrip]]></category>
		<category><![CDATA[MockServletContext]]></category>
		<category><![CDATA[stripes]]></category>
		<category><![CDATA[stripes framework]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[tests]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[unit tests]]></category>
		<category><![CDATA[wizard mode]]></category>
		<category><![CDATA[wizard modus]]></category>
		<category><![CDATA[__fp]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2008-01-24-stripes-framework-tests-fur-actionbeans-im-wizard-modus/</guid>
		<description><![CDATA[Bei meinem aktuellen Kunden wurde das Stripes Framework verwendet, um eine Java basierte Webanwendung zu erstellen. Für mehrseitige Formulare bietet Stripes ActionBeans mit einen Wizard Modus an. Dieser zeichnet sich dadurch aus, dass alle bereits ausgefüllten Formularfelder als versteckte Felder in alle folgenden Formulare eingefügt werden. Dieser Modus erspart bei mehrseitigen Formularen viel Arbeit, aber [...]]]></description>
			<content:encoded><![CDATA[<p>Bei meinem aktuellen Kunden wurde das <a href="http://www.stripesframework.org/">Stripes Framework</a> verwendet, um eine Java basierte Webanwendung zu erstellen. Für mehrseitige Formulare bietet Stripes ActionBeans mit einen <a href="http://www.stripesframework.org/display/stripes/Wizard+Forms">Wizard Modus</a> an. Dieser zeichnet sich dadurch aus, dass alle bereits ausgefüllten Formularfelder als versteckte Felder in alle folgenden Formulare eingefügt werden. Dieser Modus erspart bei mehrseitigen Formularen viel Arbeit, aber wie lässt sich dieser Wizard Modus am besten Testen? In diesem Artikel wird beschrieben, wie man mit Hilfe dem Stripes eigenen MockServletContexts sinnvolle Unit tests schreiben kann.</p>
<p><span id="more-31"></span></p>
<p>Die Dokumentation für <a href="http://www.stripesframework.org/display/stripes/Unit+Testing#UnitTesting-Approach2%3AMockContainerUsage">Stripes Unit tests</a> beschreibt sehr ausführlich, wie man mit Hilfe des MockServletContext eine Testinfrastruktur aufbaut, die es ermöglicht die ActionBeans ausserhalb des <acronym title="Java Enterprise Edition" lang="en">JEE</acronym>-Containers zu testen. Dies funktioniert für klassische ActionBeans ganz wunderbar. Doch beim schreiben von Tests für ActionBeans im Wizard Mode fiel auf, dass die Simulation eines Submits nicht funktionierte. Im Wizard Modus erzeugt das <a href="http://stripes.sourceforge.net/docs/current/javadoc/net/sourceforge/stripes/tag/FormTag.html">Stripes FormTag</a> ein zusätzliches verstecktes Formularfeld mit dem Namen &#8220;__fp&#8221;, welches alle Feldnamen des aktuellen Formulars in verschlüsselter Form enthält. Ohne dieses Feld verweigert der Stripes Dispatcher die Arbeit! Nimmt man nun einen beliebigen Wert und legt ihn in diesem Feld ab, so erzeugt das ebenfalls einen Fehler:<small>(Der Rechtschreibfehler ist tatsächlich aus dem Framework.)</small></p>
<p><code>Stripes attmpted and failed to decrypt the non-null value in the 'fields present' field.</code></p>
<p>Auch ist es nicht sinnvoll, einen beliebigen Text mit Hilfe des <code>CryptoUtil</code> zu verschlüsseln. Der Submit kann dann zwar erfolgreich simuliert werden, jedoch werden sämtliche Validierungsregel ignoriert. Mit folgenden Zeilen Code, kann ein korrekter Wert für das &#8220;__fp&#8221; Feld erzeugt werden:</p>
<pre lang="java">// Alle Feldnamen des aktuellen Formulars in eine Liste aufnehmen
   List fields = new ArrayList();
   fields.add("username");
   fields.add("password");
// Alle Feldnamen mit Trennzeichen zusammenfassen
   String hiddenFieldValue = HtmlUtil.combineValues(fields);
// servlet engine configurieren
   MockServletContext ctx = TestFixture.getServletContext();
   MockRoundtrip trip = new MockRoundtrip(this.ctx, YourCustomActionBean.class);
   HttpServletRequest request = (HttpServletRequest) trip.getRequest();
   hiddenFieldValue = CryptoUtil.encrypt(hiddenFieldValue, request);
   trip.setParameter(StripesConstants.URL_KEY_FIELDS_PRESENT, hiddenFieldValue);</pre>
<p>Für das Testen der Feldvalidierung ist es wichtig, dass die Feldnamen mit dem Wert des <code>&lt;input name="" /&gt;</code> Name Attributes in dem jeweiligen Formular übereinstimmen. Denn es werden tatsächlich nur die Felder validiert, die aus dem decodiertem Inhalt des &#8220;__fp&#8221; Feldes ausgelesen werden können.</p>
<p>Angenommen der oben abgebildete Code wird in der <code>setup()</code> Methode eines Unit Tests ausgeführt und speichert das <code>MockRoundtrip</code> Object in einem privaten Member, könnte ein Beispieltest könnte dann so aussehen:</p>
<pre lang="java">@Test
public void testLogin() throws Exception {
	trip.setParameter("username", "christophbuente");
	trip.setParameter("password", "secret");
	trip.execute("login");
	YourCustomActionBean bean = trip.getActionBean(YourCustomActionBean.class);
	Assert.assertTrue("Destination", "/account", trip.getDestination());
}</pre>
<p>Ich hoffe, dass diese Informationen ausreichen, um sinnvolle Unit Tests für ActionBeans im Wizard Modus zu schreiben. Bei Fragen helfe ich gerne weiter. Und wie immer sind Kommentare sehr willkommen.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-10-23-bots-aussperren-mit-captcha/" rel="bookmark" class="crp_title">captcha tutorial &#8211; Bots aussperren</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2009-05-16-remarkable-rails-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">Remarkable &#8211; Rails Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li><li><a href="http://www.christophbuente.de/2007-08-05-objekte-und-beziehungen/" rel="bookmark" class="crp_title">Objekte und Beziehungen</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2008-01-24-stripes-framework-tests-fur-actionbeans-im-wizard-modus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VoiceGlue Konfiguration &#8211; Server für Sprachanwendungen einrichten</title>
		<link>http://www.christophbuente.de/2007-12-21-voiceglue-konfiguration-server-fur-sprachanwendungen-einrichten/</link>
		<comments>http://www.christophbuente.de/2007-12-21-voiceglue-konfiguration-server-fur-sprachanwendungen-einrichten/#comments</comments>
		<pubDate>Fri, 21 Dec 2007 19:25:58 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Unix shell]]></category>
		<category><![CDATA[Voice]]></category>
		<category><![CDATA[agi]]></category>
		<category><![CDATA[anleitung]]></category>
		<category><![CDATA[asr]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[dtmf]]></category>
		<category><![CDATA[hilfe]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[sip]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[speech]]></category>
		<category><![CDATA[tts]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[voiceglue]]></category>
		<category><![CDATA[voicexml]]></category>
		<category><![CDATA[vox]]></category>
		<category><![CDATA[vxglue]]></category>
		<category><![CDATA[vxml]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007-12-21-voiceglue-konfiguration-server-fur-sprachanwendungen-einrichten/</guid>
		<description><![CDATA[[lang_de]In meinem letzten Artikel habe ich die Installation der IVR Software VoiceGlue unter Fedora Core 8 in einer Parallels Desktop VM beschrieben. Nun möchte ich eine Anleitung für die Einrichtung von VoiceGlue nachliefern. Damit wird es jedem möglich, eine VoiceXML basierte Sprachanwendung aufzusetzen. [ad#vert-banner] Nachdem alle Schritte aus der Installationsanleitung befolgt wurden, sind folgende Komponenten [...]]]></description>
			<content:encoded><![CDATA[<p>[lang_de]In meinem <a title="VoiceGlue Installation - Interactive Voice Response leicht gemacht" href="http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/">letzten Artikel</a> habe ich die Installation der <acronym title="Interactive Voice Response" lang="en">IVR</acronym> Software <a title="VoiceGlue" href="http://www.voiceglue.org">VoiceGlue</a> unter <a href="http://fedoraproject.org/">Fedora Core 8</a> in einer <a href="http://www.parallels.com/en/products/desktop/">Parallels Desktop VM</a> beschrieben. Nun möchte ich eine Anleitung für die Einrichtung von VoiceGlue nachliefern. Damit wird es jedem möglich, eine VoiceXML basierte Sprachanwendung aufzusetzen.<br />
<span id="more-27"></span></p>
<p>[ad#vert-banner]</p>
<p>Nachdem alle Schritte aus der Installationsanleitung befolgt wurden, sind folgende Komponenten auf dem System installiert:</p>
<ul>
<li><a href="http://www.perl.org/">perl</a> (Skriptsprache)</li>
<li><a href="http://www.asterisk.org/">asterisk</a> (Telefonieserver)</li>
<li><a href="http://www.openvxi.org/">openVXI</a> (Open Source VoiceXML Interpreter)</li>
<li><a href="http://www.speech.cs.cmu.edu/flite/index.html">flite</a> (engl. <acronym title="Text To Speech" lang="en">TTS</acronym> Engine)</li>
<li><a href="http://www.voiceglue.org">voiceglue</a> (IVR Software)</li>
</ul>
<p>Um tatsächlich Anrufe über das Telefon- oder auch VoIP Netz entgegen nehmen zu können, muss der asterisk Server konfiguriert werden. Eine vollständige Beschreibung der asterisk Konfiguration würde allerdings den Rahmen dieses Tutorials sprengen. Aus diesem Grund wird lediglich die Konfiguration erklärt, mit er es möglich ist, mit Hilfe eines sogenannten <a title="Softphone" href="http://de.wikipedia.org/wiki/Softphone">Softphones</a> an der Sprachanwendung anzurufen. Für vielschichtige asterisk Konfigurationen findet man in <a title="Asterisk" href="http://www.amazon.de/gp/redirect.html%3FASIN=0596009623%26tag=chribuensofte-21%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0596009623%253FSubscriptionId=1YNZ339ZCHHAKYFSY702">Asterisk: The Future if Telephony</a> ausreichend Hilfe.</p>
<p>Als erstes benötigen wir für die Annahme von Anrufen via <acronym title="Session Initiation Protocol" lang="en">SIP</acronym> einen eigenen Kontext in der Datei: <code>/etc/asterisk/manager.conf</code>. Die folgenden Zeilen sollte man am besten am Ende der Datei einfügen:</p>
<pre lang="conf">[phoneglue]
secret=phoneglue
read = system,call,log,verbose,command,agent,user
write = system,call,log,verbose,command,agent,user</pre>
<p>Ausserdem muss der Manager noch aktiviert werden. Deswegen sollte man sicherstellen, dass in der gleichen Datei die Variable <code>enabled=yes</code> gesetzt ist.</p>
<p>Danach wird asterisk so konfiguriert, dass alle angenommenen Anrufe per <acronym title="Asterisk Gateway Interface" lang="en">AGI</acronym> an den Voicebrowser weitergeleitet werden. Durch die Verwendung von AGI ist es möglich, den Voicebrowser auch auf einem anderen Server zu betreiben und die Verbindung via Netzwerk herzustellen. Dies nimmt bei vielen Anrufen die Last vom System. Die Konfiguration wird in der Datei <code>/etc/asterisk/extensions.conf</code> vorgenommen. Auch hier ist es wieder sinnvoll einen neuem Kontext am Ende der Datei einzufügen:</p>
<pre lang="conf">[phoneglue]
exten =&gt; 1,1,Agi(agi://localhost)
exten =&gt; 1,2,Hangup</pre>
<p>Die Einträge für die Extensions beginnen mit einer <em>1</em>. Dies ist die Durchwahl für die Sprachanwendung. Der Aufruf &#8220;Agi(agi://localhost) verbindet nun den Voicebrowser mit dem Anrufer.</p>
<p>Möchte man nun alle eingehenden Anrufe, welche mit SIP initiiert werden, an die Sprachanwendung leiten, ist noch eine Änderung in der Datei <code>/etc/asterisk/sip.conf</code> nötig. Der Standard Kontext muss von <code>default</code> auf <code>phoneglue</code> gesetzt werden.</p>
<pre lang="conf">[general]
context=phoneglue</pre>
<p>Damit ist die Konfiguration von asterisk schon abgeschlossen. Nun kann es mit der Konfiguration der Sprachanwendung weitergehen.</p>
<p>VoiceXML basierte Sprachanwendungen benötigen einen <acronym title="Hyper Text Transport Protocol" lang="en">HTTP</acronym> Server, welcher die statischen oder dynamisch erzeugten *.vxml Dateien ausliefert. Auch hier haben die Entwickler von VoiceGlue mitgedacht, indem das System so konfigurierbar ist, dass der VoiceXML Server auf einer separaten Maschine laufen kann. Zu Demonstrationszwecken genügt es hier allerdings, dass alle Dienste auf einer Maschine laufen. Die Konfiguration wird in der Datei <code>/etc/voiceglue.conf</code> vorgenommen. Hier genügt ein Eintrag, der auf die Einstiegsseite der Sprachanwendung zeigt.</p>
<pre lang="conf"> * http://localhost/index.vxml</pre>
<p>Diese Datei muss vom lokalen <a href="http://apache.org">Apache</a> ausgeliefert werden. Falls noch nicht geschehen, sollte der Apache jetzt gestartet werden:</p>
<pre lang="shell">sudo service httpd start</pre>
<p>Standardmässig liegen die <acronym title="Hyper Text Markup Language" lang="en">HTML</acronym> für den Apache unter Fedora im Verzeichnis <code>/var/www/html</code>. Genau an dieser Stelle legen wir eine klassische <span lang="en">Hello World</span> Anwendung in Form einer VoiceXML Datei mit folgendem Inhalt ab:</p>
<pre lang="xml">
<form>

      Hello World. This is my first voiceglue application.</form>
</pre>
<p>Damit ist die Konfiguration abgeschlossen. Alle Dienste sind vollständig konfiguriert und sollten jetzt gestartet werden.</p>
<pre lang="bash">sudo service asterisk start
sudo service phoneglue start
sudo service voiceglue start</pre>
<p>Als letztes wollen wir überprüfen, ob die Komfiguration erfolgreich war. Dazu benötigen wir ein Softphone. Eine freie Version findet man bei <a href="http://sjlabs.com">SJLabs</a>. Das Telefon ist für Windows, Linux und OS X verfügbar. Nach dem herunterladen muss im Menupunkt <em>Phone-&gt;Services</em> das SIP Protolkoll gewählt werden. Anschließend wählen wir unseren lokalen asterisk Dienst mit der Durchwahl <code>1@localhost</code> an.</p>
<p>Basierend auf der gezeigten Konfiguration lassen sich beliebige Sprachanwendungen erstellen. Wie jedoch schon im Beitrag <a title="VoiceGlue Installation - Interactive Voice Response leicht gemacht" href="http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/">VoiceGlue Installation &#8211; Interactive Voice Response leicht gemacht</a> beschrieben, fehlt die Intergration einer <acronym title="Automatic Speech Recognition" lang="en">ASR</acronym> Engine. Somit beschränken sich Anrufereingaben auf <acronym title="Dual Tone Multiple Frequencies" lang="en">DTMF</acronym>.[/lang_de]</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/" rel="bookmark" class="crp_title">VoiceGlue Installation &#8211; Interactive Voice Response leicht gemacht</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/" rel="bookmark" class="crp_title">Ruby on Rails auf Mac OS X &#8211; 5 Minuten Kurzanleitung</a></li><li><a href="http://www.christophbuente.de/2009-09-09-500-internal-server-error-apache-config-vs-wp-super-cache/" rel="bookmark" class="crp_title">500 Internal Server Error &#8211; Apache config vs. WP-Super-Cache</a></li><li><a href="http://www.christophbuente.de/2007-10-05-frei-nehmen-um-zu-lernen/" rel="bookmark" class="crp_title">Rails tutorial &#8211;  Eine Woche lang Agile Webentwicklung</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-12-21-voiceglue-konfiguration-server-fur-sprachanwendungen-einrichten/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VoiceGlue Installation &#8211; Interactive Voice Response leicht gemacht</title>
		<link>http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/</link>
		<comments>http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/#comments</comments>
		<pubDate>Thu, 06 Dec 2007 20:43:32 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Voice]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[fedora core]]></category>
		<category><![CDATA[help]]></category>
		<category><![CDATA[hilfe]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[ivr]]></category>
		<category><![CDATA[mac os x]]></category>
		<category><![CDATA[parallels desktop]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[speech]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[voiceglue]]></category>
		<category><![CDATA[voicexml]]></category>
		<category><![CDATA[vox]]></category>
		<category><![CDATA[vxglue]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/</guid>
		<description><![CDATA[Neulich bin ich durch Okko auf VoiceGlue aufmerksam gemacht worden. Dabei handelt es sich um eine Sammlung von Open Source Programmen, die zusammen die Funktionalität einer IVR zur Verfügung stellen. Als ehemalige Mitarbeiter der Mundwerk AG sind wir IVR Systeme der Enterprise Klasse gewohnt. Sicherlich wird VoiceGlue in der aktuellen Version 0.6 diesen Ansprüchen noch [...]]]></description>
			<content:encoded><![CDATA[<p>Neulich bin ich durch <a href="http://okkobuss.blogspot.com/2007/12/news-redux-building-voiceglue.html">Okko</a> auf <span lang="en"><a href="http://www.voiceglue.org/">VoiceGlue</a></span> aufmerksam gemacht worden. Dabei handelt es sich um eine Sammlung von <span lang="en"><a href="http://de.wikipedia.org/wiki/Open_Source">Open Source Programmen</a></span>, die zusammen die Funktionalität einer <acronym title="Interactive Voice Response" lang="en"><a href="http://de.wikipedia.org/wiki/IVR">IVR</a></acronym> zur Verfügung stellen. Als ehemalige Mitarbeiter der <a href="http://www.mundwerk.de/">Mundwerk AG</a> sind wir IVR Systeme der <span lang="en">Enterprise</span> Klasse gewohnt. Sicherlich wird <span lang="en">VoiceGlue</span> in der aktuellen <a href="http://www.voiceglue.org/download/">Version 0.6</a> diesen Ansprüchen noch nicht gerecht, zumal die Anbindung an <a href="http://de.wikipedia.org/wiki/Spracherkennung"><acronym title="Automatic Speech Recognition" lang="en">ASR</acronym> Systeme</a> bisher nur auf der Agenda steht. Trotzdem wollten wir wissen: Wie einfach ist es, eine IVR mit <span lang="en">VoiceGlue</span> zu installieren.</p>
<p><span id="more-25"></span></p>
<p>[ad#vert-banner]</p>
<p>Ein erster Blick auf die <a href="http://www.voiceglue.org/documentation/install/" title="VoiceGlue">Installationsanleitung</a> offenbart keine sehr ausführlichen Informationen. Lediglich ein paar Pakete installieren, und fertig. Nun, wir wollen sehen. Die Installation wurde mit Hilfe von <a href="http://www.parallels.com/products/desktop/" title="Virtuelle Maschine für den Mac">Parallels Desktop 3.0</a> unter <a href="http://www.apple.com/de/macosx/" title="Apple Betriebsystem">Mac OS X</a> vorgenommen. Als Gastbetriebsystem haben wir, wie in der Anleitung empfohlen <a href="http://fedoraproject.org/" title="Fedora Core 8 Linux">Fedora Core 8</a> verwendet.</p>
<p>Nach der Installation von Fedora Core 8 in der <acronym title="Virtual Machine" lang="en">VM</acronym> mit den Standard Optionen fehlen vor allem noch ein Compiler, ein paar Developer Pakete und jede Menge Perl Module. Der bereits installierte Paketmanager <a href="http://linux.duke.edu/projects/yum/"><acronym title="Yellow dog Updater, Modified" lang="en">YUM</acronym></a> wird also gleich bemüht, um alles Fehlende an den Start zu bringen.</p>
<pre lang="shell">
sudo yum install perl gcc-c++ libstdc++-devel xerces-c-devel js-devel flite openssl-devel libxml2-devel expat-devel</pre>
<p>Soweit noch nicht geschehen, sollte <a href="http://www.cpan.org/"><acronym title="Comprehensive Perl Archive Network" lang="en">cpan</acronym></a> installiert werden. Hiermit lassen sich benötigte Perl Pakete leicht installieren. Eine Anleitung findet man auf der <a href="http://search.cpan.org/~andk/CPAN-1.9205/lib/CPAN.pm">cpan homepage</a>. Es ist jedoch ratsam folgende Pakete gleich mit zu installieren: <code>ncftp, wget</code></p>
<pre lang="shell">
sudo yum install ncftp wget cpan</pre>
<p>Nun fehlen noch folgende Perl Module: <code>XML::LibXML, BSD::Resource, Module::Build</code>. Während der Installation von cpan werden mehrere Fragen gestellt, die eigentlich alle, bis auf die Frage nach dem Ort und den Servern, mit &#8220;ENTER&#8221; bestätigt werden können. Aber genau lesen hat noch nie geschadet. Die Fragen, ob alle benötigten Pakete ebenfalls installiert werden sollen, kann man auch getrost mit &#8220;ja&#8221; beantworten. Aber man sollte gewarnt sein: Je nach dem, wie viel oder wenig Perl Module schon installiert sind, dauert es unter Umständen bis zu 10 Minuten. Wie sich allerdings herausstellt, gibt es für <code>Module::Build</code> zwei optionale Pakete, die zwar wichtig sind, aber nicht automatisch installiert werden. Aus diesem Grund wird <code>ExtUtils::ParseXS</code> und damit auch <code>ExtUtils::CBuilder</code> zusätzlich installiert.</p>
<pre lang="shell">
cpan install Bundle::CPAN
cpan install XML::LibXML
cpan install BSD::Resource
cpan install ExtUtils::ParseXS
cpan install Module::Build</pre>
<p>Wenn alle Module erfolgreich installiert wurden, fehlt nur noch der <a href="http://www.asterisk.org/">asterisk</a> Dienst. Dieser ist jedoch nicht über das Fedora Repository erhältlich. Deswegen muss in die YUM Konfiguration ein weiteres Repository aufgenommen werden. Dazu wird die Datei <code>/etc/yum.repos.d/atrpms.repo</code> mit folgendem Inhalt angelegt:</p>
<pre lang="shell">
[atrpms]
name=Fedora Core $releasever - $basearch - ATrpms
baseurl=http://dl.atrpms.net/f$releasever-$basearch/atrpms/stable
#enabled=1
gpgkey=http://ATrpms.net/RPM-GPG-KEY.atrpms
gpgcheck=1</pre>
<p>Anschließend muss noch der <a href="http://www.gnupg.org/" title="The GNU Privacy Guard"><acronym title="The GNU Privacy Guard" lang="en">GPG</acronym></a> Schlüssel für das neue Repository importiert werden:</p>
<pre lang="shell">
sudo rpm --import http://ATrpms.net/RPM-GPG-KEY.atrpms</pre>
<p>Jetzt kann der asterisk Dienst installiert werden. YUM wird vorschlagen, alle fehlenden Pakete ebenfalls zu installieren:</p>
<pre lang="shell">
sudo yum install asterisk</pre>
<p>Nachdem nun endlich alle Vorbereitungen für die Installation abgeschlossen sind, sollte das Voiceglue Paket <a href="http://www.voiceglue.org/download">heruntergeladen</a> werden. Nachdem Download einfach entpacken, und los geht der Spass.</p>
<pre lang="shell">
tar xvfz voiceglue_0.6.tar.gz
cd voiceglue_0.6
perl doc/install-voiceglue</pre>
<p>Sollte das Installationsskript wider Erwarten nicht korrekt durchlaufen, müssen die einzelnen Komponenten per Hand in der richtigen Reihenfolge installiert werden:</p>
<ul>
<li>Cam-Scom</li>
<li>dynlog</li>
<li>libvglue</li>
<li>openvxi</li>
<li>phoneglue</li>
<li>Satc</li>
<li>SRGSDTMF</li>
<li>voiceglue</li>
<li>Vxglue</li>
</ul>
<p>In jedem Unterverzeichnis sollte entweder eine Build.pl Datei oder ein build Skript liegen, welches ausgeführt werden muss. Bei Problemen kann ich gerne versuchen zu helfen.</p>
<p>Fazit: Mit der Original Anleitung war die Installation sehr mühsam, weil nicht alle Pakete aufgeführt sind, die benötigt werden. Nach mehrmaligem Zurücksetzen der Virtuellen Maschine konnte ich alle Paketabhängigkeiten herausfinden und auflösen. Die hier beschriebene Lösung funktionierte für mich ohne Probleme. Wie immer ist Feedback sehr willkommen. Für Hinweise und bei Problemen einfach einen Kommentar hinterlassen.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-12-21-voiceglue-konfiguration-server-fur-sprachanwendungen-einrichten/" rel="bookmark" class="crp_title">VoiceGlue Konfiguration &#8211; Server für Sprachanwendungen einrichten</a></li><li><a href="http://www.christophbuente.de/2007-11-25-ruby-on-rails-auf-mac-os-x-5-minuten-kurzanleitung/" rel="bookmark" class="crp_title">Ruby on Rails auf Mac OS X &#8211; 5 Minuten Kurzanleitung</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li><li><a href="http://www.christophbuente.de/2008-08-04-bilder-versehentlich-geloscht-urlaubserinnerungen-ganz-leicht-zuruckholen/" rel="bookmark" class="crp_title">Bilder versehentlich gelöscht &#8211; Urlaubserinnerungen ganz leicht zurückholen</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Paypal subscriptions &#8211; Abonnements in Java integrieren</title>
		<link>http://www.christophbuente.de/2007-11-10-paypal-subscriptions-abonnements-in-java-integrieren/</link>
		<comments>http://www.christophbuente.de/2007-11-10-paypal-subscriptions-abonnements-in-java-integrieren/#comments</comments>
		<pubDate>Sat, 10 Nov 2007 14:48:10 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Web Entwicklung]]></category>
		<category><![CDATA[abonnement]]></category>
		<category><![CDATA[anleitung]]></category>
		<category><![CDATA[buttonfactory]]></category>
		<category><![CDATA[exclude]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[J2EE]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JEE]]></category>
		<category><![CDATA[paypal]]></category>
		<category><![CDATA[paypal subschription]]></category>
		<category><![CDATA[sandbox]]></category>
		<category><![CDATA[Software Entwicklung]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[zahlungsabwicklung]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007-11-10-paypal-subscriptions-abonnements-in-java-integrieren/</guid>
		<description><![CDATA[Für einen Kunden habe ich in der letzten Woche die Zahlungsabwicklung von Abonnements über Paypal integriert. Der Web Nutzer kann auf diesem einfachen Wege die Vorzüge vom Premiumdiensten nutzen. Der Vorteil hierbei ist: Der potentielle Käufer muss seine Kreditkarten- bzw. Kontodaten nicht an eine &#8220;nicht vertrauenswürdige&#8221; Seite weitergeben, sondern nutzt die bereits bei Paypal hinterlegten [...]]]></description>
			<content:encoded><![CDATA[<p>Für einen Kunden habe ich in der letzten Woche die Zahlungsabwicklung von Abonnements über <a href="http://www.paypal.de">Paypal</a> integriert. Der Web Nutzer kann auf diesem einfachen Wege die Vorzüge vom Premiumdiensten nutzen. Der Vorteil hierbei ist: Der potentielle Käufer muss seine Kreditkarten- bzw. Kontodaten nicht an eine &#8220;nicht vertrauenswürdige&#8221; Seite weitergeben, sondern nutzt die bereits bei <a href="http://www.paypal.de">Paypal</a> hinterlegten Daten. Ist der Käufer noch keine <a href="http://www.paypal.de">Paypal</a> Kunde, ist eine vorige Anmeldung allerdings notwendig.</p>
<p><span id="more-18"></span></p>
<p>Der grundlegende Mechanismus für Subscriptions ist denkbar einfach. An einer beliebigen Stelle in unserer Webapplikation wird der Benutzer per link oder submit button an die Paypal Seite geleitet. Alle relevanten Daten für die Zahlung werden entweder als GET Parameter (Link) oder POST Parameter (Button) übertragen. Dazu zählen vor allem folgende Angaben:</p>
<ul>
<li>Abonnementinterval (1 Tag, 4 Wochen oder 12 Monate)</li>
<li>Betrag pro Abonnementinterval</li>
<li>Währung</li>
<li>Paypal Id des Verkäufers</li>
<li>Rechnungsnummer</li>
<li>Automatische Verlängerung (ja/nein)</li>
<li>Beliebige zusätzliche Informationen</li>
</ul>
<p>Sollte der Benutzer noch kein Paypal Kunde sein, muss er sich bei Paypal erst registrieren. Um dies so einfach wie möglich zu gestalten können wir zusätzlich Benutzerinformationen mitsenden, die Paypal in das Registrierungsformular einfügt.</p>
<ul>
<li>Name, Nachname</li>
<li>Adress(Strasse, <abbr title="Postleitzahl">PLZ</abbr>, Stadt, Land)</li>
<li>Email Adresse</li>
</ul>
<p>Damit wir zum Testen unserer Applikation kein Vermögen hinblättern müssen, stellt Paypal eine sogenannte Sandbox zur Verfügung. Eine eigene <a href="https://developer.paypal.com">Developer Sandbox</a> kann man sich hier einrichten. Diese <a href="https://sandbox.paypal.com">Sandbox</a> stellt die kompletten Funktionen von Paypal zur Verfügung. Mit zwei Unterschieden: Es fließt kein echtes Geld und es gibt nur die Benutzer, die wir selbst angelegt haben. Um also einen Zahlungsfluss zu simulieren müssen in der Sandbox mindestens zwei Benutzer angelegt sein (Verkäufer und Käufer). Zum Erzeugen eines einfachen Bezahlknopfes  eignet sich die Paypal Button Factory, welche unter <a href="https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_merchant&amp;nav=3">Merchant Services</a> im Paypal Menü des Verkäufers erreichbar ist. Doch es gibt auch Gründe gegen einen statischen Bezahlknopf auf der Webseite. Angenommen wir wollen mehrere Abonnements verkaufen, die sich je nach Laufzeit im Preis unterscheiden. Wäre es da nicht besser ein eigenes Formular zu erstellen, welches dem Benutzer die komplette Auswahl unserer Produkte anzeigt? Nachdem sich der Benutzer für eines unserer Abonnements entschieden hat, überträgt er seine Auswahl per druck auf den Bezahlknopf. Unsere Webapplikation wertet diese Informationen aus und leitet den Benutzer per redirect auf die Paypal Seite um. Dazu muss die <acronym title="Uniform Resource Locator" lang="en">URL</acronym> mit sämtlichen Zahlungsinformationen dynamisch erzeugt werden. Hier eine Beispielimplementierung:</p>
<pre lang="java">public String getPurchaseUrl() throws EncoderException {
	StringBuffer urlBuffer = new StringBuffer("https://www.sandbox.paypal.com/cgi-bin/webscr");
	urlBuffer.append("?no_note=1"); // Abonnements unterstützen keine Notizen
	urlBuffer.append("&amp;a3=9.99"); // Der Preis des Abonnements
	urlBuffer.append("&amp;t3=M"); // Intervall Einheit = Monate
	urlBuffer.append("&amp;p3=1"); // Intervall Länge = 1 (Monat)
	urlBuffer.append("&amp;business=verkaeufer@deine.url.de"); // Die email adresse für den verkäufer account bei paypal
	urlBuffer.append("&amp;cmd=_xclick-subscriptions"); // Wir wollen eine abonnement
	urlBuffer.append("&amp;src=1"); // Abonnement verlängert sich automatisch
	urlBuffer.append("&amp;currency_code=EUR"); // Wir nehmen Zahlungen in Euro entgegen
	urlBuffer.append("&amp;invoice=Rechnungsnummer"); // Hier kann eine Rechnungsnummer vergeben werden
	urlBuffer.append("&amp;lc=DE"); // Die Zielseite soll in deutscher Sprache angezeigt werden
	urlBuffer.append("&amp;no_shipping=1"); // Wir brauchen keine Versandadresse, denn wir verkaufen virtuelle Güter oder Dienstleistungen
	URLCodec encoder = new URLCodec();
	return encoder.encode(urlBuffer.toString());
}</pre>
<p>Für das URL Encoding, welches alle Sonderzeichen in übertragbare Zeichen umwandelt, verwende ich die <a href="http://commons.apache.org/codec/">commons-codec Bibliothek</a> von <a href="http://commons.apache.org/">Apache Commons</a>.</p>
<p><!--adsense#vert-banner--></p>
<p>Die geladene Paypal Seite enthält nun alle Zahlungsinformationen. Der Potentielle Käufer muss sich lediglich mit seinem Paypal Benutzernamen anmelden und die Zahlung bestätigen. Ist die Automatische Rückleitung aktiviert, landet der Benutzer danach wieder auf unserer Seite. Die Aktivierung kann im Paypal Menu des Verkäufers unter &#8220;Profile -&gt;Website Payment Preferences&#8221; eingestellt werden. Dazu wählt man den Radiobutton &#8220;Auto Return ON&#8221; und trägt unter &#8220;Return URL&#8221; die entsprechende Url ein, an die der Benutzer weitergeleitet werden soll. Mit dieser URL überträgt Paypal eine Transaktions Id,  wenn in den Einstellungen zusätzlich noch &#8220;Payment Data Transfer&#8221; auf &#8220;On&#8221; gesetzt wurde. Die Dokumentation für <acronym title="Payment Data Transfer" lang="en">PDT</acronym> finden man auf der <a href="https://www.paypal.com/IntegrationCenter/ic_pdt.html">Paypal Developer Seite</a>. Paypal erwartet darauf hin, dass unsere Webapplikation folgende Informationen zurück sendet:</p>
<ul>
<li>TransaktionsId</li>
<li>Identitätstoken</li>
<li> Kommando</li>
</ul>
<p>Die TransaktionsId ist die eben empfangene Id. Der Identitätstoken kann an der Stelle eingesehen werden, wo &#8220;Payment Data Transfer&#8221; angeschaltet wurde. Dies stellt sicher, dass  Zahlungsinformationen nicht an unberechtigte Personen gesendet werden. Das Kommando muss den den Wert &#8220;_notify-synch&#8221; enthalten. Hier ein Beispiel, wie die Implementierung aussehen könnte. Für den Post Request zurück an Paypal habe ich die <a href="http://jakarta.apache.org/httpcomponents/httpclient-3.x/">commons-httpclient Bibliothek</a> von <a href="http://commons.apache.org/">Apache Commons</a> verwendet.</p>
<pre lang="java">/**
 * Verabeitet Paypals Payment Data Transfer
 *
 * @param txId The transactionId
 * @return
 */
public void handleCallback(long txId) {
	Map&lt;String,Object&gt; params = new HashMap&lt;String, Object&gt;();
	params.put("cmd","_notify_synch");
	params.put("tx", txId);
	params.put("at", "IDENTITY_TOKEN");
	try {
		PostMethod method = doPostRequest("https://www.sandbox.paypal.com/cgi-bin/webscr", params);
		String responseBody = method.getResponseBodyAsString();
		if(responseBody != null) {
			if(responseBody.startsWith("SUCCESS")) {
				// Super, alles hat geklappt
				// Erfolgsnachricht anzeigen
			} else if(responseBody.startsWith("FAIL")) {
				// Die Zahlung war nicht korrekt durchgeführt
				// Fehlernachricht anzeigen
			} else {
				// Irgendwas ging richtig in die Hose
				// Fehlerbehandlung
			}
		} else {
 			// Das war auch nicht korrekt
	 		// Fehlerbehandlung
 		}
	} catch (HttpException e) {
		// Error sending PDT response
	} catch (IOException e) {
		// Error sending PDT response
	}
}
/**
 * Does a POST request to the given url and the given parameter map
 *
 * @param url
 * @param params
 * @return The method containing the response
 * @throws HttpException
 * @throws IOException
 */
public PostMethod doPostRequest(String url, Map&lt;String, Object &gt; params)
 	throws HttpException, IOException {
		HttpClient client = new HttpClient();
		HttpConnectionManager conManager = client.getHttpConnectionManager();
		HttpClientParams clientParams = client.getParams();
		clientParams.setConnectionManagerTimeout(2000);
		HttpConnectionManagerParams managerParams = conManager.getParams();
		managerParams.setConnectionTimeout(5000);
		managerParams.setSoTimeout(5000);
		PostMethod method = new PostMethod();
		method.setURI(new URI(url, false));
		HttpMethodParams paramsM = method.getParams(); // Wiederholungen unterdrücken
		paramsM.setParameter(HttpMethodParams.RETRY_HANDLER,
	 		new DefaultHttpMethodRetryHandler(0, false));
	Set&lt;String&gt; keys = params.keySet();
	for (String key : keys) {
		String value = (String) params.get(key);
		method.addParameter(key, value); // Setze Url Parameter
	}
	client.executeMethod(method); // Http Post ausführen
	return method;
}</pre>
<p>Der Benutzer merkt vom Austausch der Zahlungsinformationen nichts, Es wird lediglich eine einfache Bestätigungsseite angezeigt. Auf dieser Seite wird dem Benutzer mitgeteilt wird, dass die Zahlung erfolgreich oder nicht erfolgreich war, und dass er von Paypal per Mail darüber benachrichtigt werden wird.</p>
<p>Paypal bietet zusätzlich die Möglichkeit, unsere Webapplikation asynchron über eingehende Zahlungen und/oder Kündigungen zu informieren. Die Mechanismus nennt sich <acronym title="Instant Payment Notification" lang="en">IPN</acronym>, was soviel bedeutet wie &#8220;sofortige Zahlungsavisierung&#8221;. Dieser Mechanismus ist deutlich robuster, als &#8220;Payment Data Transfer&#8221;. Doch dazu in später mehr.</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-10-23-bots-aussperren-mit-captcha/" rel="bookmark" class="crp_title">captcha tutorial &#8211; Bots aussperren</a></li><li><a href="http://www.christophbuente.de/2009-10-29-opensocial-gadgets-apps-fur-studivz-selbst-entwickeln/" rel="bookmark" class="crp_title">Opensocial Gadgets &#8211; Apps für StudiVZ selbst entwickeln</a></li><li><a href="http://www.christophbuente.de/2008-01-24-stripes-framework-tests-fur-actionbeans-im-wizard-modus/" rel="bookmark" class="crp_title">Stripes Framework &#8211; Tests für ActionBeans im Wizard Modus</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2009-09-09-500-internal-server-error-apache-config-vs-wp-super-cache/" rel="bookmark" class="crp_title">500 Internal Server Error &#8211; Apache config vs. WP-Super-Cache</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-11-10-paypal-subscriptions-abonnements-in-java-integrieren/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Shell Ausgabeumleitung &#8211; Fehlermeldungen in der Standardausgabe</title>
		<link>http://www.christophbuente.de/2007-11-02-shell-ausgabeumleitung-fehlermeldungen-in-der-standardausgabe/</link>
		<comments>http://www.christophbuente.de/2007-11-02-shell-ausgabeumleitung-fehlermeldungen-in-der-standardausgabe/#comments</comments>
		<pubDate>Thu, 01 Nov 2007 22:33:20 +0000</pubDate>
		<dc:creator>Christoph Bünte</dc:creator>
				<category><![CDATA[Allgemeines]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[Unix shell]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[ausgabeumleitung]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[shell]]></category>
		<category><![CDATA[sox]]></category>
		<category><![CDATA[stderr]]></category>
		<category><![CDATA[stdout]]></category>
		<category><![CDATA[tips und tricks]]></category>
		<category><![CDATA[umleitung]]></category>

		<guid isPermaLink="false">http://www.christophbuente.de/2007-11-02-shell-ausgabeumleitung-fehlermeldungen-in-der-standardausgabe/</guid>
		<description><![CDATA[Hin und wieder braucht man ein paar Tips und Tricks für die Kommandozeile. Im Internet findet sich zahlreiche Hilfe. Doch nach spätestens zwei Wochen hat man es wieder vergessen, und die Suche geht von vorne Los. Aus Gründen meiner eigenen Vergesslichkeit hier nun auch für die Öffentlichkeit Zum Beispiel: Wie leitet man die Fehlerausgabe von [...]]]></description>
			<content:encoded><![CDATA[<p>Hin und wieder braucht man ein paar Tips und Tricks für die Kommandozeile. Im Internet findet sich zahlreiche Hilfe. Doch nach spätestens zwei Wochen hat man es wieder vergessen, und die Suche geht von vorne Los. Aus Gründen meiner eigenen Vergesslichkeit hier nun auch für die Öffentlichkeit <img src='http://www.christophbuente.de/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Zum Beispiel: Wie leitet man die Fehlerausgabe von Programmen auf das Standard Ausgabegerät um?</p>
<p><span id="more-17"></span></p>
<p>[ad#vert-banner]</p>
<p>Mit einem einfachen Trick kann man Ausgaben von der Fehlerausgabe auf die Standardausgabe umleiten, um eben diese  Ausgabe in anderen Programmen weiter zu verwenden.</p>
<pre lang="bash">$ <erstesKommando> 2>&#038;1 | <zweitesKommando> </pre>
<p>Die Fehlerausgabe von &#8220;erstesKommando&#8221; wird auf die Standardausgabe umgelenkt. Als besonderes Beispiel sei hier <a href="http://sox.sourceforge.net/">SOX</a> genannt. Es gilt als das Schweizer Taschenmesser der Audioverarbeitung auf der Kommandozeile.</p>
<pre lang="bash">$ sox beispiel.wav -e stat 2>&#038;1 | grep Length | awk '{print $3}'</pre>
<p>Diese Kommandofolge analysiert die Audiodatei beispiel.wav, filtert die Zeile aus dem Ergebnis, welche &#8220;Length&#8221; enthält, und gibt anschließend das dritte Wort aus. In diesem Fall handelt es sich dabei um die Länge in Sekunden.</p>
<p>Et voilà!</p>
<div id="crp_related"><h3>Ähnliche Beiträge:</h3><ul><li><a href="http://www.christophbuente.de/2007-06-19-performance-tests/" rel="bookmark" class="crp_title">Performance Tests</a></li><li><a href="http://www.christophbuente.de/2007-12-06-voiceglue-installation-interactive-voice-response-leicht-gemacht/" rel="bookmark" class="crp_title">VoiceGlue Installation &#8211; Interactive Voice Response leicht gemacht</a></li><li><a href="http://www.christophbuente.de/2007-11-17-canoo-webtest-web-anwendungen-automatisch-testen/" rel="bookmark" class="crp_title">canoo webtest &#8211; Web-Anwendungen automatisch testen</a></li><li><a href="http://www.christophbuente.de/2007-12-01-mac-software-heise-deals-zur-weihnachtszeit/" rel="bookmark" class="crp_title">Mac Software &#8211; heiße Deals zur Weihnachtszeit</a></li><li><a href="http://www.christophbuente.de/2007-11-24-advancing-rails-ein-workshop-mit-david-a-black/" rel="bookmark" class="crp_title">Advancing Rails &#8211; Ein Workshop mit David A. Black</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://www.christophbuente.de/2007-11-02-shell-ausgabeumleitung-fehlermeldungen-in-der-standardausgabe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using memcached (Feed is rejected)
Page Caching using memcached
Database Caching 12/53 queries in 0.092 seconds using memcached
Object Caching 1565/1682 objects using memcached

Served from: www.christophbuente.de @ 2012-02-07 08:39:51 -->
