<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-4466305307772589754</atom:id><lastBuildDate>Thu, 19 Jan 2017 09:47:33 +0000</lastBuildDate><category>Grails</category><category>IT-Consulting</category><category>ElasticSearch</category><category>Konferenz</category><category>exensio</category><category>Portal</category><category>Groovy</category><category>claretportal</category><category>User Interface</category><category>Mobile</category><category>e20</category><category>Informationsportal</category><category>Testing</category><category>JavaScript</category><category>solr</category><category>BigData</category><category>HTML5</category><category>Business Intelligence</category><category>Excel</category><category>Open-Source</category><category>Selenium</category><category>Usability</category><category>socialmedia</category><category>Testautomatisierung</category><category>java</category><category>Apache Webserver</category><category>Browsertest</category><category>D3</category><category>Enterprise Search</category><category>Geb</category><category>IoT</category><category>Logstash</category><category>Sensoren</category><category>Springboot</category><category>Statistical Data</category><category>Tomcat</category><category>sharepoint</category><category>Kapow</category><category>Kibana</category><category>Spock</category><category>socbiz</category><category>Kofax</category><category>Lucene</category><category>MySQL</category><category>Python</category><category>RaspberryPi</category><category>WebLogic Portal</category><category>WebLogic Server</category><category>pharma</category><category>Enterprise Applikationen</category><category>Jira</category><category>Responsive Design</category><category>Spring</category><category>Wissensmanagement</category><category>barcamp</category><category>jquery mobile</category><category>BI</category><category>Confluence</category><category>Content</category><category>GORM</category><category>Knowledgemanagement</category><category>Migration</category><category>Nagios</category><category>Play framework</category><category>REST</category><category>Responsive Web Design</category><category>Rickshaw</category><category>Web Applikation</category><category>rwd</category><category>AS3</category><category>BPMN</category><category>CMS</category><category>EPK</category><category>Flash</category><category>Integration</category><category>Liferay</category><category>Monitoring</category><category>NVD3.js</category><category>PIM</category><category>Projektplanung</category><category>Qlik</category><category>SNMP</category><category>Scrapy</category><category>Security</category><category>Sense</category><category>Virtualisierung</category><category>Web Scraping</category><category>Wiki</category><category>agile</category><category>bcka</category><category>cloud</category><category>excel2web</category><category>ggx</category><category>iPad</category><category>shipit-day</category><category>vaadin</category><category>web</category><category>ADF</category><category>API</category><category>ActionScript</category><category>Anforderungsanalyse</category><category>Anforderungsmanagement</category><category>Apache Wink</category><category>Apps</category><category>Aufgabenplanung</category><category>Auswahlberatung</category><category>Automatisierter Build</category><category>Batch</category><category>Beratung</category><category>BlackBerry</category><category>Build Prozess</category><category>CKEditor</category><category>Canvas</category><category>Compass Search</category><category>DMS</category><category>DPWK</category><category>DWH</category><category>EJB 3.0</category><category>ESB</category><category>ETL</category><category>EclipseLink</category><category>Enterprise Application Integration</category><category>Enterprise Service Bus</category><category>Evaluation</category><category>FacetView</category><category>Fail2ban</category><category>Fixtures</category><category>Flex</category><category>Geolocation</category><category>Glosse</category><category>Grid</category><category>Grok</category><category>Groovy Migration</category><category>Hibernate</category><category>Informationsmanagement</category><category>JPA</category><category>JRockit</category><category>Jetty</category><category>Kettle</category><category>Kontraktlogistik</category><category>Lancom</category><category>Layout</category><category>Leaflet</category><category>Lizenzen</category><category>LocalConnection</category><category>Logistik</category><category>Map</category><category>Mapbox</category><category>Mocha</category><category>Node.js</category><category>OS X</category><category>Offshoring</category><category>Pharmamarketing</category><category>Pharmavertrieb</category><category>Piwik</category><category>Propagation</category><category>Prozessanalyse</category><category>Prozessmodellierung</category><category>R</category><category>Releaseplanung</category><category>Requirements Engineering</category><category>Requirements Management</category><category>Router</category><category>Ruby</category><category>SAP EP</category><category>SVG</category><category>Sauce Labs</category><category>ScanCode toolkit</category><category>SeInterpreter</category><category>Sensor</category><category>Snapsvg</category><category>Spezifikation</category><category>Subversion</category><category>Taxonomie</category><category>Tweepy</category><category>WebDAV</category><category>Webtest</category><category>Wissensdatenbank</category><category>akka</category><category>bcs5</category><category>bedcon</category><category>digital workplace</category><category>industrie40</category><category>ionic</category><category>jax</category><category>km</category><category>olap</category><category>projektinfo</category><category>soa</category><category>web20</category><title>exensio it blog</title><description></description><link>http://blog.exensio.de/</link><managingEditor>noreply@blogger.com (Peter Soth)</managingEditor><generator>Blogger</generator><openSearch:totalResults>246</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-8990823025886432462</guid><pubDate>Thu, 03 Nov 2016 09:00:00 +0000</pubDate><atom:updated>2016-11-04T07:53:35.476+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">exensio</category><category domain="http://www.blogger.com/atom/ns#">pharma</category><category domain="http://www.blogger.com/atom/ns#">PIM</category><title>Preisbindung für rezeptpflichtige Medikamente – Warum sich Pharma-politische Entscheidungen auf unsere IT Lösungen auswirken?</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-XVve8lX_nYM/WBNQQ2CjWNI/AAAAAAAACA4/5zT22NhyrI8oNzpeWuwS3hBQ289AuMgGACLcB/s1600/pharma_preise_300x200.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://3.bp.blogspot.com/-XVve8lX_nYM/WBNQQ2CjWNI/AAAAAAAACA4/5zT22NhyrI8oNzpeWuwS3hBQ289AuMgGACLcB/s1600/pharma_preise_300x200.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Vor kurzem hat der Europäische Gerichtshof die Preisbindung für verschreibungspflichtige Medikamente in Deutschland gekippt (siehe u.a. &lt;a href=&quot;http://www.tagesschau.de/wirtschaft/eugh-arzneimittel-103.html&quot;&gt;http://www.tagesschau.de/wirtschaft/eugh-arzneimittel-103.html&lt;/a&gt;). Was steckt dahinter? In Deutschland ist die Preisbildung für verschreibungspflichtige Arzneimittel gesetzlich geregelt (Arzneimittelpreisverordnung). Dahinter steckt der Grundgedanke, dass Patienten das gleiche Medikament in jeder Apotheke zum gleichen Preis erhalten. Kranke sollen in ihrer Notlage nicht noch Preise vergleichen müssen. Zudem soll mit dem System die Grund- und Notfallversorgung mit Medikamenten sichergestellt werden.&lt;br /&gt;&lt;br /&gt;D.h. deutschen Apotheken ist es für rezeptpflichtige Arzneimittel nicht erlaubt, Rabatte zu gewähren. Dies gilt auch für Versandapotheken.&lt;br /&gt;&lt;br /&gt;Mit dem Urteil des EuGH ist diese Preisbindung für ausländische Versandapotheken nun aufgehoben worden. Der Aufschrei der deutschen (Versand-)Apotheken blieb natürlich nicht aus, wenn ab sofort über den ausländischen Apotheken-Versandhandel die gleichen Medikamente zu günstigerem Preis erworben werden können und in Deutschland aber die Preisbindung gilt.&lt;br /&gt;&lt;br /&gt;2 Lösungsszenarien liegen auf der Hand: Entweder wird nun auch für deutsche (Versand-) Apotheken die Preisbindung aufgehoben oder der Versandhandel für rezeptpflichtige Medikamente wird verboten. Zu letzterer Variante gibt es bereits einen Vorstoß durch den Gesundheitsminister (siehe u.a. &lt;a href=&quot;https://www.welt.de/newsticker/dpa_nt/infoline_nt/schlaglichter_nt/article159106082/Groehe-will-Versandhandel-mit-Arzneien-auf-Rezept-verbieten.html&quot;&gt;https://www.welt.de/newsticker/dpa_nt/infoline_nt/schlaglichter_nt/article159106082/Groehe-will-Versandhandel-mit-Arzneien-auf-Rezept-verbieten.html&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Wieso beschäftigen wir von exensio uns mit diesem Thema? exensio erstellt IT Lösungen in unterschiedlichen Bereichen von Pharmaunternehmen. Da wir die geschäftlichen Abläufe und Hintergründe verstehen müssen, ist es für uns wichtig, immer ein Ohr an den aktuellen fachlichen Entwicklungen zu haben.&lt;br /&gt;&lt;br /&gt;So hat exensio für einen unserer Pharma Kunden ein PIM (Product Information Management) System implementiert, mit dem unter anderem sämtliche Preise für alle Präparate verwaltet werden. Dazu gehören der Hersteller Abgabepreis (HAP), der Apotheken Einkaufspreis (AEP) sowie der Apotheken Verkaufspreis (AVP).&lt;br /&gt;&lt;br /&gt;Der Hersteller kann diese Preise regelmäßig (alle 14 Tage) ändern und meldet diese der IFA (Informationsstelle für Arzneimittelspezialitäten). Mit Hilfe unserer PIM Lösung können diese Preisanpassungen auf elektronischem Wege automatisiert übermittelt (und Rückmeldungen verarbeitet) werden.&lt;br /&gt;&lt;br /&gt;Je nach Lösung des oben beschriebenen Konflikts würde dies eine Änderung für unser Modul &quot;Preisänderungsmeldung&quot; implizieren. Warten wir ab, wer sich durchsetzt.</description><link>http://blog.exensio.de/2016/11/preisbindung-fur-rezeptpflichte.html</link><author>noreply@blogger.com (Irving Tschepke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-XVve8lX_nYM/WBNQQ2CjWNI/AAAAAAAACA4/5zT22NhyrI8oNzpeWuwS3hBQ289AuMgGACLcB/s72-c/pharma_preise_300x200.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-9029588474761815271</guid><pubDate>Wed, 19 Oct 2016 07:57:00 +0000</pubDate><atom:updated>2016-10-19T10:14:22.787+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">cloud</category><category domain="http://www.blogger.com/atom/ns#">Content</category><category domain="http://www.blogger.com/atom/ns#">Open-Source</category><category domain="http://www.blogger.com/atom/ns#">Python</category><category domain="http://www.blogger.com/atom/ns#">Responsive Design</category><category domain="http://www.blogger.com/atom/ns#">Scrapy</category><category domain="http://www.blogger.com/atom/ns#">Tweepy</category><category domain="http://www.blogger.com/atom/ns#">Web Scraping</category><title>Integration mit Scrapy und Tweepy</title><description>In diesem Posting gehe ich auf die Integration von Webinhalten mittels Scrapy und Tweepy ein. Ich zeige, wie man einen Scrapy-Spider bei Srapinghub betreibt und wie man Tweets auf Twitter postet.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Problemstellung&lt;/h3&gt;Eine Webseite (in diesem Fall im Internet) stellt Content zur Verfügung, der potentiell für eine breite Masse von Interesse ist. Die Usability der Webseite stellt eine hohe Hürde für viele User dar. Das beginnt beispielsweise am fehlenden Responsive Design, geht weiter über mangelnde Teilbarkeit und endet bei nicht vorhandener, moderner Funktionalität. Die Ursachen für die Mängel sind vielschichtig und reichen von nicht vorhandenem Budget bis zur falschen Wahl des verwendeten Frameworks bzw. veralteter Technologie. Ähnlich verhält es sich mit der Ablösung des Systems, die eigentlich folgerichtig wäre. Die üblichen Gründe für den Weiterbetrieb sind z.B. fehlendes Bewußtsein der Mängel, eingeschränktes KnowHow bzgl. neuer Technologien oder nicht vorhandenes Budget.&lt;br /&gt;&lt;br /&gt;Das bestehende System wird trotz der Mängel vom Betreiber intensiv genutzt. Ziel des Projekts ist die einfache Integration der im Quellsystem zur Verfügung gestellten Inhalte in moderne Technologien, hier gezeigt anhand von Twitter. Die Vorteile der vorgestellten Lösung sind geringe Integrationskosten, cloudbasierte Lösung, die kaum Verwaltungsaufwand erfordert, bestehende Arbeitsprozesse seitens des Betreibers bleiben unverändert. Durch die Veröffentlichung auf Twitter wird der zur Verfügung gestellte Inhalt auf einfachste Weise einem breiten Publikum zugänglich gemacht. Zugleich lassen sich sämtliche Vorteile der Plattform nutzen (Teilbarkeit, Usability, Responsive Design). &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Projektübersicht und Ablauf&lt;/h3&gt;Das Quellsystem verfügt über keinerlei Schnittstelle oder API, so dass entschieden wurde, die zur Verfügung gestellten Inhalte mit Screen Scraping Technologie auszulesen. Die Wahl fiel auf das Framework Scrapy [1], da es einfach in der Handhabung ist und es sich günstig in der Cloudlösung Scrapinghub [2] betreiben lässt.&lt;br /&gt;Aus den oben genannten Gründen wurde für die Wiederveröffentlichung der erfassten Inhalte der Mikrobloggingdienst Twitter [3] gewählt. Durch die zuvor genannte Festlegung der Web Scraping Technologie (Scrapy benutzt Python) musste ein auf Python basiertes Tool gefunden werden. Hier bot sich die Verwendung von Tweepy [4] an, einer einfach zu benutzenden Python Bibliothek für die Twitter API.&lt;br /&gt;Abgerundet wird die Lösung durch den Einsatz von TinyURL [5], einem Kurz-URL-Dienst, der sich sehr einfach in Python integrieren lässt. Dieser Schritt ist notwendig, um die 140-Zeichen Grenze von Twitter einzuhalten und dennoch sinnvolle Inhalte zu posten.&lt;br /&gt;&lt;br /&gt;Der Scrapy-Spider wird nach seiner Erstellung in den Srapinghub geladen. Dort wird ein &lt;i&gt;scheduled Job&lt;/i&gt; angelegt, der z.B. stündlich ausgeführt wird. Die durch den Spider erfassten Inhalte werden im Spider selbst anhand von Selektoren verarbeitet und in &lt;i&gt;Items&lt;/i&gt; aufgeteilt. Alle Items werden anschließend an eine &lt;i&gt;Pipeline&lt;/i&gt; übergeben. In der Pipeline sind weitere Bearbeitungsschritte möglich, wie z.B. Aufarbeitung von Inhalten oder Veröffentlichung als Tweet.&lt;br /&gt;&lt;br /&gt;Im Spider wird der &lt;i&gt;Request&lt;/i&gt; auf die angegebene URL ausgeführt und die erfassten Daten schrittweise verarbeitet. Im ersten Schritt werden die erfassten IDs mit den bereits bearbeiteten IDs verglichen. Items mit IDs, die bereits bekannt sind, werden ausgefiltert. Auf diese Weise wird Persistenz erreicht und es wird verhindert, dass bereits bearbeitete Inhalte erneut veröffentlicht werden.&lt;br /&gt;Anschließend werden alle nicht gefilterten Items an die Pipeline durchgereicht, siehe Code Listing 1:&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/a7cbf47c600e3a8e523e31c39fdf7569.js&quot;&gt;&lt;/script&gt; Die Pipeline umfasst zwei Schritte.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Kurz-URL anlegen&lt;br /&gt;Für die Erzeugung der Kurz-URL bot sich TinyURL auch deswegen an, weil weder ein Account erforderlich ist, noch eine eigene Bibliothek installiert werden muss. Dies kann einfach mit den Modulen &lt;i&gt;requests&lt;/i&gt; und &lt;i&gt;json&lt;/i&gt; erledigt werden, siehe Code Listing 2:&lt;script src=&quot;https://gist.github.com/exblog/6ae87bd2718b44deb567089127b7599d.js&quot;&gt;&lt;/script&gt;&lt;/li&gt;&lt;li&gt;Tweet posten&lt;br /&gt;Bevor der erfasste Inhalt getweetet werden kann, soll ein &lt;i&gt;Hashtag&lt;/i&gt; hinzugefügt werden. Und natürlich muss die verkürzte URL zum eigentlichen Inhalt eingefügt werden. Schließlich muss noch kontrolliert werden, dass der gesamte Tweet nicht länger als 140 Zeichen lang ist. Sollte der Text die Grenze überschreiten, muss gekürzt werden, siehe Code Listing 3:&lt;script src=&quot;https://gist.github.com/exblog/2e75e3fe78553b4393b78abcc1e0a9ba.js&quot;&gt;&lt;/script&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3&gt;Hands on...&lt;/h3&gt;Zur Vorbereitung der Arbeitsumgebung gehört die Installation von Scrapy, Tweepy und weiteren Tools. Unter Linux also: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;sudo pip install Scrapy&lt;br /&gt;sudo pip install tweepy&lt;br /&gt;sudo pip install shub&lt;br /&gt;&lt;/pre&gt;shub [6] installiert den &lt;i&gt;Scrapinghub Command Line Client&lt;/i&gt;. Der Client stellt ein praktisches Tool für die Entwicklung und das Deployment des Projekts auf Scrapinghub dar.Zuerst muss ein Projektverzeichnis angelegt werden. Mit dem Kommando: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;scrapy startproject myProject&lt;br /&gt;&lt;/pre&gt;erstellt Scrapy das komplette Projektverzeichnis inkl. aller zusätzlicher Dateien. Die Datei &lt;i&gt;settings.py&lt;/i&gt; enthält alle Einstellungen auf Projektebene. Die Datei &lt;i&gt;pipelines.py&lt;/i&gt; enthält die oben definierten Pipelines. Und in der Datei &lt;i&gt;items.py&lt;/i&gt; werden die Attribute unseres Items festgelegt.&lt;br /&gt;&lt;br /&gt;Im nächsten Schritt wird mit dem folgenden Kommando ein Scrapy-Spider angelegt und seine Start-URL definiert: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;scrapy genspider mySpider start.url&lt;br /&gt;&lt;/pre&gt;Scrapy erstellt in diesem Fall die Datei mySpider.py, mit einem Grundgerüst eines Scrapy-Spiders. Die Datei lässt sich anschließend in einem Editor bearbeiten. Für das Grundgerüst unterstützt Scrapy Templates und Profile. Mehr dazu ist in der Hilfe jedes Befehls zu finden (&lt;i&gt;scrapy genspider -h&lt;/i&gt;).&lt;br /&gt;&lt;br /&gt;Ist der Spider ausreichend an die eigenen Bedürfnisse angepasst, lässt er sich mit diesem Kommando starten: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;scrapy crawl mySpider&lt;br /&gt;&lt;/pre&gt;Bei diesem Aufruf findet die Ausgabe mit dem DEBUG Loglevel auf stdout statt. Damit lässt sich also prima überprüfen, was der Spider im Detail macht. Dort sieht man insbesondere auch die verwendeten Umgebungsvariablen, die angewendeten Einstellungen (bestehend aus globalen Scrapy-Einstellungen, Projekteinstellungen und Spider-Einstellungen), die Attribute unserer Items und die verwendeten Pipelines.&lt;br /&gt;&lt;br /&gt;Bevor das Projekt nach Scrapinghub geladen werden kann, müssen evtl. vorhandene Abhängigkeiten zu Fremd-Modulen berücksichtigt werden. Scrapinghub erlaubt die Möglichkeit, externe Bibliotheken zu definieren [7]. Ich habe mit dem folgenden Kommando die Abhängigkeiten in meinem Projekt ermittelt: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;pip freeze &amp;gt; requirements.txt&lt;br /&gt;&lt;/pre&gt;Anschließend verweise ich in der Datei &lt;i&gt;scrapinghub.yml&lt;/i&gt; auf meine soeben erstellte Datei &lt;i&gt;requirements.txt&lt;/i&gt;, siehe Code Listing 4: &lt;script src=&quot;https://gist.github.com/exblog/eaed4240e8c64ac9f274707030c9734f.js&quot;&gt;&lt;/script&gt;Jetzt sind alle Bedingungen erfüllt und das Projekt kann nach Scrapinghub geladen werden. Für das Deployment dient der Befehl: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;shub deploy&lt;br /&gt;&lt;/pre&gt;Beim ersten Aufruf dieses Befehl wird ein Wizard gestartet, mit dessen Hilfe die benötigen Einstellungen für den Upload beu Scrapinghub vorgenommen werden. Nach erfolgtem Deployment sieht eine typische Ausgabe so aus: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;Packing version 1.0&lt;br /&gt;Deploying to Scrapy Cloud project &quot;myProjectId&quot;&lt;br /&gt;{&quot;status&quot;: &quot;ok&quot;, &quot;version&quot;: &quot;1.0&quot;, &quot;spiders&quot;: 1, &quot;project&quot;: myProjectId}&lt;br /&gt;Run your spiders at: https://app.scrapinghub.com/p/myProjectId/&lt;br /&gt;&lt;/pre&gt;Da das Deployment erfolgreich war, folgt jetzt der große Moment, in dem der Spider das erste Mal gestartet wird. Der Spider kann entweder über die Weboberfläche von Scrapinghub gestartet werden, oder wieder über den Command Line Client. Das Kommando dafür ist: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;shub schedule mySpider&lt;br /&gt;&lt;/pre&gt;Der Aufruf wird typischerweise quittiert durch die folgende Ausgabe, die Hinweise auf das Logging enthält: &lt;br /&gt;&lt;pre class=&quot;java&quot; name=&quot;code&quot;&gt;Spider mySpider scheduled, job ID: myProjectId/1/1&lt;br /&gt;Watch the log on the command line:&lt;br /&gt;    shub log -f 1/1&lt;br /&gt;or print items as they are being scraped:&lt;br /&gt;    shub items -f 1/1&lt;br /&gt;or watch it running in Scrapinghub&#39;s web interface:&lt;br /&gt;    https://app.scrapinghub.com/p/myProjectId/job/1/1&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Tipp: Persistenz zwischen Läufen eines Spiders&lt;/h3&gt;Häufig wird in der Scrapinghub Dokumentation und in Foren zum Thema Persistenz auf das Addon &lt;i&gt;DeltaFetch&lt;/i&gt; [8] verwiesen. Dieses Addon ist dazu geeignet, das Erfassen von URLs zu vermeiden, die bereits früher analysiert wurden. Ist der eigene Spider also so angelegt, dass die zu erfassenden URLs aus der Start-URL gescrapt werden, dann ist DeltaFethc in der Lage zu unterscheiden, ob die eingelesenen URLs in einem vorigen Lauf schon ausgelesen wurden. In diesem Fall werden diese URLs nicht erneut bearbeitet.&lt;br /&gt;Im aktuellen Projekt werden allerdings keine URLs erfasst, sondern IDs die sich in Div-Tags befinden und die keine eigene URL besitzen. Deshalb war es für die Persistenz erforderlich, eine eigene Lösung zu entwickeln. Als Basis dient das Addon &lt;i&gt;DotScrapy&lt;/i&gt; [9], das die Funktion &lt;i&gt;data_path()&lt;/i&gt; zur Verfügung stellt. Umgesetzt wurden die Funktionen &lt;i&gt;setLastRunId()&lt;/i&gt; und &lt;i&gt;getLastRunId()&lt;/i&gt;, siehe Code Listing 1. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Fazit&lt;/h3&gt;Mit der vorgestellten Lösung lassen sich Webinhalte von schwer zugänglichen Webseiten auf einfache, günstige und schnelle Weise einem großen Publikum zur Verfügung stellen. Die Lösung ist vollständig cloudbasiert, erfordert also keinerlei eigene Administration. Durch die Screen Scraping Technik müssen weder bestehende Prozesse, noch bestehende Systeme angepasst werden.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Links&lt;/h3&gt;[1] &lt;a href=&quot;https://scrapy.org/&quot;&gt;Scrapy&lt;/a&gt;&lt;br /&gt;[2] &lt;a href=&quot;https://scrapinghub.com/&quot;&gt;Scrapinghub&lt;/a&gt;&lt;br /&gt;[3] &lt;a href=&quot;https://twitter.com/&quot;&gt;Twitter&lt;/a&gt;&lt;br /&gt;[4] &lt;a href=&quot;http://www.tweepy.org/&quot;&gt;Tweepy&lt;/a&gt;&lt;br /&gt;[5] &lt;a href=&quot;https://tinyurl.com/&quot;&gt;TinyURL&lt;/a&gt;&lt;br /&gt;[6] &lt;a href=&quot;https://pypi.python.org/pypi/shub&quot;&gt;Scrapinghub Command Line Client&lt;/a&gt;&lt;br /&gt;[7] &lt;a href=&quot;https://doc.scrapinghub.com/scrapy-cloud.html#dependencies-and-external-libraries&quot;&gt;Dependencies and External Libraries in Scrapinghub&lt;/a&gt;&lt;br /&gt;[8] &lt;a href=&quot;https://doc.scrapinghub.com/addons.html#deltafetch&quot;&gt;Scrapinghub Addon DeltaFetch&lt;/a&gt;&lt;br /&gt;[9] &lt;a href=&quot;https://doc.scrapinghub.com/addons.html#dotscrapy-persistence&quot;&gt;Scrapinghub Addon DotScrapy&lt;/a&gt;</description><link>http://blog.exensio.de/2016/10/integration-mit-scrapy-und-tweepy.html</link><author>noreply@blogger.com (Roland Rickborn)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3650104092735786688</guid><pubDate>Thu, 13 Oct 2016 09:20:00 +0000</pubDate><atom:updated>2016-10-13T11:20:43.999+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">Spock</category><category domain="http://www.blogger.com/atom/ns#">Testautomatisierung</category><category domain="http://www.blogger.com/atom/ns#">Testing</category><title>Grails, good to know: Working with the Build Test Data Plugin</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-70G4zkoHwbU/V_9OhAuAxGI/AAAAAAAAA1M/aH6RySbJuHonnU19gRL0ZUqkhpBS98dEwCLcB/s1600/Grails_logo_2009_2010.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://4.bp.blogspot.com/-70G4zkoHwbU/V_9OhAuAxGI/AAAAAAAAA1M/aH6RySbJuHonnU19gRL0ZUqkhpBS98dEwCLcB/s200/Grails_logo_2009_2010.jpg&quot; width=&quot;200&quot; height=&quot;56&quot; /&gt;&lt;/a&gt;&lt;/div&gt;There are several choices for creating test data when working with &lt;a href=&quot;https://grails.org/&quot; target=&quot;_blank&quot;&gt;Grails&lt;/a&gt;. Beside the manual creation of domain objects it is possible to use one of the existing plugins. Before Grails 3.0 one of the good choices was the &lt;a href=&quot;https://grails.org/plugin/fixtures&quot; target=&quot;_blank&quot;&gt;Fixture Plugin&lt;/a&gt; for specifying domain test data. This plugin is not ported to newer Grails versions and therefore no longer an option. Another good choice is the &lt;a href=&quot;https://github.com/longwa/build-test-data/wiki&quot; target=&quot;_blank&quot;&gt;Build Test Data Plugin&lt;/a&gt; which is in the focus of this post. &lt;br /&gt;&lt;br /&gt;After referencing the plugin via the build.gradle file, new domain objects can be created easily by calling the &lt;i&gt;build()&lt;/i&gt; method on a domain class.  The following listing demonstrates the usage by creating two new entities of the type project. All required attributes of the entities are populated automatically or can be alternatively specified explicitly as shown for the second entity. &lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/244b8ad330802b640847c67d873f1fab.js&quot;&gt;&lt;/script&gt; The &lt;a href=&quot;https://github.com/longwa/build-test-data/wiki&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt; provides more information on the general usage of the plugin. The following sections provide two best practices on using some less known features of the Build Test Data Plugin. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Testing REST APIs&lt;/h2&gt;&lt;br /&gt;Nowadays many Grails applications provide REST APIs that have also run through the automatic test cycles.  Assuming in our case that an existing project from an external system should be imported via REST, it is necessary for a test to construct a post request that contains all necessary attributes and especially an ID. When calling the standard &lt;i&gt;build()&lt;/i&gt; method on the project entity and then converting it to JSON, the object will already be saved in the database before sending it via REST to the application. This can be avoided by calling the &lt;i&gt;buildWithoutSave()&lt;/i&gt; method instead of the &lt;i&gt;build()&lt;/i&gt; method. An example for the usage is shown in the following code snippet:  &lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/edd59f4e46f57df256d86ad27e73aed7.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;&lt;h2&gt;Creation of custom identities&lt;/h2&gt;&lt;br /&gt;The ID of the entity is available after creating a new entity via the &lt;i&gt;build()&lt;/i&gt; method, when using the standard settings for domain classes. Depending on the requirements it might be necessary to use custom IDs for the database that are assigned manually. This can be specified in the mapping block of a domain class, as shown below: &lt;script src=&quot;https://gist.github.com/exblog/eba5acec99785ed0c30441306a5cb095.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;To avoid the manual assignment of IDs in test cases it is possible to enhance the &lt;a href=&quot;https://github.com/longwa/build-test-data/wiki/TestDataConfig&quot; target=&quot;_blank&quot;&gt;TestDataConfig&lt;/a&gt; file. This file of the BuildTestData Plugin can be used to define static or dynamic values for the attributes of entities when creating test data.  In our case we assume that UUIDs are assigned as IDs to the domain classes. We want to make sure that an artificial ascending UUID is assigned to every created entity. This can be done by defining a closure that generates the assignment code of an ID for each domain class which is shown in the following listing. &lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/8115f18323d7cbf640d833ebe3d91076.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;A simple test for verifying the creation of project entities and its correct UUID assignment can look like shown below. &lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/a84601785abd9e8067c07eadc56ec091.js&quot;&gt;&lt;/script&gt;  </description><link>http://blog.exensio.de/2016/10/grails-good-to-know-working-with-build.html</link><author>noreply@blogger.com (Tobias Kraft)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://4.bp.blogspot.com/-70G4zkoHwbU/V_9OhAuAxGI/AAAAAAAAA1M/aH6RySbJuHonnU19gRL0ZUqkhpBS98dEwCLcB/s72-c/Grails_logo_2009_2010.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-7653698935958895781</guid><pubDate>Wed, 05 Oct 2016 08:26:00 +0000</pubDate><atom:updated>2016-10-05T10:26:48.079+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Geb</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">Groovy</category><category domain="http://www.blogger.com/atom/ns#">Migration</category><category domain="http://www.blogger.com/atom/ns#">Testing</category><category domain="http://www.blogger.com/atom/ns#">Webtest</category><title>Migration von Grails 1.3.7 nach 3.1.9 - Testing - Teil 3</title><description>Dies ist der dritte Beitrag über die Migration einer Grails Applikation. Im &lt;a href=&quot;http://blog.exensio.de/2016/08/migration-grails-137-nach-319.html&quot;&gt;ersten Teil&lt;/a&gt;&amp;nbsp;habe ich mich mit allgemeinen Schwierigkeiten und Lösungen befasst und im &lt;a href=&quot;http://blog.exensio.de/2016/08/migration-grails-137-nach-319-erstellen.html&quot;&gt;Zweiten Teil&lt;/a&gt;&amp;nbsp;eine selbstentwickelte Lösung zum Erstellen von Testdaten vorgestellt. In diesem Beitrag werde ich speziell die Tests beleuchten.&lt;br /&gt;&lt;h4&gt;Testarten&lt;/h4&gt;In der existierenden Applikation gibt es eine übersichtliche Anzahl von Unit-Tests. Der größte Teil der Integrationstests besteht aus Controller- Integrationstests und nur wenigen Service- Integrationstests. Als funktionale Tests wurden historisch bedingt die Frameworks&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Geb&lt;/span&gt; und &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Webtest&lt;/span&gt;&amp;nbsp;eingesetzt.&lt;br /&gt;In früheren Versionen konnte das Testing Framework &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Spock&lt;/span&gt; über ein Plugin eingebunden werden, während es in neueren Versionen direkt in Grails integriert ist. Auch Geb muss nicht mehr als Plugin eingebunden werden sondern wird direkt unterstützt. Webtest ist ein Plugin das zum automatischen Testen von Web-Applikationen implementiert wurde, jedoch nicht mehr weiter entwickelt wird und deshalb nicht mehr verwendet werden kann.&lt;br /&gt;&lt;h4&gt;Unit Tests&lt;/h4&gt;Da schon in der ursprünglichen Version das Test Framework &lt;span style=&quot;font-family: inherit;&quot;&gt;Spock&lt;/span&gt; verwendet wurde, konnten die Unit Tests ohne große Schwierigkeiten migriert werden. Hauptsächlich sind Funktionsaufrufe überflüssig, die durch Annotationen ersetzt wurden. &lt;br /&gt;&lt;h4&gt;Integrationstests&lt;/h4&gt;Es wird empfohlen Controller möglichst als Unit Tests zu realisieren und Services mit Integrationstests zu testen. Sämtliche Versuche, die bestehenden Controller-Integrationstests zu migrieren, blieben erfolglos. Man kann ein Objekt eines Controllers erstellen, jedoch war es nicht möglich, diesen mit allen Abhängigkeiten zu initialisieren. Schwierigkeiten hierbei waren die &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Hibernate-Session&lt;/span&gt; und &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;HTTP-Sessions&lt;/span&gt;, die nicht korrekt funktionierten, so dass bspw. ein Service keine Daten der Datenbank abfragen oder die HTTP- Session bearbeiten&amp;nbsp;konnte.&lt;br /&gt;&lt;div&gt;Wir haben uns dazu entschlossen, den Empfehlungen zu folgen und die Tests zu ändern. Das bedeutet für die Controller neue Unit Tests zu schreiben und für die Services Integrationstests. Ich glaube, dass durch diesen Schritt eine höhere Robustheit gegenüber kommenden neueren Versionen geschaffen wird, da jetzt ausschließlich native Bordmittel von Grails verwendet werden.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Beim Migrieren der Service-Integrationstests macht sich vor allem Grails&#39; Umstellung auf Spring- Boot bemerkbar, das seit der Version 3.0 verwendet wird &lt;a href=&quot;http://docs.grails.org/3.0.0/guide/introduction.html#whatsNew&quot; target=&quot;_blank&quot;&gt;[1]&lt;/a&gt;. Denn ab jetzt wird die &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;setupSpec&lt;/span&gt; Funktion von Spock, der ersten Testklasse, vor dem Start der Applikation ausgeführt, was deren Nutzen stark einschränkt. Beispielsweise ist das Anlegen oder Laden von Daten aus der Datenbank, die zum Testen verwendet werden sollen, nicht mehr möglich, denn sämtliche Hibernate- Funktionen sind nicht verfügbar. Weiter wird der &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;where&lt;/span&gt; Block, der in Spock verwendet werden kann, vor dem Ausführen der &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;setup&lt;/span&gt;- Methode ausgewertet. Somit sollten dort statische Werte verwendet werden, wie &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;String&lt;/span&gt;, &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;int&lt;/span&gt; oder &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;boolean&lt;/span&gt;. Es ist möglich, eine ähnliche Funktionsweise wie die setupSpec Funktion nachzubilden.&lt;br /&gt;Dazu wird eine statische boolean Variable &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;initialized = false&lt;/span&gt; angelegt. In der setup-Funktion wird zusätzlich zu dem Code, der vor jeder Testmethode ausgeführt werden soll, eine if- Condition verwendet um Code zu kapseln, der nur ein einziges mal zu Beginn ausgewertet werden soll. Hierzu wird mit &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;!initialized&lt;/span&gt; überprüft, ob dieser Teil bereits einmal durchlaufen wurde. &amp;nbsp;Am Ende der if- condition wird die Variable &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;initialized&lt;/span&gt; auf &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;true&lt;/span&gt; gesetzt und somit wird dieser Codeteil nicht noch einmal ausgeführt. Das nachfolgende Codebeispiel veranschaulicht das Prinzip.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/fd79bb656253987ec8cbd00d557b3407.js&quot;&gt;&lt;/script&gt; &lt;br /&gt;&lt;h4&gt; Funktionale Tests&lt;/h4&gt;Da in der ursprünglichen Version ebenfalls schon Geb verwendet wurde, können diese Tests ohne größere Anstrengungen migriert werden. Auch hier sind nur vereinzelt kleinere Änderungen durchzuführen. Zum Beispiel müssen alle Testklassen mit der Annotation &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;@Integration&lt;/span&gt; markiert werden, oder der &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;contextPath&lt;/span&gt; muss bei der Url Definition der &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;pages&lt;/span&gt;&amp;nbsp;erweitert werden, da Grails diesen nicht mehr standardmäßig auf den Namen der Applikation setzt &lt;a href=&quot;http://docs.grails.org/3.1.9/guide/testing.html#functionalTesting&quot; target=&quot;_blank&quot;&gt;[2]&lt;/a&gt;.&lt;br /&gt;&lt;div&gt;Das dem Grails Webtest Plugin zu Grunde liegende Projekt&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Canoo Webtest&lt;/span&gt;&amp;nbsp;wird nicht mehr entwickelt und somit ist auch das Grails Plugin nicht mehr aktuell und funktionsfähig. &lt;a href=&quot;https://github.com/canoo/webtest&quot; target=&quot;_blank&quot;&gt;[3]&lt;/a&gt; &lt;a href=&quot;https://grails.org/plugin/webtest&quot; target=&quot;_blank&quot;&gt;[4]&lt;/a&gt; Es gibt somit keine Alternative außer der Neu-Implementierung dieser Tests mit Geb. Ich habe eine - wenn auch sehr umständliche - Möglichkeit gefunden, die alten Webtests gegen die migrierte Applikation auszuführen. Der Vorteil hierbei ist, dass die neue Applikationen während der Migration auf die richtige Funktionalität geprüft werden kann. Somit hat man die Gewissheit, dass sie wie gewünscht funktioniert, auch wenn noch keine umfangreichen neu implementierten Tests vorhanden sind.&lt;/div&gt;&lt;div&gt;Dazu lässt sich in der Konfigurationsdatei &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;webtest.properties&lt;/span&gt;&amp;nbsp;mit den folgenden drei Zeilen einstellen, welcher Server getestet werden soll. Da dadurch die alte Applikation gestartet wird, muss darauf geachtet werden, dass sie mit einem anderen Port wie die Neue startet, da es sonst zu Fehlern kommt.&lt;/div&gt;&lt;script src=&quot;https://gist.github.com/exblog/b98787e9ac90baa816d8762669bbf902.js&quot;&gt;&lt;/script&gt; &lt;br /&gt;&lt;h4&gt;Fazit&lt;/h4&gt;Die Migration der Tests ist in unserem Fall der größte Teil Umstellung auf Grails 3.1.9. Da es in früheren Versionen noch mehrere Test-Möglichkeiten gab und auch Grails sich stark weiter entwickelt hat, ist es leider nicht immer möglich, alte Tests zu migrieren - ein großer Teil der Tests muss komplett neu geschrieben werden.&lt;br /&gt;Ich hoffe ich kann mit dieser Blog-Artikel-Reihe über die Migration einer großen Grails Applikation einigen Interessierten einige Arbeit ersparen, indem sie auf die aufgezeigten Lösungen zurückgreifen.&lt;br /&gt;&lt;h4&gt;Links&lt;/h4&gt;&lt;div&gt;[1]&amp;nbsp;&lt;a href=&quot;http://docs.grails.org/3.0.0/guide/introduction.html#whatsNew&quot; target=&quot;_blank&quot;&gt;Neuerungen seit Grails 3&lt;/a&gt;&lt;/div&gt;&lt;div&gt;[2]&amp;nbsp;&lt;a href=&quot;http://docs.grails.org/3.1.9/guide/testing.html#functionalTesting&quot; target=&quot;_blank&quot;&gt;Funktionale Tests in Grails 3.1.9&lt;/a&gt;&lt;/div&gt;&lt;div&gt;[3]&amp;nbsp;&lt;a href=&quot;https://github.com/canoo/webtest&quot; target=&quot;_blank&quot;&gt;Canoo Webtest Sourcecode auf GitHub&lt;/a&gt;&lt;/div&gt;&lt;div&gt;[4]&amp;nbsp;&lt;a href=&quot;https://grails.org/plugin/webtest&quot; target=&quot;_blank&quot;&gt;Grails Webtest Plugin&lt;/a&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/10/migration-von-grails-137-nach-319.html</link><author>noreply@blogger.com (Sebastian Jäger)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-6958112712635532517</guid><pubDate>Tue, 27 Sep 2016 04:30:00 +0000</pubDate><atom:updated>2016-09-27T06:30:27.580+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Fixtures</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">Groovy</category><category domain="http://www.blogger.com/atom/ns#">Migration</category><title>Migration von Grails 1.3.7 nach 3.1.9 - Erstellen von Testdaten - Teil 2</title><description>Wie schon im &lt;a href=&quot;http://blog.exensio.de/2016/08/migration-grails-137-nach-319.html&quot;&gt;ersten Teil&lt;/a&gt; dieser Reihe beschrieben, stand ich während der Migration einer Applikation der Version 1.3.7 auf 3.1.9 vor dem Problem, dass das Plugin&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Fixtures&lt;/span&gt;, welches zum Erstellen und&amp;nbsp;Einspielen von Testdaten verwendet wurde, nicht mehr weiterentwickelt wird. Hier will ich nun darstellen, welche Anforderungen wir an eine neue Lösung hatten, welche Möglichkeiten sich boten und was schließlich dazu führte, eine eigene Lösung zu implementieren. Abschließend werde ich das Prinzip meiner Lösung näher erläutern und Codebeispiele geben.&lt;br /&gt;&lt;h4&gt;Anforderungen&lt;/h4&gt;Eine besondere Funktionalität des &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Fixtures-&lt;/span&gt;Plugins ist die Möglichkeit, den einzelnen Testdaten-Instanzen einen eindeutigen Namen zu geben und diese in Test Cases zu referenzieren. Da Testdaten vorhanden waren, die natürlich wieder verwendet werden sollten, ist es zusätzlich von Vorteil, wenn die Daten möglichst ähnlich dargestellt werden. Damit ist es möglich mit Hilfe der Suchen und Ersetzen Funktion der IDE wiederkehrende Muster zu finden und diese an das neue Format anzupassen. Eine weitere Anforderung war die Robustheit gegenüber Änderungen. Zum Beispiel sollte es keine großen Anpassung der Fixtures nach sich ziehen, wenn einem Attribut der Constraint &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;bindable:false&lt;/span&gt; hinzugefügt wird. Diese Änderung würde bei der Erstellung einer Instanz erzwingen, dass dieses Attribut nicht innerhalb einer Map übergeben wird, sondern einzeln gesetzt werden muss.&lt;br /&gt;&lt;h4&gt;Alternativen&lt;/h4&gt;Das Grails-Plugin &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Build-Test-Data&lt;/span&gt; wurde für die Erstellung von Testdaten implementiert. Es analysiert automatisch Constraints einer Domainklasse und erstellt valide Instanzen. Möglich wäre es, die schon vorhandenen Daten zu verwenden und daraus Instanzen zu erstellen - jedoch nicht, ohne eine eigene Erweiterung die Daten zu speichern und wieder zu verwenden. &lt;br /&gt;&lt;br /&gt;Da ohne eine eigene Implementierung keine Möglichkeit gegeben war, kam die Idee auf, die einzelnen Instanzen manuell per Konstruktor-Aufruf zu erstellen. Hierzu müsste jedoch die Syntax der Test-Daten stark geändert werden. Auch könnte es zu Problemen führen, wenn es Änderungen an den Constraints gibt. Wird, wie oben beschrieben, zu einem Attribut der Constraint &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;bindable:false&lt;/span&gt; hinzugefügt, müssten alle Instanzen der Domainklasse angepasst werden.&lt;br /&gt;&lt;br /&gt;Da keine der Lösungen zufriedenstellend verwendet werden konnte, habe ich mich dazu entschlossen, eine eigene Lösung zu implementieren, um Test-Daten zu erstellen. Mit der eigenen Implementierung ist es wieder möglich, die Testdaten in Test Cases zu referenzieren.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style=&quot;font-kerning: none;&quot;&gt;Implementierung der eigenen Logik&lt;/span&gt;&lt;/h3&gt;Es soll die Möglichkeit geboten werden, Daten zu definieren, die automatisch gespeichert werden. Für komplexere Beziehungen soll es möglich sein, separate Daten zu beschreiben, die zunächst erstellt und nicht explizit gespeichert werden sollen, da diese von anderen Daten abhängen und dort ein kaskadierendes Speichern notwendig ist. Abschließend kann eine Funktion implementiert sein,  in der beliebige Operationen für Modifikationen ausführbar sind.&lt;br /&gt;&lt;h4&gt;Data-Klasse&lt;/h4&gt;Da alle Klassen einem bestimmten Aufbau folgen müssen, um eine korrekte Funktionsweise zu gewährleisten, habe ich eine abstrakte Oberklasse implementiert, von der geerbt wird. Diese besitzt folgende leere Funktionen, die dazu verwendet werden um zum einen die Daten auszulesen und zum andern ggf. spezielle Beziehungen herzustellen:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;getPreData&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;:&lt;/span&gt;&amp;nbsp;Diese Methode muss überschrieben werden und&amp;nbsp;&lt;/span&gt;eine Map mit Daten zurückgeben.&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;getData:&lt;/span&gt;&amp;nbsp;Diese Methode muss ebenso&amp;nbsp;eine Map der Daten zurück geben.&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;post:&lt;/span&gt;&amp;nbsp;Diese Methode kann überschrieben werden. &lt;/li&gt;&lt;/ul&gt;Beide &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;get&lt;/span&gt;&amp;nbsp;Methoden müssen eine Map zurückgeben, in der die Daten enthalten sind. Als Schlüssel wird jeweils der Name verwendet, unter dem die Testdaten Instanz referenziert werden kann, und als Wert eine Map, die die Attribute und deren Werte enthält. Zusätzlich muss der Schlüssel &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;domainName&lt;/span&gt; enthalten sein, der die Domainklasse definiert. Da der Aufbau der neuen Daten ähnlich dem der Fixtures ist lassen sich diese schnell passend migrieren. Wie nachfolgend zu sehen müssen vor allem die Klassen sowie Methoden-Deklarationen erweitert werden.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/9414aa2b90073a79a3cdf4a56387411a.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/f4467f017b34e7c92eabf1624fb1365b.js&quot;&gt;&lt;/script&gt; Sollen Beziehungen zwischen Instanzen hergestellt werden, realisiert man diese mit Closures. Dabei wird, wie oben zu sehen eine Referenz auf die gewünschte Instanz zurückgeben. Da die Closure erst beim Erstellen der Daten ausgewertet wird, muss die Reihenfolge beachtet werden, in der man Daten erstellt. Bei Beziehungen, die mit &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;belongsTo&lt;/span&gt;&amp;nbsp;markiert sind, greift ein kaskadierendes Speichern, das die abhängige Instanz mitspeichert. Hierfür wurde die Methode &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;getPre&lt;/span&gt;&amp;nbsp;geschaffen, die es ermöglicht, Daten zu erstellen, die nicht explizit gespeichert werden, aber nach dem Erstellen der Hauptdaten  auf Persistenz überprüft werden. In der Methode &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;post&lt;/span&gt;&amp;nbsp;kann man beliebige Operationen ausführen. In der migrierten Applikation sind in wenigen Domainklassen Hilfsfunktionen implementiert um Beziehungen zwischen Instanzen herzustellen. Dabei wird nicht nur die Referenz gespeichert sondern auch Attributwerte an verschiedensten Stellen in der Datenbank geändert. Es bietet sich an dies, wie in dem nachfolgenden Codeausschnitt zu sehen, in der &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;post&lt;/span&gt; Methode zu verwenden.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/cabe5ece614924bf4f04a68716ae4d64.js&quot;&gt;&lt;/script&gt; &lt;br /&gt;&lt;h4&gt;DataLoader-Klasse&lt;/h4&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;DataLoader&lt;/span&gt;&amp;nbsp;ist eine abstrakte Klasse, die die Map &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;data&lt;/span&gt;&amp;nbsp;enthält, in der alle erstellten Instanzen gespeichert werden. Mit der Funktion &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;loadData&lt;/span&gt;Class&lt;/span&gt; ist es möglich, alle Daten, die in der übergebenen Klasse definiert sind, zu erstellen und speichern. Tritt ein Fehler in einer der Daten Instanzen auf, wird eine &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;Exception&lt;/span&gt; geworfen. Zuerst wird ein Objekt der übergebenen Klasse erstellt und die &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;preData&lt;/span&gt;&amp;nbsp;sowie &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;data&lt;/span&gt;&amp;nbsp;ausgelesen. Sind &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;preData&lt;/span&gt;&amp;nbsp;vorhanden, werden diese vor den Hauptdaten erstellt, anschließend gespeichert und die &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;preData&lt;/span&gt;&amp;nbsp;auf Persistenz geprüft. Zum Schluss wird die Funktion &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;post&lt;/span&gt;&amp;nbsp;ausgeführt. Im folgenden Sequenzdiagramm ist der Ablauf bildlich darstellt:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-4ELZ4Bq8c0w/V8aGHNQ1vsI/AAAAAAAAACg/mpkOxuVzG3AvRB5yngC-0H3rkFqmmBeDgCLcB/s1600/Unbenannt.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://4.bp.blogspot.com/-4ELZ4Bq8c0w/V8aGHNQ1vsI/AAAAAAAAACg/mpkOxuVzG3AvRB5yngC-0H3rkFqmmBeDgCLcB/s320/Unbenannt.PNG&quot; width=&quot;244&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Eine Exception wird erzeugt, wenn&lt;br /&gt;&lt;ol&gt;&lt;li&gt;ein Name zur Referenzierung der Daten doppelt verwendet wird&lt;/li&gt;&lt;li&gt;keine Beziehung (&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;null&lt;/span&gt;) hergestellt werden kann&lt;/li&gt;&lt;li&gt;das Speichern einer Instanz nicht möglich ist&lt;/li&gt;&lt;li&gt;ein &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;preData&lt;/span&gt;-Aufruf nicht gespeichert wurde&lt;/li&gt;&lt;/ol&gt;Der folgende Code- Block enthält einen ersten Entwurf der Logik, wie das Erstellen der Daten realisiert werden kann.&lt;/div&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/8f438a24d7ffcfc82d339c33ce396bbe.js&quot;&gt;&lt;/script&gt; &lt;br /&gt;&lt;h4&gt;Fazit&lt;/h4&gt;Diesd Implementierung funktioniert in dem migrierten Projekt sehr gut, wenngleich noch einige Verbesserungen möglich sind. Zum einen könnte die Performance verbessert werden und zum anderen könnten die Implementierung dahingehend verbessert werden, dass eine Fehlverwendung vermieden wird.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;</description><link>http://blog.exensio.de/2016/09/migration-von-grails-137-nach-319_27.html</link><author>noreply@blogger.com (Sebastian Jäger)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://4.bp.blogspot.com/-4ELZ4Bq8c0w/V8aGHNQ1vsI/AAAAAAAAACg/mpkOxuVzG3AvRB5yngC-0H3rkFqmmBeDgCLcB/s72-c/Unbenannt.PNG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-2029376133351009772</guid><pubDate>Fri, 23 Sep 2016 07:30:00 +0000</pubDate><atom:updated>2016-09-23T09:30:17.493+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">OS X</category><category domain="http://www.blogger.com/atom/ns#">Subversion</category><title>SVN und Mac OS X und Umlaute</title><description>&lt;div&gt;Hat man unter Mac OS X schon einmal ein Subversion Repository ausgecheckt, das Dateien mit Umlauten im Namen enthält kennt man wahrscheinlich das Problem: Es werden scheinbar ohne Grund Dateien als geändert und als unversioniert angezeigt. Es gibt auch erst einmal keine offensichtliche Lösung für das Problem. &lt;br/&gt;&lt;/div&gt;    &lt;h2&gt;        Das Problem&lt;/h2&gt;    &lt;div&gt;        Mac OS X speichert Umlaute in Dateinamen als sogenannte &lt;b&gt;&lt;a             href=&quot;https://en.wikipedia.org/wiki/Precomposed_character&quot; target=&quot;_blank&quot;&gt;precomposed characters&lt;/a&gt;&lt;/b&gt;        (auf Deutsch etwa: &quot;zusammengesetzte Buchstaben&quot;). Das bedeutet, dass ein &quot;ü&quot; nicht als einzelner Buchstabe         gespeichert wird, sondern als Zusammensetzung aus einem &quot;u&quot; und dem Zeichen für zwei Punkte über dem Buchstabe         (&quot;¨&quot;). Das ist an sich völlig in Ordnung und so vorgesehen. Allerdings gibt es Programme (wie Subversion), die         beim Vergleich von Dateinamen diesen Umstand nicht berücksichtigen. Für Subversion sind das Zeichen         &quot;ü&quot; und das zusammengesetzte Zeichen &quot;ü&quot; aus zwei Zeichen unterschiedliche Buchstaben.&lt;br/&gt;        &lt;br/&gt;        Fügt man mit Windows eine Datei mit Umlauten in ein Subversion Repository hinzu und checked dieses auf         OS X aus, sieht das Ergebnis von &lt;span             style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;svn status&lt;/b&gt;&lt;/span&gt; so         aus:         &lt;script src=&quot;https://gist.github.com/deflomu/f6b3ff124cbec01559f306ac616d8bdc.js&quot;&gt;&lt;/script&gt;    Man kann die Dateien weder commiten noch reverten. Der Zustand lässt sich nicht ändern. Das Problem ist im     Subversion Bugtracker     seit 2005 &lt;a href=&quot;https://issues.apache.org/jira/browse/SVN-2464&quot; target=&quot;_blank&quot;&gt;gemeldet&lt;/a&gt;. Es existiert auch     &lt;a href=&quot;http://wiki.apache.org/subversion/NonNormalizingUnicodeCompositionAwareness&quot; target=&quot;_blank&quot;&gt;eine Seite&lt;/a&gt;    im Subversion-Wiki zu diesem Thema. Nur leider ist bisher noch keine Lösung im offizielle Subversion-Code gelandet     (Zum Zeitpunkt der Erstellung diese Artikels ist 1.9.4 die aktuelle Version von Subversion).&lt;br/&gt;     &lt;/div&gt;    &lt;h2&gt;        Die Lösung&lt;/h2&gt;&lt;div&gt;    An der Fehlermeldung im Subversion-Bugtracker ist ein Patch angehängt, der das Problem behebt. Mit dem Paketmanager     &lt;a href=&quot;http://brew.sh/&quot; target=&quot;_blank&quot;&gt;Homebrew&lt;/a&gt; kann dieser relativ einfach in Subversion eingebaut     werden. Ein Nebeneffekt ist, dass man ab dann eine relativ aktuelle Version von Subversion verwendet.&lt;br/&gt;    &lt;br/&gt;    Um den Patch einspielen zu können muss man natürlich erst einmal Homebrew installieren. Wie das geht steht auf der     oben verlinkten Seite. Mit den folgenden Schritten kann man Subversion patchen: &lt;/div&gt;&lt;div&gt;    &lt;ol&gt;        &lt;li&gt;Im Terminal mit &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;brew edit subversion&lt;/b&gt;&lt;/span&gt;            die Subversion-Formel zum anpassen öffnen         &lt;/li&gt;        &lt;li&gt;Unterhalb von &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;patch :DATA&lt;/b&gt;&lt;/span&gt;            muss die URL und der Hash des Patches eingetragen werden. Standardmäßig wird unter OS X der Editor &lt;a                     href=&quot;http://www.vim.org/&quot; target=&quot;_blank&quot;&gt;VIM&lt;/a&gt; verwendet. Mit der Taste &lt;span                     style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;i&lt;/b&gt;&lt;/span&gt; kann             man in den Eingabemodus wechseln. Die Datei sieht an dieser Stelle dann so aus:             &lt;script src=&quot;https://gist.github.com/deflomu/220df43e245665cacec76c946de271b4.js&quot;&gt;&lt;/script&gt;        &lt;/li&gt;        &lt;li&gt;Die Datei speichern und schließen. In VIM drückt man zuerst &lt;span                 style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;ESC&lt;/b&gt;&lt;/span&gt; um den             Eingabemodus zu verlassen und gibt dann &lt;span                     style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;:x&lt;/b&gt;&lt;/span&gt; ein             und bestätigt mit &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;Enter&lt;/b&gt;&lt;/span&gt;        &lt;/li&gt;        &lt;li&gt;Speichern und Subversion bauen mit &lt;span                 style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;brew install --build-from-source subversion&lt;/b&gt;&lt;/span&gt;        &lt;/li&gt;        &lt;li&gt;Terminal schließen und neu öffnen und mit &lt;span                 style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;svn --version&lt;/b&gt;&lt;/span&gt;            überprüfen ob Version 1.9.4 oder neuer läuft         &lt;/li&gt;    &lt;/ol&gt;    &lt;h3&gt;        Update von Subversion&lt;/h3&gt;&lt;/div&gt;&lt;div&gt;    Mit Homebrew kann man im Terminal mit dem Befehl &lt;span         style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;brew update&lt;/b&gt;&lt;/span&gt; und     dann &lt;span         style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;brew upgrade&lt;/b&gt;&lt;/span&gt; alle     installierten Programme aktualisieren.&lt;br/&gt;        &lt;br/&gt;    Bei &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;brew update&lt;/b&gt;&lt;/span&gt;    öffnet sich bedingt durch die obige Anpassung manchmal der Standardeditor mit einer Merge-Nachtricht. Es muss dann     einfach gespeichert und der Editor beendet werden, damit Homebrew das Update beendet. Es handelt sich hier um einen     normalen Git-Merge.&lt;br/&gt;        &lt;br/&gt;    Wird eine neue Version von Subversion installiert (z.B. durch &lt;span         style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;brew upgrade&lt;/b&gt;&lt;/span&gt;),     wird automatisch die vorkompilierte Version verwendet. Diese muss dann durch eine selbstkompilierte Version ersetzt     werden: &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;brew reinstall --build-from-source subversion&lt;/b&gt;&lt;/span&gt;.     So wird automatisch wieder der Patch eingespielt.&lt;br/&gt;&lt;br/&gt;    Nun kann man ohne Probleme mit Subversion-Repsitories arbeiten, die Datei mit Umlauten enthalten.&lt;br/&gt;&lt;/div&gt;&lt;h3&gt;    IntelliJ&lt;/h3&gt;&lt;div&gt;    IntelliJ kann glücklicherweise so eingestellt werden, dass die neue gepatche Version von Subversion     verwendet wird. Dazu muss man in den Einstellungen auf die Homebrew-Version von Subversion     wechseln (&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;b&gt;/usr/local/bin/svn&lt;/b&gt;&lt;/span&gt;):&lt;br/&gt;    &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;            &lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;a                     href=&quot;https://3.bp.blogspot.com/-V7fWSiRss54/V9_ZcZBgNeI/AAAAAAAAARU/czqGUmXKukkOYWhBfy6K67_ZvWAFB5D-QCLcB/s1600/Subversion%2Bin%2BIntelliJ.png&quot;                     imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;170&quot;                                                                                       src=&quot;https://3.bp.blogspot.com/-V7fWSiRss54/V9_ZcZBgNeI/AAAAAAAAARU/czqGUmXKukkOYWhBfy6K67_ZvWAFB5D-QCLcB/s400/Subversion%2Bin%2BIntelliJ.png&quot;                                                                                       width=&quot;400&quot;/&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both;&quot;&gt;    Jetzt sollte auch IntelliJ mit Umlauten in Repositories umgehen können. &lt;/div&gt;&lt;h2&gt;    Subversion GUI Tools&lt;/h2&gt;&lt;div&gt;    Bei fast allen Subversion GUI Tools (z.B. &lt;a href=&quot;http://versionsapp.com/&quot;                                                  target=&quot;_blank&quot;&gt;Versions&lt;/a&gt;, &lt;a         href=&quot;http://www.zennaware.com/cornerstone/index.php&quot;         target=&quot;_blank&quot;&gt;Cornerstone&lt;/a&gt; oder &lt;a href=&quot;http://www.smartsvn.com/&quot; style=&quot;font-family: inherit;&quot;                                                 target=&quot;_blank&quot;&gt;SmartSVN&lt;/a&gt;) ist es leider so, dass diese eingebaute Subversion-Clients verwenden. Diese sind in der Regel leider nicht gepatcht (siehe z.B. den &lt;a         href=&quot;http://www.zennaware.com/cornerstone/support.php#accents-and-diacritics&quot; target=&quot;_blank&quot;&gt;FAQ von Cornerstone&lt;/a&gt;) und so zeigen diese Programme auch immer Dateien als geändert an, obwohl sich dort nichts geändert hat. &lt;/div&gt;</description><link>http://blog.exensio.de/2016/09/svn-und-mac-os-x-und-umlaute.html</link><author>noreply@blogger.com (Florian Mutter)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-V7fWSiRss54/V9_ZcZBgNeI/AAAAAAAAARU/czqGUmXKukkOYWhBfy6K67_ZvWAFB5D-QCLcB/s72-c/Subversion%2Bin%2BIntelliJ.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-5597955995855683656</guid><pubDate>Tue, 20 Sep 2016 04:00:00 +0000</pubDate><atom:updated>2016-09-20T10:32:35.412+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">Groovy Migration</category><title>Migration von Grails 1.3.7 nach 3.1.9 - Probleme und deren Behebung - Teil 1</title><description>In den letzten Monaten hat es zu meinen Hauptaufgaben gezählt, eine große Business-Applikation von Grails 1.3.7 auf die Version 3 zu migrieren. In diesem Blog Post will ich auf allgemeine Schwierigkeiten und Lösungen eingehen, die in unserem Fall aufgetreten sind.&lt;br /&gt;In den folgenden Posts werde ich zum einen auf die selbst entwickelte Lösung zum Erstellen von Testdaten eingehen und zum anderen die Probleme bei der Migration der einzelnen Testarten erläutern.&lt;br /&gt;&lt;br /&gt;Für die Migration wurde in folgender Reihenfolge vorgegangen:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Neues Projekt mit der gewünschten Grails Version erstellen und konfigurieren&lt;/li&gt;&lt;li&gt;Einbinden aller Plugins in der neusten verfügbaren Version, die verwendet werden sollen&lt;/li&gt;&lt;li&gt;Migrieren der Domain-/ Java-/ Groovy-Klassen, sowie TagLibs und i18n- Ressourcen&lt;/li&gt;&lt;li&gt;Einspielen von Testdaten&lt;/li&gt;&lt;li&gt;Migrieren der Services&lt;/li&gt;&lt;li&gt;Migrieren der Controller&lt;/li&gt;&lt;li&gt;Migrieren der Views und alle zugehörigen Ressourcen wie JavaScript und CSS Dateien&lt;/li&gt;&lt;li&gt;Migrieren der Testdateien&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Nach jedem Schritt wurden automatisierte Tests, die die schon migrierten Teile der Applikation testen, ebenfalls migriert, um möglichst früh Fehler zu erkennen. Wie oben beschrieben werde ich im dritten Teil dieser Serie genauer darauf eingehen.&lt;/div&gt;&lt;div&gt;&lt;h4&gt;Hibernate naming_strategy&lt;/h4&gt;&lt;/div&gt;Nachdem die Domainklassen sowie sämtliche Hilfsklassen migriert waren, ist durch das Starten mit einer bestehenden Datenbank, aufgefallen, dass das automatisch erstellte Datenbankschema nach dem Starten der Applikation sich von dem Ursprünglichen hinsichtlich der Tabellennamen unterscheidet. Das Anpassen der &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;hibernate.naming_strategy&lt;/span&gt; hat für mich das Problem gelöst. In der&amp;nbsp;Hibernate-Dokumentation für das Interface&amp;nbsp;&lt;a href=&quot;https://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/cfg/NamingStrategy.html&quot; target=&quot;_blank&quot;&gt;NamingStrategy&lt;/a&gt;&amp;nbsp;können implementierte Strategien gefunden werden, die Hibernate von Haus aus mit bringt. Das Definieren eigener Strategien ist jedoch ebenso möglich. &lt;a href=&quot;http://docs.grails.org/3.1.9/guide/single.html#customNamingStrategy&quot; target=&quot;_blank&quot;&gt;[1]&lt;/a&gt;&lt;br /&gt;&lt;h4&gt;Actions von Controllern&lt;/h4&gt;Treten bei Controllern Fehler auf, dass Annotationen nicht erlaubt seien, liegt das daran, dass Actions seit Grails 2 als Methoden implementiert werden sollen. Bei Applikationen der Version 1.x war es üblich diese als Closures zu programmieren. &lt;a href=&quot;http://docs.grails.org/2.0.0/guide/introduction.html#webFeatures&quot; target=&quot;_blank&quot;&gt;[2]&lt;/a&gt;&lt;br /&gt;&lt;h4&gt;Transaktionen in Services&lt;/h4&gt;Transaktionen ist der wesentliche Punkt, der sich für Services verändert hat. Bis zur Version 2.3 von Grails wurden die Spring Transaktionen verwendet, die durch das statische Attribut &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;transactional&lt;/span&gt; aktiviert oder deaktiviert wurden. Empfohlen wird, diese komplett durch die seither neuen, Grails Transaktionen zu ersetzen, die über Annotationen verwendet werden. Alle Services ohne jegliche Annotationen benutzen standardmäßig Transaktionen.&lt;br /&gt;&lt;div&gt;Vorsicht ist geboten, wenn der Modus einzelner Methoden vom default Wert &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;read-write&lt;/span&gt;&amp;nbsp;&lt;/span&gt;beispielsweise zu &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;readOnly&lt;/span&gt;&amp;nbsp;geändert werden soll, denn dann muss die Service Klasse ebenfalls als &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;@Transactional&lt;/span&gt;&amp;nbsp;gekennzeichnet werden. Sind nur einzelne Methoden und nicht die Klasse gekennzeichnet, werden nur für diese Methoden Transaktionen verwendet, alle anderen jedoch nicht. &lt;a href=&quot;http://docs.grails.org/3.1.9/guide/services.html#declarativeTransactions&quot; target=&quot;_blank&quot;&gt;[3]&lt;/a&gt;&lt;/div&gt;&lt;h4&gt;Resource- Plugin durch Asset- Pipeline ersetzen&lt;/h4&gt;Seit der Version 2.0 von Grails wurde das bisher verwendete &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;resource&lt;/span&gt;&amp;nbsp;Plugin durch &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;asset-pipeline&lt;/span&gt;&amp;nbsp;ersetzt. Dadurch muss das Einbinden der JavaScript und CSS Dateien angepasst werden. In der Datei &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;UIResources.groovy&lt;/span&gt;&amp;nbsp;wurden bisher sogenannte Module definiert. Mit dem Tag &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;lt;r:require modules=“common”/&amp;gt;&lt;/span&gt;&amp;nbsp;wurden diese Dateien in dem entsprechenden View eingebettet. Um ein ähnliches Verhalten nachzubilden, habe ich für jedes Modul eine neue JavaScript und eine CSS Datei erstellt, die die zugehörigen Dateien definiert. In den folgenden Ausschnitten ist dies beispielhaft dargestellt.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/a865c546865f92091152200389e8e8bb.js&quot;&gt;&lt;/script&gt;&lt;script src=&quot;https://gist.github.com/exblog/c185388cfff1016b7da3172535c72572.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;Die verwendeten Pfade der Ressourcen sind relativ, ausgehend von der Dateistruktur&amp;nbsp;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;grails-app/assets/javascript/&lt;/span&gt;&amp;nbsp;oder &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;grails-app/assets/stylesheets/&lt;/span&gt;. Wichtig ist hierbei auf die Reihenfolge zu achten, denn ansonsten könnte es vorkommen, dass JavaScript eine Funktion verwenden will, die noch nicht definiert wurde, was zu Fehlern führt. Um die neu erstellten &quot;Module&quot; zu nutzen, werden nun zwei Aufrufe benötigt: &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;lt;asset:javascript src=“commonModule.js”/&amp;gt;&lt;/span&gt;&amp;nbsp;und &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&amp;lt;asset:stylesheet src=“commonModule.css”/&amp;gt;&lt;/span&gt;.&lt;br /&gt;&lt;h4&gt;Deploying&lt;/h4&gt;Abschließend gehe ich noch auf ein Problem ein, das schwer zu entdecken ist. Ein, mit Hilfe des Gradle Task &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;bootRepackag&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;erstelltes&lt;/span&gt;&amp;nbsp;Standalone War-File, hat zufällig, entweder unter Windows oder, was öfter auftrat, unter Linux, anstelle der erwarteten Login Seite eine Liste aller Controller angezeigt. Verursacht wurde dieses Problem dadurch, dass in unserer Applikation das URL- Mapping, speziell der Root- Endpunkt (&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;“/“&lt;/span&gt;), angepasst wurde. Dadurch kann es auftreten, dass ein Plugin, das auch eine &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;UrlMapping.groovy&lt;/span&gt; Datei besitzt, die eigene Änderung überschreibt. Hier war noch der Standardwert enthalten, der auf eine fehlerhafte View verwiesen hat. Mit einem Workaround lässt sich dies umgehen. Dazu wird ein Interceptor implementiert, der aktiv werden soll, wenn eine Anfrage an &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;“/“ &lt;/span&gt;gesendet wird und dann manuell auf den gewollten Controller und dessen action umleitet. Hier ist ein Beispiel, das eine mögliche Implementierung des Interceptors darstellt.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/673492f66c59458dcedb1e8a0f11ce44.js&quot;&gt;&lt;/script&gt; &lt;br /&gt;&lt;div&gt;&lt;h4&gt;Fazit&lt;/h4&gt;&lt;/div&gt;&lt;div&gt;Es wurden einige Probleme und deren Möglichkeiten zur Behebung bei einer Grails-Migration vorgestellt. Eine Migration von älteren Versionen ist also nicht unmöglich, aber auch nicht an allen Stellen einfach. Oft sind es nur Kleinigkeiten, die sich geändert haben und meist durch eine Anpassung der Konfigurationen behoben werden können. Problematisch ist eher das Finden der Ursache zu den auftretenden Fehlern.&lt;br /&gt;&lt;h4&gt;Links&lt;/h4&gt;[1]&amp;nbsp;&lt;a href=&quot;http://docs.grails.org/3.1.9/guide/single.html#customNamingStrategy&quot; target=&quot;_blank&quot;&gt;Hibernate Naming Strategy ändern - Grails 3.1.9 Guide&lt;/a&gt;&lt;br /&gt;[2]&amp;nbsp;&lt;a href=&quot;http://docs.grails.org/2.0.0/guide/introduction.html#webFeatures&quot; target=&quot;_blank&quot;&gt;Änderungen seit Grails 2.0&lt;/a&gt;&lt;br /&gt;[3]&amp;nbsp;&lt;a href=&quot;http://docs.grails.org/3.1.9/guide/services.html#declarativeTransactions&quot; target=&quot;_blank&quot;&gt;Transaktionen in Grails 3.1.9&lt;/a&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/09/migration-von-grails-137-nach-319.html</link><author>noreply@blogger.com (Sebastian Jäger)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3244242716806449655</guid><pubDate>Tue, 13 Sep 2016 12:12:00 +0000</pubDate><atom:updated>2016-09-13T14:12:53.788+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">CKEditor</category><category domain="http://www.blogger.com/atom/ns#">JavaScript</category><category domain="http://www.blogger.com/atom/ns#">web</category><title>CKEditor Customizing</title><description>CKEditor ist ein im Web weit verbreiteter WYSIWYG-Editor (&quot;what you see is what you get&quot;), welcher sich sehr flexibel an die Bedürfnisse eines Projekts anpassen lässt. In diesem Blogpost möchte ich kurz einige Anpassungen beleuchten, welche vielleicht auch Ihnen bei Ihren Projekten weiterhelfen können.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Lange Texte im Editor&lt;/h3&gt;&lt;div&gt;In einem unserer Projekte ist die Anforderung, dass über den CKEditor relativ lange Texte eingegeben werden müssen. Dies ist an sich kein Problem, allerdings erhält man damit unter umständen zwei Scrollbars - eine im Editor und eine für die gesamte Seite. Gerade im Zeitalter von Touchscreens eine unschöne Sache.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-wl5KfK3CSPI/V9fPfuJIgoI/AAAAAAAAAHg/7EuIRndB23wjYvDl5OT0hYgUgPUBT_ndACLcB/s1600/Bildschirmfoto%2B2016-09-13%2Bum%2B11.38.51.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://4.bp.blogspot.com/-wl5KfK3CSPI/V9fPfuJIgoI/AAAAAAAAAHg/7EuIRndB23wjYvDl5OT0hYgUgPUBT_ndACLcB/s400/Bildschirmfoto%2B2016-09-13%2Bum%2B11.38.51.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Abhilfe schafft hier das Plugin &lt;a href=&quot;http://ckeditor.com/addon/autogrow&quot; target=&quot;_blank&quot;&gt;Autogrow&lt;/a&gt;, welches den Editor mit dem Inhalt wachsen lässt. Nach dem herunterladen und hinzufügen muss es nur noch in der config-Datei aktiviert werden. Standardmäßig reagiert das Plugin erst, sobald der Editor im Fokus ist. Will man jedoch, dass dies direkt bei Seitenaufbau passiert, zum Beispiel weil der Editor mit Inhalt gefüllt wird, kann dies ebenfalls in der Config angepasst werden.&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src=&quot;https://gist.github.com/exblog/fccc67c83a105a47721e729bbb85165b.js&quot;&gt;&lt;/script&gt; &lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-ZuYxDhLDA-w/V9fSYDOozAI/AAAAAAAAAH0/TWvYe3Y5OHQQa8tdX3Xjcxs4CkXPTLNfQCEw/s1600/Bildschirmfoto%2B2016-09-13%2Bum%2B11.39.54.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;327&quot; src=&quot;https://4.bp.blogspot.com/-ZuYxDhLDA-w/V9fSYDOozAI/AAAAAAAAAH0/TWvYe3Y5OHQQa8tdX3Xjcxs4CkXPTLNfQCEw/s400/Bildschirmfoto%2B2016-09-13%2Bum%2B11.39.54.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Nun wächst der Editor wie gewollt mit dem Inhalt mit, jedoch verliert sich die Toolbar am oberen Rand. Soll etwas editiert werden muss erst wieder ganz nach oben gescrollt werden. Unschön!&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://2.bp.blogspot.com/-Ysw6CwJ8T5Q/V9fSX6QVmbI/AAAAAAAAAHw/oPyRWWccoUEw5cTYEovJu1QDBpEvBjxDQCLcB/s1600/Bildschirmfoto%2B2016-09-13%2Bum%2B11.40.12.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;325&quot; src=&quot;https://2.bp.blogspot.com/-Ysw6CwJ8T5Q/V9fSX6QVmbI/AAAAAAAAAHw/oPyRWWccoUEw5cTYEovJu1QDBpEvBjxDQCLcB/s400/Bildschirmfoto%2B2016-09-13%2Bum%2B11.40.12.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Hierfür haben wir zwei Lösungsansätze gefunden: entweder die Toolbar mitscrollen lassen oder eine Toolbar bei Bedarf einblenden, sobald der Nutzer einen Bereich markiert.&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Für die erste Variante existiert das Plugin &lt;a href=&quot;http://ckeditor.com/addon/fixed&quot; target=&quot;_blank&quot;&gt;Fixed&lt;/a&gt;, welches jedoch ohne Anpassungen in unserem Fall nicht korrekt funktioniert (beim Scrollen verschob sich die Position der Toolbar). Nichts, was sich nicht richten ließe, aber in unseren Projekten wollen wir externe Plugins möglichst nicht verändern, um spätere Updates problemlos durchführen zu können.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Umgesetzt haben wir die zweite Option mittels des Plugins &lt;a href=&quot;http://ckeditor.com/addon/floating-tools&quot; target=&quot;_blank&quot;&gt;Floating-Tools&lt;/a&gt;. Es hat eine Abhängigkeit zu &lt;a href=&quot;http://ckeditor.com/addon/toolbar&quot; target=&quot;_blank&quot;&gt;Editor Toolbar&lt;/a&gt;, diesen Plugin ist aber standardmäßig in alles Presets des &lt;a href=&quot;http://ckeditor.com/builder&quot; target=&quot;_blank&quot;&gt;Builders&lt;/a&gt; enthalten, sodass &amp;nbsp;keine weiteren Schritte nötig sind. Die Toolbar von Floating-Tools kann unabhängig von der Haupttoolbar konfiguriert werden, übernimmt aber deren Aussehen.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src=&quot;https://gist.github.com/exblog/3d057c50ed696fa0fd03e16c459fbf57.js&quot;&gt;&lt;/script&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://1.bp.blogspot.com/-60QjcGsObXI/V9fVSlk41yI/AAAAAAAAAIA/BA6qCVTsSnwsDpXyRxxb-aIu82aZWwgigCLcB/s1600/Bildschirmfoto%2B2016-09-13%2Bum%2B11.41.00.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;305&quot; src=&quot;https://1.bp.blogspot.com/-60QjcGsObXI/V9fVSlk41yI/AAAAAAAAAIA/BA6qCVTsSnwsDpXyRxxb-aIu82aZWwgigCLcB/s400/Bildschirmfoto%2B2016-09-13%2Bum%2B11.41.00.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Soll das Plugin nicht in alles Instanzen des CKEditors aktiv sein, so kann man es auch lokal aktivieren. Hier müssen alle zusätzlichen Plugins angegeben sein, da dieser Parameter extraPlugins aus der config-Datei überschreibt.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src=&quot;https://gist.github.com/exblog/22bb755b5c4054aecef212d511f7a069.js&quot;&gt;&lt;/script&gt; &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;Nun lässt sich vernünftig mit langen Texten arbeiten.&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: left;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Paste from Word&lt;/h3&gt;&lt;div&gt;Eine weitere Anforderung ist die Möglichkeit Texte aus Word in den Editor zu kopieren. Um ungewünschte Formatierung zu vermeiden gibt es hierfür das &lt;a href=&quot;http://ckeditor.com/addon/pastefromword&quot; target=&quot;_blank&quot;&gt;Paste From Word&lt;/a&gt; Plugin, welches an sich gute Arbeit leistet. Was das Plugin allerdings nicht bewerkstelligt, ist leere Paragraphen und alleinstehende Leerzeichen zu unterdrücken. Außerdem werden Einrückungen über inline-Style mit margin-left bewerkstelligt. Dies tut CKEditor selbst auch, aber aus Word eingefügte Einrückung verwendet cm und der Editor erwartet px, sodass solche Einzüge über die graphische Oberfläche nicht mehr editiert werden können.&amp;nbsp;&lt;/div&gt;&lt;div&gt;Um dem entgegenzuwirken haben wir in der Config für paste-Events Regeln definiert, welche eben jene Zeichenketten erkennen und ersetzen. In unserem Fall löschen wir neben leeren Paragraphen und Leerzeichen alle inline-Styles - genauer genommen finden wir diese Fälle und ersetzen sie mit einer leeren Zeichenkette.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;script src=&quot;https://gist.github.com/exblog/1d75e8f55956cabf28b14cee86cd2b9e.js&quot;&gt;&lt;/script&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hier können natürlich auch weitere Regeln eingefügt oder der &lt;a href=&quot;https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/RegExp&quot; target=&quot;_blank&quot;&gt;reguläre Ausdruck&lt;/a&gt; entsprechen Ihrer Anforderung angepasst werden.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Viel Spaß beim Customizing!&lt;/div&gt;</description><link>http://blog.exensio.de/2016/09/ckeditor-customizing.html</link><author>noreply@blogger.com (Andreas Scheidmeir)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://4.bp.blogspot.com/-wl5KfK3CSPI/V9fPfuJIgoI/AAAAAAAAAHg/7EuIRndB23wjYvDl5OT0hYgUgPUBT_ndACLcB/s72-c/Bildschirmfoto%2B2016-09-13%2Bum%2B11.38.51.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3132006615500366318</guid><pubDate>Mon, 12 Sep 2016 16:40:00 +0000</pubDate><atom:updated>2016-09-12T18:43:57.872+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">BI</category><category domain="http://www.blogger.com/atom/ns#">Business Intelligence</category><category domain="http://www.blogger.com/atom/ns#">ElasticSearch</category><category domain="http://www.blogger.com/atom/ns#">Kapow</category><category domain="http://www.blogger.com/atom/ns#">Scrapy</category><category domain="http://www.blogger.com/atom/ns#">Web Scraping</category><title>Competitive Intelligence: Suchmaschinen im Kontext von Business Intelligence</title><description>&lt;a href=&quot;http://exensio.de/sites/default/files/exensio-tdwi-bi-spektrum.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://exensio.de/sites/default/files/exensio-tdwi-bi-spektrum.png&quot; /&gt;&lt;/a&gt;Im &amp;nbsp;aktuellen BI Spektrum ist von uns ein Artikel bzgl. des Einsatzes von Suchtechnologien im Kontext von Competitive Intelligence erschienen.&lt;br /&gt;&lt;br /&gt;Suchmaschinen werden hauptsächlich mit der Suche in unstrukturierten Datenansammlungen wie Texten assoziiert. Die Eignung für die Analyse strukturierter Informationen ist derzeit dagegen nicht umfassend bekannt. Bei der Verwendung strukturloser Daten stoßen BI-Lösungen leicht an ihre Grenzen, besonders wenn ein eindeutiger Kenner wie beispielsweise ein EAN-Code (Barcode) für eine Preisvergleichsanalyse fehlt ...&lt;br /&gt;&lt;br /&gt;Der Artikel kann &lt;a href=&quot;http://exensio.de/sites/default/files/exensio-tdwi-bi-spektrum-competitive-intelligence.pdf&quot;&gt;hier&lt;/a&gt; als Sonderdruck auf unserer Homepage gelesen werden.</description><link>http://blog.exensio.de/2016/09/competitive-intelligence-suchmaschinen.html</link><author>noreply@blogger.com (Peter Soth)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-2409397942872284960</guid><pubDate>Mon, 25 Jul 2016 08:12:00 +0000</pubDate><atom:updated>2016-07-25T10:12:00.200+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Enterprise Application Integration</category><category domain="http://www.blogger.com/atom/ns#">Enterprise Service Bus</category><category domain="http://www.blogger.com/atom/ns#">ESB</category><category domain="http://www.blogger.com/atom/ns#">Portal</category><title>Integration mit SEEBURGER Business Integration Suite</title><description>&lt;a href=&quot;http://3.bp.blogspot.com/-spA56OBgxFg/V5XGTvpZMCI/AAAAAAAAB_E/kaWG_HOmAuwfomKgmFbFVqNYLU04Vk9UwCK4B/s1600/Grafik_Integration.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;234&quot; src=&quot;https://3.bp.blogspot.com/-spA56OBgxFg/V5XGTvpZMCI/AAAAAAAAB_E/kaWG_HOmAuwfomKgmFbFVqNYLU04Vk9UwCK4B/s320/Grafik_Integration.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;exensio hat schon sehr viele individuelle Portal Lösungen für seine Kunden implementiert. Wesentliches Element bei diesen Projekten sind stets Integrationen mit verschiedensten Backend Systemen. Erst der versteckte Durchgriff auf andere Applikationen macht den Mehrwert echter Portal-Lösungen für die Benutzer aus.&lt;br /&gt;&lt;br /&gt;Durch diese Projekte kommen wir mit allerlei anderen Systemen in Kontakt und haben verschiedenste technische Anbindungen implementiert. In einem vor kurzem abgeschlossenen Projekt konnten wir den Vorteil eines Enterprise Integration Busses genießen: bei unserem Kunden wird die SEEBURGER Business Integration Suite (BIS) eingesetzt.&lt;br /&gt;&lt;br /&gt;Damit waren wir von der individuellen Anbindung an die Systeme entbunden und konnten eine für uns technisch einfache Umsetzung der Schnittstelle wählen. Die Konvertierung in die für das Schnittstellensystem gewünschten Formate wurde durch den BIS Server umgesetzt.&lt;br /&gt;&lt;br /&gt;Wir wählten für die Kommunikation XML over http, d.h. haben entsprechend als XML verpackte Anfragen per GET und PUT Requests an den BIS Server geschickt und Antworten in Form von XML erhalten. Damit lassen sich auch sehr einfach die Schnittstellen per cURL testen.&lt;br /&gt;&lt;br /&gt;In dieser identischen Art konnten wir zum einen das CRM System anbinden (hier konkret Update7) sowie SAP. Die Zugriffe waren sowohl lesend als auch schreibend.&lt;br /&gt;&lt;br /&gt;Folgende Vorteile haben wir bei der Umsetzung gesehen:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Vom technischen Format unabhängige Implementierung der beiden an der Schnittstelle beteiligten Systeme (Abstraktion durch den BIS Server)&lt;/li&gt;&lt;li&gt;Gute Testbarkeit, insbesondere auch während des Betriebs (Testen der Schnittstelle durch cURL Aufrufe)&lt;/li&gt;&lt;li&gt;Zusätzliche Monitoring Ebene realisiert durch den BIS Server&lt;/li&gt;&lt;li&gt;Verfügbarkeit der Schnittstelle, auch wenn das eigentliche Zielsystem temporär technisch nicht erreichbar ist – beispielsweise bei der Weitergabe von Statusinformationen&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;In Summe konnten durch die Verwendung des Enterprise Integration Busses die Implementierungsaufwände für die Schnittstellen gegenüber einer konventionellen Anbindung deutlich reduziert werden.&lt;br /&gt;&lt;br /&gt;Neben SEEBURGER gibt es natürlich noch jede Menge weiterer Anbieter, die solche Enterprise Service Bus Lösungen anbieten (IBM, Oracle, etc.). SEEBURGER ist bekannt für die Integration mit SAP und stellt hierfür entsprechende Adapter zur Verfügung. Darüber hinaus gibt es eine ganze Reihe nicht-kommerzieller Anbieter, wie beispielsweise verschiedene Lösungen der Apache Software Foundation (Service Mix, Synapse, Tuscany) oder von JBoss.&lt;br /&gt;&lt;br /&gt;Im Übrigen halten wir Bus Lösungen oder Integrations-Frameworks wie Apache Camel nicht nur für Enterprise Portale sondern generell für zukünftige Lösungen im IoT und Industrie 4.0 Kontext für sehr relevant. Aber das Thema ist wohl einen separaten Blogbeitrag wert.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/07/integration-mit-seeburger-business.html</link><author>noreply@blogger.com (Irving Tschepke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-spA56OBgxFg/V5XGTvpZMCI/AAAAAAAAB_E/kaWG_HOmAuwfomKgmFbFVqNYLU04Vk9UwCK4B/s72-c/Grafik_Integration.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-5540437734773991666</guid><pubDate>Mon, 18 Jul 2016 05:34:00 +0000</pubDate><atom:updated>2016-11-09T10:49:44.195+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Browsertest</category><category domain="http://www.blogger.com/atom/ns#">Geb</category><category domain="http://www.blogger.com/atom/ns#">Groovy</category><category domain="http://www.blogger.com/atom/ns#">Selenium</category><category domain="http://www.blogger.com/atom/ns#">Spock</category><title>Interaktive Browser-Automatisierung mit Geb und der Groovy-Shell</title><description>Dieser Blog-Post beschreibt die Entstehung eines einfachen Werkzeugs zur interaktiven Benutzung von Geb und zeigt die Verwendung des Werkzeugs anhand eines Beispiels. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Problemstellung und Motivation&lt;/h2&gt;&lt;a href=&quot;http://www.gebish.org/&quot; target=&quot;_blank&quot;&gt;Geb&lt;/a&gt; ist eine Lösung zur Browser-Automatisierung auf Basis der Selenium Webdriver und der Programmiersprache &lt;a href=&quot;http://www.groovy-lang.org/&quot; target=&quot;_blank&quot;&gt;Groovy&lt;/a&gt;. Die Programm-Bibliothek bietet einfache und elegante Möglichkeiten für das automatisierte Testen von Webanwendungen, lässt sich aber auch für das Scraping von Webseiten einsetzen. Zusammen mit dem Testframework &lt;a href=&quot;https://github.com/spockframework/spock&quot; target=&quot;_blank&quot;&gt;Spock &lt;/a&gt;setzen wir Geb für funktionale Tests ein. &lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://2.bp.blogspot.com/-2jVrrKZlYK8/WCLxMEPg5xI/AAAAAAAAA2Q/t_gQVQdDlUsbePAIOfTYHEUIgtveacnNQCLcB/s1600/geb.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://2.bp.blogspot.com/-2jVrrKZlYK8/WCLxMEPg5xI/AAAAAAAAA2Q/t_gQVQdDlUsbePAIOfTYHEUIgtveacnNQCLcB/s320/geb.png&quot; width=&quot;320&quot; height=&quot;259&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Um einzelne Elemente einer Seite zu selektieren, bietet Geb eine jQuery-ähnliche Syntax. Die auf diese Weise selektierten Elemente einer Seite lassen sich in Geb zu einer logischen Einheit zusammenfassen.&lt;br /&gt;Bevor ich einen neuen funktionalen Test schreibe, wähle ich zunächst die daran beteiligten Elemente einer Seite (Buttons, Eingabefelder etc.) aus und erstelle entsprechende Selektoren - also Ausdrücke, die ein bestimmtes Element oder eine Gruppe von Elementen adressieren und für weitere Aktionen zugänglich machen. Auf Grundlage dieser Selektoren erstelle ich die oben beschriebene Einheit, auch PageObject genannt und verwende diese dann im funktionalen Test. &lt;br /&gt;&lt;br /&gt;Als ich erste Erfahrungen mit Geb sammelte, um funktionale Tests zu schreiben, verhielt sich mein Programmcode nicht immer so, wie ich es erwartet hätte. Ich passte die entsprechenden Stellen an und startete den funktionalen Test erneut. Dieses Vorgehen ist aber sehr zeitintensiv, da die zu testende Applikation neu gestartet und Testdaten neu geladen werden müssen. Daher suchte ich nach einer einfachen Lösung, um die Selektoren vor ihrer Verwendung ausprobieren zu können. Als ich keine fertige Lösung für dieses Problem fand, erstellte ich ein kleines Werkzeug auf Basis der Groovy-Shell und dem Build-Tool Gradle. Die Groovy-Shell implementiert einen REPL (read-eval-print-loop), wie man ihn von vielen Scriptsprachen (wie beispielsweise Python oder Javascript) kennt. In Kombination mit Geb lassen sich so Webseiten interaktiv untersuchen. &lt;br /&gt;&lt;br /&gt;Im folgenden Szenario möchten wir die Überschriften der zuletzt veröffentlichten Blog-Posts von der exensio-Homepage extrahieren.&lt;br /&gt;&lt;br /&gt;Wir laden uns den Quellcode des Projektes von &lt;a href=&quot;https://github.com/exensio/geb-groovyshell&quot; target=&quot;_blank&quot;&gt;GitHub&lt;/a&gt; herunter oder checken das Projekt mittels git aus. Um das Tool starten zu können, wird das Java Development Kit in der Version 8 und der Firefox Browser benötigt. Außerdem sollte die Umgebungsvariable „JAVA_HOME“ korrekt gesetzt sein.&lt;br /&gt;Nach dem wir auf der Kommandozeile in das Projektverzeichnis gewechselt sind, wird folgender Befehl eingegeben, um die Groovy-Shell und Geb zu initialisieren:&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/366442509e593852a3026b99362e962e.js&quot;&gt;&lt;/script&gt; Zunächst wird Gradle und die benötigten Abhängigkeiten (die Geb-Bibliothek, der Selenium-Webdriver etc.) heruntergeladen. Dann sollte sich automatisch eine neue Firefox-Instanz öffnen. Mittels des Browser-Objekts können wir nun diese Instanz ansteuern. Das folgende Beispiel sucht vom exensio-Blog die letzten Posts heraus und zeigt diese mit Hilfe des inspect-Befehls der Groovy-Shell in einem Dialog an.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/2aafbd933a5f416b6a2d4a895759a860.js&quot;&gt;&lt;/script&gt; Um die Groovy-Shell zu beenden, müssen folgende Befehle eingegeben werden: &lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/7657512486a0debe1f06f9ccf2029aaf.js&quot;&gt;&lt;/script&gt; &lt;h2&gt;Fazit&lt;/h2&gt;„Probieren geht über Studieren“ – ersetzt sicherlich nicht das Lesen der Dokumentation, doch gerade, wenn man eine neue Technologie kennenlernt, ist es von großem Vorteil, über eine Möglichkeit zu verfügen, einfach und unkompliziert etwas ausprobieren zu können. Die Groovy-Shell ist hierfür ein gutes Werkzeug. In diesem Beispiel haben wir sie mit Geb kombiniert, doch lässt sich dieses Prinzip auch auf andere Java bzw. Groovy-Bibliotheken übertragen. Auf der Projektseite des &lt;a href=&quot;https://github.com/tkruse/gradle-groovysh-plugin/tree/master/samples&quot; target=&quot;_blank&quot;&gt;Gradle-Groovy-Shell-Plugins&lt;/a&gt; finden sich weitere Beispiele, u.a. zur Kombination mit Spring-Boot.&lt;br /&gt;&lt;br /&gt;</description><link>http://blog.exensio.de/2016/07/interaktive-browser-automatisierung-mit.html</link><author>noreply@blogger.com (Benjamin Kretschmann)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://2.bp.blogspot.com/-2jVrrKZlYK8/WCLxMEPg5xI/AAAAAAAAA2Q/t_gQVQdDlUsbePAIOfTYHEUIgtveacnNQCLcB/s72-c/geb.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-301040322319877315</guid><pubDate>Fri, 01 Jul 2016 09:02:00 +0000</pubDate><atom:updated>2016-08-26T10:48:34.962+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">Lizenzen</category><category domain="http://www.blogger.com/atom/ns#">Open-Source</category><category domain="http://www.blogger.com/atom/ns#">ScanCode toolkit</category><title>Lizenzanalyse mit dem Open Source Tool ScanCode toolkit</title><description>In diesem Blogpost möchte ich auf das Tool &lt;a href=&quot;https://github.com/nexB/scancode-toolkit&quot; target=&quot;_blank&quot;&gt;ScanCode toolkit&lt;/a&gt; eingehen und zeigen wie man damit überprüfen kann welche Lizenzen die abhängigen Jar-Dateien eines Java-Projektes verwenden. Diese Information kann relevant sein, wenn man prüfen will ob daraus bspw. rechtliche Probleme resultieren können. Im &lt;a href=&quot;https://www.bitkom.org/Publikationen/2016/Leitfaden/Open-Source-Software-20/Bitkom-Leitfaden-Open-Source-Software-20.pdf&quot; target=&quot;_blank&quot;&gt;Bitkom-Leitfaden zu Open-Source-Software 2.0&lt;/a&gt; wird diese Thematik aufgegriffen und behandelt.&lt;br /&gt;Für dieses Beispiel wurde eine Grails- Applikation zur Hand genommen, welche etwas mehr als 150 externe Jar- Dateien einbindet, von denen die Lizenzen ermittelt werden sollen.&lt;br /&gt;&lt;br /&gt;Damit ScanCode toolkit Dateien überprüfen kann, müssen sie in entpackter Form vorliegen. Die Funktion zum Entpacken wird von Haus aus mitgeliefert, jedoch muss das Entpacken manuell gestartet werden. Wechselt man mit einem Terminal in das Verzeichnis des Tools kann mit folgendem Befehl das rekursive Entpacken aller Dateien in dem Zielverzeichnis gestartet werden:&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/b5e5aa3446735321fb02663808b4c583.js&quot;&gt;&lt;/script&gt; Der Pfad zum Zielverzeichnis ist relativ. Alle entpackten Dateien werden in demselben Verzeichnis mit dem Postfix &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;i&gt;„-extract“&lt;/i&gt;&lt;/span&gt; gespeichert. Liegen alle Dateien entpackt vor, kann man den Scan starten. &lt;br /&gt;Dies geschieht mit dem folgenden Befehl:&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/a4b74070872b388012386403d1f597d4.js&quot;&gt;&lt;/script&gt; Auch hier werden relative Pfade erwartet. Verwendet man die Option &lt;i&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;„-- format“&lt;/span&gt;&lt;/i&gt;kann die Art der Ausgabe bestimmt werden, dazu später mehr.&lt;br /&gt;&lt;br /&gt;Die Funktionsweise von ScanCode toolkit ist einfach, es durchsucht alle Dateien, in dem Zielverzeichnis, gegen einen bestehenden und erweiterbaren Datensatz von Lizenzen. Nach dem gleichen Prinzip ist es auch möglich Copyright- Statements zu finden, dies wurde jedoch nicht getestet und wird hier nicht weiter erläutert. &lt;br /&gt;Der Nachteil hierbei ist, dass dadurch Jar- Dateien mehrfach aufgelistet werden. Dies hat mehrere Gründe, zum einen kann es sein, dass diese unter einem dualen Lizenzsystem angeboten werden. Das bedeutet es werden mehrere Lizenzen aufgelistet, unter welcher die Software verwendet wird bleibt dem Benutzer überlassen. Zum anderen ist es möglich, dass ein Plugin seinerseits weiteren Code einbindet und dessen Lizenz, beispielsweise in einem Kommentar deutlich macht. In extremen Fällen verwendet auch dieser ein duales Lizenzsystem.&lt;br /&gt;&lt;br /&gt;Man hat die Wahl zwischen 3 verschiedenen Visualisierungsmöglichkeiten. Die Ausgabe als JSON- Datei, einer statisch HTML- Seite, welche eine Tabelle der Daten enthält oder eine HTML- Applikation die das Filtern, Sortieren und Navigieren über die Verzeichnisstruktur erlaubt.&lt;br /&gt;&lt;br /&gt;In Abbildung 1 ist eine beispielhafte Darstellung eines Scanergebnisses  als HTML- App dargestellt. Navigiert man im linken Bereich durch die  Verzeichnisstruktur werden die visualisierten Daten im rechten Bereich  entsprechend angepasst. Sind in dieser Gesamtansicht nun unerwünschte  Lizenzen aufgelistet wird die Stärke dieser HTML- Applikation deutlich. &lt;br /&gt;&lt;br /&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-62neP2kUouY/V2ztlNOgA4I/AAAAAAAAACM/nq-e7odD8UYDHKsNKwBZOAEmjM41qcaUgCK4B/s1600/Uebersicht_Ergebnis_schmal.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;340&quot; src=&quot;https://3.bp.blogspot.com/-62neP2kUouY/V2ztlNOgA4I/AAAAAAAAACM/nq-e7odD8UYDHKsNKwBZOAEmjM41qcaUgCK4B/s400/Uebersicht_Ergebnis_schmal.PNG&quot; title=&quot;Abbildung 1&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Abbildung 1&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-sZpaa1cevFE/V2zX5hwb-hI/AAAAAAAAABY/rPCEBEjZf3EAT8463wX5BasLB2YtJq2EACK4B/s1600/Uebersicht_Ergebnis_schmal.PNG&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-J1I2Bx3ANTo/V2zX8xV07jI/AAAAAAAAABg/MptlSx_z3h8j19zdosAvmhdN8tEmmfYhACK4B/s1600/Uebersicht_Scan_Ergebnis.PNG&quot; imageanchor=&quot;1&quot;&gt;&lt;/a&gt;&lt;br /&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt; &lt;o:OfficeDocumentSettings&gt;  &lt;o:RelyOnVML/&gt;  &lt;o:AllowPNG/&gt; &lt;/o:OfficeDocumentSettings&gt;&lt;/xml&gt;&lt;![endif]--&gt;&lt;br /&gt;Wechselt man in den Reiter &lt;i&gt;&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;„License &amp;amp; Copyright Details“&lt;/span&gt;&lt;/i&gt;wird eine Liste angezeigt die Dateien enthält in denen Lizenzen gefunden wurden. Sortiert man diese, wie in Abbildung 2, nach der Spalte Info kann man gezielt die Namen, der Jar- Files, in der Spalte Path ablesen, in denen Stichworte gefunden wurden, die in Verbindung mit den unerwünschten Lizenzen stehen. Das Verwenden der Suchfunktion, oben rechts, kann hierbei eine Hilfe sein.&lt;br /&gt;&lt;br /&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt; &lt;o:OfficeDocumentSettings&gt;  &lt;o:RelyOnVML/&gt;  &lt;o:AllowPNG/&gt; &lt;/o:OfficeDocumentSettings&gt;&lt;/xml&gt;&lt;![endif]--&gt;&lt;br /&gt;&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://1.bp.blogspot.com/-RUOe8Mygypo/V2zhgRHdqNI/AAAAAAAAAB8/L7a7ctxCpskuzymTPCcuCsoRTbwJss0IgCK4B/s1600/Reiter_Lizenzen_schmal.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;290&quot; src=&quot;https://1.bp.blogspot.com/-RUOe8Mygypo/V2zhgRHdqNI/AAAAAAAAAB8/L7a7ctxCpskuzymTPCcuCsoRTbwJss0IgCK4B/s400/Reiter_Lizenzen_schmal.PNG&quot; title=&quot;Abbildung 2&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Abbildung 2&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt; &lt;w:WordDocument&gt;  &lt;w:View&gt;Normal&lt;/w:View&gt;  &lt;w:Zoom&gt;0&lt;/w:Zoom&gt;  &lt;w:TrackMoves/&gt;  &lt;w:TrackFormatting/&gt;  &lt;w:HyphenationZone&gt;21&lt;/w:HyphenationZone&gt;  &lt;w:PunctuationKerning/&gt;  &lt;w:ValidateAgainstSchemas/&gt;  &lt;w:SaveIfXMLInvalid&gt;false&lt;/w:SaveIfXMLInvalid&gt;  &lt;w:IgnoreMixedContent&gt;false&lt;/w:IgnoreMixedContent&gt;  &lt;w:AlwaysShowPlaceholderText&gt;false&lt;/w:AlwaysShowPlaceholderText&gt;  &lt;w:DoNotPromoteQF/&gt;  &lt;w:LidThemeOther&gt;DE&lt;/w:LidThemeOther&gt;  &lt;w:LidThemeAsian&gt;X-NONE&lt;/w:LidThemeAsian&gt;  &lt;w:LidThemeComplexScript&gt;X-NONE&lt;/w:LidThemeComplexScript&gt;  &lt;w:Compatibility&gt;   &lt;w:BreakWrappedTables/&gt;   &lt;w:SnapToGridInCell/&gt;   &lt;w:WrapTextWithPunct/&gt;   &lt;w:UseAsianBreakRules/&gt;   &lt;w:DontGrowAutofit/&gt;   &lt;w:SplitPgBreakAndParaMark/&gt;   &lt;w:EnableOpenTypeKerning/&gt;   &lt;w:DontFlipMirrorIndents/&gt;   &lt;w:OverrideTableStyleHps/&gt;  &lt;/w:Compatibility&gt;  &lt;m:mathPr&gt;   &lt;m:mathFont m:val=&quot;Cambria Math&quot;/&gt;   &lt;m:brkBin m:val=&quot;before&quot;/&gt;   &lt;m:brkBinSub m:val=&quot;&amp;#45;-&quot;/&gt;   &lt;m:smallFrac m:val=&quot;off&quot;/&gt;   &lt;m:dispDef/&gt;   &lt;m:lMargin m:val=&quot;0&quot;/&gt;   &lt;m:rMargin m:val=&quot;0&quot;/&gt;   &lt;m:defJc m:val=&quot;centerGroup&quot;/&gt;   &lt;m:wrapIndent m:val=&quot;1440&quot;/&gt;   &lt;m:intLim m:val=&quot;subSup&quot;/&gt;   &lt;m:naryLim m:val=&quot;undOvr&quot;/&gt;  &lt;/m:mathPr&gt;&lt;/w:WordDocument&gt;&lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt; &lt;w:LatentStyles DefLockedState=&quot;false&quot; DefUnhideWhenUsed=&quot;true&quot;   DefSemiHidden=&quot;true&quot; DefQFormat=&quot;false&quot; DefPriority=&quot;99&quot;   LatentStyleCount=&quot;267&quot;&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;0&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Normal&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;heading 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 7&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 8&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;9&quot; QFormat=&quot;true&quot; Name=&quot;heading 9&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 7&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 8&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; Name=&quot;toc 9&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;35&quot; QFormat=&quot;true&quot; Name=&quot;caption&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;10&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Title&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;1&quot; Name=&quot;Default Paragraph Font&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;11&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Subtitle&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;22&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Strong&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;20&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Emphasis&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;59&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Table Grid&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; UnhideWhenUsed=&quot;false&quot; Name=&quot;Placeholder Text&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;1&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;No Spacing&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; UnhideWhenUsed=&quot;false&quot; Name=&quot;Revision&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;34&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;List Paragraph&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;29&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Quote&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;30&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Intense Quote&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 1&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 2&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 3&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 4&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 5&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;60&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Shading Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;61&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light List Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;62&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Light Grid Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;63&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 1 Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;64&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Shading 2 Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;65&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 1 Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;66&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium List 2 Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;67&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 1 Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;68&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 2 Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;69&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Medium Grid 3 Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;70&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Dark List Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;71&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Shading Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;72&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful List Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;73&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; Name=&quot;Colorful Grid Accent 6&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;19&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Subtle Emphasis&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;21&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Intense Emphasis&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;31&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Subtle Reference&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;32&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Intense Reference&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;33&quot; SemiHidden=&quot;false&quot;    UnhideWhenUsed=&quot;false&quot; QFormat=&quot;true&quot; Name=&quot;Book Title&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;37&quot; Name=&quot;Bibliography&quot;/&gt;  &lt;w:LsdException Locked=&quot;false&quot; Priority=&quot;39&quot; QFormat=&quot;true&quot; Name=&quot;TOC Heading&quot;/&gt; &lt;/w:LatentStyles&gt;&lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 10]&gt;&lt;style&gt; /* Style Definitions */  table.MsoNormalTable  {mso-style-name:&quot;Normale Tabelle&quot;;  mso-tstyle-rowband-size:0;  mso-tstyle-colband-size:0;  mso-style-noshow:yes;  mso-style-priority:99;  mso-style-parent:&quot;&quot;;  mso-padding-alt:0cm 5.4pt 0cm 5.4pt;  mso-para-margin-top:0cm;  mso-para-margin-right:0cm;  mso-para-margin-bottom:10.0pt;  mso-para-margin-left:0cm;  line-height:115%;  mso-pagination:widow-orphan;  font-size:11.0pt;  font-family:&quot;Calibri&quot;,&quot;sans-serif&quot;;  mso-ascii-font-family:Calibri;  mso-ascii-theme-font:minor-latin;  mso-hansi-font-family:Calibri;  mso-hansi-theme-font:minor-latin;  mso-fareast-language:EN-US;} &lt;/style&gt;&lt;![endif]--&gt; &lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Es ist sinnvoll die Plugins, bei denen ein unerwünschte Lizenz gefunden wurde, einzelnen auf deren Lizenz zu überprüfen. Denn, wie oben beschrieben, ist es möglich und meiner Erfahrung nach meistens der Fall, dass es unter einer Multilizenz steht oder Code einbindet der unter einer Mehrfachlizenzierung steht, was der Grund ist warum diese unerwünschte Lizenz angezeigt und in Verbindung mit der Jar- Datei  aufgelistet wird.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Fazit&lt;span style=&quot;font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;Das Tool ersetzt nicht das Evaluieren der Lizenzen. Die Entscheidung unter welche Lizenz eine Jar-Datei fallen darf, oder besser unter welche sie nicht fallen darf, damit es verwendet wird, muss noch immer manuell getroffen werden. Aber um einen schnellen Überblick zu bekommen welche Lizenzen verwendet werden und ob evtl. unerwünschte vorhanden sind ist es hervorragend geeignet.&lt;/span&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;In diesem Fall sind, von den anfänglich gut 150 Jar- Dateien, sieben in Verbindung mit unerwünschten Lizenzen aufgetaucht. Nach einer weiteren Untersuchung, bspw. auf der Hersteller Homepage, konnten auch deren Lizenzen schnell überprüft und für gut befunden werden.&lt;/span&gt;</description><link>http://blog.exensio.de/2016/07/lizenzanalyse-mit-dem-open-source-tool.html</link><author>noreply@blogger.com (Sebastian Jäger)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-62neP2kUouY/V2ztlNOgA4I/AAAAAAAAACM/nq-e7odD8UYDHKsNKwBZOAEmjM41qcaUgCK4B/s72-c/Uebersicht_Ergebnis_schmal.PNG" height="72" width="72"/><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-6839257530362120585</guid><pubDate>Fri, 24 Jun 2016 08:04:00 +0000</pubDate><atom:updated>2016-06-24T10:05:38.770+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">HTML5</category><category domain="http://www.blogger.com/atom/ns#">Responsive Design</category><category domain="http://www.blogger.com/atom/ns#">Responsive Web Design</category><title>Warum sich Responsive Design für Intranet Applikationen lohnt</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-HhLsapWHw5s/V2vzGy0E9II/AAAAAAAAB8U/fn4MRNiannE08PAtyeVZFa3y265MainrACLcB/s1600/responsive.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;189&quot; src=&quot;https://3.bp.blogspot.com/-HhLsapWHw5s/V2vzGy0E9II/AAAAAAAAB8U/fn4MRNiannE08PAtyeVZFa3y265MainrACLcB/s320/responsive.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Responsive Design ist eines der Buzzwords in Bezug auf die Gestaltung von Internet Webseiten. Was steckt dahinter? Die Webseite wird so implementiert, dass sich das Layout flexibel dem Ausgabegerät und dessen Auflösung anpasst. Damit kann man mit einer Implementierung alles von PC bis Smartphone abdecken.&lt;br /&gt;&lt;br /&gt;Natürlich gibt es Vor- und Nachteile dieses Ansatzes. Insbesondere wenn es um mobile Geräte geht, stellt sich die Frage, ob nicht doch besser eine native App – also eine Implementierung für ein spezielles Endgerät – Sinn macht. Eine native App ist generell dann vorteilhaft, wenn Hardware-nahe Funktionen genutzt werden müssen. Diese lassen sich bei einer Geräte-unabhängigen Implementierung nicht oder erheblich schwieriger umsetzen. Auf der anderen Seite muss dann für verschiedene Endgeräte jeweils eine neue Version der App, meist von Grund auf, umgesetzt werden. Und die eigentliche Web Applikation benötigt man ja auch noch.&lt;br /&gt;&lt;br /&gt;exensio entwickelt viele Web Lösungen, die im Intranet der Unternehmen eingesetzt werden. Auch hier stellt sich immer häufiger die Frage, mit welchen Endgeräten auf die Applikation zugegriffen werden soll. Ein klassischer Fall sind unsere Portal-Lösungen, die beispielsweise von Marketing und Vertrieb genutzt werden. Während etliche Marketing Kollegen vor allem im Innendienst aktiv sind und Desktop PCs oder Laptops verwenden, arbeiten die Vertriebsmitarbeiter mit mobilen Varianten, d.h. hier kommen verstärkt Tablets zum Einsatz.&lt;br /&gt;&lt;br /&gt;Bei einem unserer Kunden gab es das Szenario, dass für unsere Portal Lösung eine native App implementiert wurde. Auf Portal Seite haben wir entsprechende REST/JSON Schnittstellen entwickelt, ein anderer Dienstleister die App.&lt;br /&gt;&lt;br /&gt;Schon die erste Version der App hatte trotz vorhandener Portal Schnittstellen bei weitem nicht den Funktionsumfang des Portals. Zudem gab es nicht zu vernachlässigende Aufwände, um die Mitarbeiter für die App zu schulen, da diese im Vergleich zum Portal einen anderen Aufbau hatte und komplett anders zu bedienen war.&lt;br /&gt;&lt;br /&gt;Weiterhin stellte sich bei allen neu entwickelten Erweiterungen für das Portal die Frage, ob dies in der Schnittstelle für die App abzubilden ist und wann das neue Feature dann auch auf der App verfügbar ist. Die Konstellation mit 2 Dienstleistern tat ihr Übriges dazu. So wurde die funktionale Lücke zwischen Portal und App immer größer und die Akzeptanz der App schwand.&lt;br /&gt;&lt;br /&gt;Letztlich konnten wir unseren Kunden davon überzeugen, das Portal auf ein Responsive Design umzustellen. Die &lt;b&gt;Vorteile&lt;/b&gt; waren klar:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Keine Trennung in der Entwicklung einer Desktop Version und einer App.&lt;/li&gt;&lt;li&gt;Ein durchgängiges Design Konzept für Desktop Version und Zugriff über die Tablets.&lt;/li&gt;&lt;li&gt;Eine Umsetzung mit HTML5, die auf allen Endgeräten lauffähig ist.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Für Entscheider ist insbesondere der Blick auf die Kosten relevant:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Reduzierung der Entwicklungskosten:&lt;/b&gt;&amp;nbsp;keine extra Entwicklungen für Portal, Schnittstelle und App&lt;/li&gt;&lt;li&gt;&lt;b&gt;Reduzierung von Schulungs- und Trainingsaufwand:&lt;/b&gt; intuitives Design auf allen Geräten ähnlich&lt;/li&gt;&lt;li&gt;&lt;b&gt;Reduzierung der Wartungskosten: &lt;/b&gt;kein Installations- und Updateaufwand von Endgeräten&lt;/li&gt;&lt;li&gt;&lt;b&gt;Keine Migrationskosten:&lt;/b&gt; HTML5 ist auf allen Plattformen (iOS, Android, Windows, …) lauffähig&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Die beispielhaften Vergleichsrechnungen bei den Investitionskosten konnten auch überzeugen. Faktor 2 beim Vergleich, das Portal auf Responsive Design umzustellen gegenüber der Angleichung zwischen Portal und App. Beim Vergleich der Kosten für die Entwicklung einer neuen Funktion kamen wir sogar auf einen Faktor 3 zwischen der Responsive Lösung und der Variante mit Portal und nativer App.&lt;br /&gt;&lt;br /&gt;Als positiven Nebeneffekt konnten wir die generelle Überarbeitung des Designs des Portals in einen frischeren und modernen Look nutzen und damit auch alle Anwender zusätzlich erfreuen.&lt;br /&gt;&lt;br /&gt;Fazit: Auch bei internen Web Applikationen, die im Intranet von Unternehmen zum Einsatz kommen, kann sich die Umsetzung eines Responsive Designs lohnen.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/06/warum-sich-responsive-design-fur.html</link><author>noreply@blogger.com (Irving Tschepke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-HhLsapWHw5s/V2vzGy0E9II/AAAAAAAAB8U/fn4MRNiannE08PAtyeVZFa3y265MainrACLcB/s72-c/responsive.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-1789920567893173604</guid><pubDate>Wed, 22 Jun 2016 13:25:00 +0000</pubDate><atom:updated>2016-06-23T10:50:28.363+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">solr</category><title>HTML als HTML in Grails anzeigen</title><description>HTML als HTML in Grails anzeigen ist natürlich keine Rocket-Science. Aber da ich aktuell eine Weile suchen musste, möchte ich hier kurz mein Wissen teilen :-)&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;In Solr&amp;nbsp;Highlighting bekommt man die markierten Texte automatisch mit &amp;lt;em&amp;gt; bzw. &amp;lt;/em&amp;gt; markiert. Und eben diese wollte ich in eine GSP in Grails anzeigen.&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Eigentlich sollte folgendes funktionieren:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;${doc.content}&lt;/i&gt; wird automatisch encoded, wenn in Config.groovy&amp;nbsp;&lt;i&gt;grails.views.default.codec=&quot;html&quot;&lt;/i&gt; gesetzt ist, müsste man auf &lt;i&gt;&quot;none&quot;&lt;/i&gt; setzen. Man kann dies auch auf nur einer Seite mittels&amp;nbsp;&lt;i&gt;&amp;lt;%@page defaultCodec=&quot;none&quot; %&amp;gt; &lt;/i&gt;setzen.&lt;/li&gt;&lt;li&gt;Oder man benutzt die JSP Notation,&amp;nbsp;&lt;i&gt;&amp;lt;%=doc.content%&amp;gt; &lt;/i&gt;benutzen&lt;i&gt;.&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Hat beides nicht funktioniert. In Grails 2.5.4 hat schließlich nur folgendes funktioniert:&amp;nbsp;&lt;i&gt;${raw(doc.content)}&lt;/i&gt;.&lt;/div&gt; Happy Coding!</description><link>http://blog.exensio.de/2016/06/html-als-html-in-grails-anzeigen.html</link><author>noreply@blogger.com (Peter Soth)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-2645605426547541579</guid><pubDate>Thu, 16 Jun 2016 07:42:00 +0000</pubDate><atom:updated>2016-06-16T09:42:45.430+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Anforderungsanalyse</category><category domain="http://www.blogger.com/atom/ns#">Anforderungsmanagement</category><category domain="http://www.blogger.com/atom/ns#">exensio</category><category domain="http://www.blogger.com/atom/ns#">Requirements Engineering</category><category domain="http://www.blogger.com/atom/ns#">Requirements Management</category><title>Requirements Engineering nach IREB</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-ot52dGobcOY/V2EXCH-EoTI/AAAAAAAAB7w/c3256lsKhlML8GoIt066MmVY3JI899LNgCLcB/s1600/training_re.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://3.bp.blogspot.com/-ot52dGobcOY/V2EXCH-EoTI/AAAAAAAAB7w/c3256lsKhlML8GoIt066MmVY3JI899LNgCLcB/s320/training_re.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Nach dem Wunsch von 2 Kollegen, sich mit dem Thema „Anforderungen“ näher beschäftigen zu wollen, haben wir kurzerhand eine interne Fortbildung für alle Mitarbeiter veranstaltet. Neben dem Gedanken, dass alle Mitarbeiter Grundkenntnisse im Requirements Engineering besitzen sollten, hatten wir auch ein weiteres Ziel: ein gemeinsames Verständnis für die Anforderungsanalyse zu entwickeln und das Zusammenspiel zwischen den Kollegen, die mehr beim Kunden vor Ort sind und täglich sich mit Anforderungen beschäftigen und jenen, die ihren Schwerpunkt auf der Entwicklung haben, zu fördern.&lt;br /&gt;&lt;br /&gt;Über die Technische Akademie Esslingen TAE (&lt;a href=&quot;https://www.tae.de/&quot;&gt;https://www.tae.de/&lt;/a&gt;) haben wir Kontakt zu Frau Dr. Andrea Herrmann (&lt;a href=&quot;http://herrmannehrlich.twoday.net/&quot;&gt;http://herrmannehrlich.twoday.net/&lt;/a&gt;) aufgenommen, die für uns ein 2-tägiges Programm mit dem Titel „Requirements Engineering nach IREB“ zusammengestellt hat.&lt;br /&gt;&lt;br /&gt;IREB ist das „International Requirements Engineering Board“, eine non-profit Organisation, die sich zum Ziel gesetzt hat, Aus- und Weiterbildung im Requirements Engineering zu fördern und einen entsprechenden Standard entwickelt hat.&lt;br /&gt;&lt;br /&gt;In intensiven Sessions haben wir uns in 2 Tagen mit einer Fallstudie auseinandergesetzt und dabei alle wesentlichen Themen des Requirements Engineering vermittelt bekommen und in Übungen angewendet. Beginnend mit der Definition des Systems und dessen Kontext haben wir die verschiedenen Erhebungsmethoden kennen gelernt und darauf aufbauend die Anforderungen an das System in Form von Use Cases beschrieben.&lt;br /&gt;&lt;br /&gt;Intensive Diskussionen gab es beim Thema Qualitätsanforderungen, da hier insbesondere die praktischen Erfahrungen die Bedeutung dieser Art von Anforderungen relativiert: Aspekte wie beispielsweise Wartbarkeit und Sicherheit will jeder Kunden haben, aber es soll am besten nichts kosten… Auf der anderen Seite ist es nicht einfach, Anforderungen dieser Art messbar und damit nachprüfbar zu machen.&lt;br /&gt;&lt;br /&gt;Frau Dr. Herrmann hat auch auf unseren Wunsch hin Aspekte des GMP (Good Manufacturing Practice) beleuchtet, da wir durch unsere Tätigkeiten für die Pharma Industrie uns mit diesem Thema beschäftigen müssen.&lt;br /&gt;&lt;br /&gt;In verschiedenen Übungen haben wir die diversen Diagrammtypen der UML angewendet (wie Use Case-, Aktivitäts- und Zustands- und Klassendiagramm) und dafür das freie UML Werkzeug StarUML (&lt;a href=&quot;http://staruml.io/&quot;&gt;http://staruml.io/&lt;/a&gt;) eingesetzt. Über unsere (auch bereits vor der Schulung vorhandenen) Erfahrungen mit dem Tool berichten wir in einem späteren Blog-Beitrag. Die aktuelle Verwendung verschiedener Diagrammtypen in unseren bisherigen Projekten haben wir auch beleuchtet. Nicht alles, was die UML bietet, kann man auch dem Endkunden zur Abstimmung der Anforderungen vorlegen. So setzen wir bereits heute sehr gezielt nur eine Auswahl von Diagrammtypen ein. Zudem stellt sich auch immer die Frage des Kosten-Nutzen-Verhältnisses.&lt;br /&gt;&lt;br /&gt;Schließlich haben wir uns noch mit dem Management der Anforderungen im Projektverlauf beschäftigt (Requirements Management) und uns mit dem (für uns üblichen) iterativen Vorgehen und Change Request Verfahren auseinander gesetzt.&lt;br /&gt;&lt;br /&gt;Das Ziel, eine gemeinsame Basis beim Thema Requirements Engineering für alle Mitarbeiter der exensio zu schaffen, ist erreicht. Nun gilt es, die ein oder andere Anregung aus den beiden Tagen näher zu betrachten und in den Projektalltag zu integrieren.&lt;br /&gt;&lt;br /&gt;Einen herzlichen Dank nochmals an Frau Dr. Herrmann, die uns in der Kürze der Zeit sehr fundiert das Requirements Engineering nach IREB vermittelt hat und auf unsere Spezialthemen eingegangen ist.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/06/requirements-engineering-nach-ireb.html</link><author>noreply@blogger.com (Irving Tschepke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-ot52dGobcOY/V2EXCH-EoTI/AAAAAAAAB7w/c3256lsKhlML8GoIt066MmVY3JI899LNgCLcB/s72-c/training_re.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-7785253723603598548</guid><pubDate>Tue, 07 Jun 2016 07:41:00 +0000</pubDate><atom:updated>2016-06-07T09:42:10.171+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ElasticSearch</category><category domain="http://www.blogger.com/atom/ns#">Lucene</category><category domain="http://www.blogger.com/atom/ns#">solr</category><title>Artikel von exensio im aktuellen JavaSPKETRUM // Schweizer Taschenmesser für Daten - Serverlose Suchmaschinen</title><description>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-w9wrve59p-s/V1Z6bFwTEmI/AAAAAAAAE-8/-qMF3BJxJWQX-Icv8PtW4zJhjEJQLvdlwCLcB/s1600/cover_JS_03_16_weboptimiert.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://4.bp.blogspot.com/-w9wrve59p-s/V1Z6bFwTEmI/AAAAAAAAE-8/-qMF3BJxJWQX-Icv8PtW4zJhjEJQLvdlwCLcB/s1600/cover_JS_03_16_weboptimiert.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;In der aktuellen Ausgabe des JavaSPEKTRUM ist von mir ein Artikel mit dem Titel »Schweizer Taschenmesser für Daten - Serverlose Suchmaschinen« erschienen. In diesem zeige ich auf, dass sich Suchtechnologie noch für mehr, als nur Volltextsuche eignet. Als weitere Einsatzgebiete kommen hier:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Query-Turbo für SQL-Datenbanken&amp;nbsp;&lt;/li&gt;&lt;li&gt;Verarbeitung von GEO-Daten&amp;nbsp;&lt;/li&gt;&lt;li&gt;Business Intelligence&amp;nbsp;&lt;/li&gt;&lt;li&gt;Internet of Things (IoT)&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;in Frage.&lt;br /&gt;&lt;br /&gt;Der Artikel kann von &lt;a href=&quot;http://exensio.de/sites/default/files/javaspektrum_03_2016_exensio.pdf&quot;&gt;hier&lt;/a&gt; geladen werden.</description><link>http://blog.exensio.de/2016/06/artikel-von-exensio-im-aktuellen.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://4.bp.blogspot.com/-w9wrve59p-s/V1Z6bFwTEmI/AAAAAAAAE-8/-qMF3BJxJWQX-Icv8PtW4zJhjEJQLvdlwCLcB/s72-c/cover_JS_03_16_weboptimiert.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-4685219215683861290</guid><pubDate>Mon, 06 Jun 2016 05:17:00 +0000</pubDate><atom:updated>2016-06-06T11:51:33.252+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">Groovy</category><category domain="http://www.blogger.com/atom/ns#">Konferenz</category><title>Rückblick auf die GR8Conf in Kopenhagen</title><description>&lt;a href=&quot;https://3.bp.blogspot.com/-TqbBIkpjGjU/V1Sbvo2fb_I/AAAAAAAAAz4/e0ZYo6brXLk212sMjNxeQTaC--U4LPUYgCLcB/s1600/DSC_0111.JPG&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;200&quot; src=&quot;https://3.bp.blogspot.com/-TqbBIkpjGjU/V1Sbvo2fb_I/AAAAAAAAAz4/e0ZYo6brXLk212sMjNxeQTaC--U4LPUYgCLcB/s200/DSC_0111.JPG&quot; width=&quot;98&quot; /&gt;&lt;/a&gt;Dieses Jahr durfte ich drei Tage auf der gr8conf zu Gast sein und mein Wissen hinsichtlich des Groovy- und Grails-Ökosystems erweitern. Um die Open-Source Aktivitäten rund um diese Technologien zu fördern waren wir von der Firma &lt;a href=&quot;http://www.exensio.de&quot; target=&quot;_blank&quot;&gt;exensio&lt;/a&gt; auch einer der Sponsoren dieser Konferenz.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tag 1&lt;/h2&gt;Über den gesamten ersten Tag wurden jeweils 2 parallele Workshops angeboten. &lt;br /&gt;Ich hatte zunächst den Workshop zu gradle besucht, der viele Best Practices zum Build-System geboten hat.  &lt;br /&gt;Mein zweiter Workshop befasste sich mit Grails und AngularJS. Mit dem AngularJS-Profile wird eine Integration des Javascript-Frameworks innerhalb von Grails ermöglicht. Durch die direkte Integration können allerdings die beiden Komponenten nicht mehr einfach voneinander physikalisch getrennt werden, sprich der Javascript-Code wird auf einem anderen Server wie die Grails-Code installiert.  &lt;br /&gt;Am Abend fand der traditionelle Hackergarten statt, dessen Ziel es ist innerhalb eines Abends etwas zur Open-Source-Community beizutragen. Ich arbeitete mit anderen Teilnehmern an der Aktualisierung des Elasticsearch-Plugins für Grails. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tag 2&lt;/h2&gt;Mit der Keynote von Ken Kousen startete der zweite Tag. Er ging insbesondere auf den aktuellen Status von Groovy ein. Die Ankündigung von gradle vor wenigen Wochen, dass zukünftig neben Groovy die Programmiersprache Kotlin unterstützt wird, sorgte für einiges an Diskussionen in der Groovy-Community. Aus seiner Sicht sollte sich Groovy davon  aber nicht beunruhigen lassen, da Groovy weiterhin von gradle unterstützt wird und außerdem in vielen anderen Systemen, wie bspw. Jenkins, verwendet wird. &lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-FhFwgEo068c/V1ScLI20w6I/AAAAAAAAA0Q/IxPqha1QmBcdMtuqlKGQBMQ1KjXNZ_wRQCLcB/s1600/DSC_0119.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://4.bp.blogspot.com/-FhFwgEo068c/V1ScLI20w6I/AAAAAAAAA0Q/IxPqha1QmBcdMtuqlKGQBMQ1KjXNZ_wRQCLcB/s320/DSC_0119.JPG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://2.bp.blogspot.com/-xuztTn8-EqU/V1ScLDnVcJI/AAAAAAAAA0U/uQqNkrCizhU1YReObbAcHUb3LebqkyoSQCLcB/s1600/DSC_0132.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://2.bp.blogspot.com/-xuztTn8-EqU/V1ScLDnVcJI/AAAAAAAAA0U/uQqNkrCizhU1YReObbAcHUb3LebqkyoSQCLcB/s320/DSC_0132.JPG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Den interessantesten Vortrag an diesem Tag hielt aus meiner Sicht Michael Ploed zum Thema Reactive Applikations mit Grails 3. Er zeigte auf, wie einfach die Modularisierung von Grails-Applikationen mit Hilfe des in Grails 3 integrierten Reactor-Frameworks erfolgen kann.  &lt;br /&gt;In der Präsentation »Monitoring and Metrics with Grails 3« stellte Jeff Scott Brown das neue dropwizard-metric Plugin vor. Hiermit können zukünftig elegant Laufzeiten und die Anzahl von Methodenaufrufen gemessen werden. &lt;br /&gt;Das Thema »Dockerize you Grails App« war meine Abschluss-Session an diesem Tag. Hier wurde auf Docker Basics eingegangen und aufgezeigt, wie einfach Grails-Applikationen darauf aufsetzen können. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Tag 3&lt;/h2&gt;Am dritten Tag standen für mich zwei Sessions zum Thema Plugins auf dem Programm. Neben einem generellen Überblick im Vortrag »Mastering Grails 3 plugins« ging der zweite Vortrag auf die Migrationsmöglichkeiten von Plugins von der Version 2 auf 3 ein. &lt;br /&gt;Am spannendsten waren die Präsentationen von Graeme Rocher zur weiteren Entwicklung von Grails. Hier ist insbesondere das mit Grails 3.2 kommende Thema RxGORM, das nicht blockierende Datenbankzugriffe bietet sehr interessant.  &lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://1.bp.blogspot.com/-qyVgsbWqT_E/V1Sb_8pn0bI/AAAAAAAAA0A/6ZTxyv_lhxISYcoMPcQRwxbVKLcX0JjpQCLcB/s1600/DSC_0108.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://1.bp.blogspot.com/-qyVgsbWqT_E/V1Sb_8pn0bI/AAAAAAAAA0A/6ZTxyv_lhxISYcoMPcQRwxbVKLcX0JjpQCLcB/s320/DSC_0108.JPG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-wwR9oYvQz58/V1ScAcpMA9I/AAAAAAAAA0I/q3a2mPp27akn5iHs7j-PlOcp0lh1-e3EwCLcB/s1600/DSC_0134.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://4.bp.blogspot.com/-wwR9oYvQz58/V1ScAcpMA9I/AAAAAAAAA0I/q3a2mPp27akn5iHs7j-PlOcp0lh1-e3EwCLcB/s320/DSC_0134.JPG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h2&gt;Fazit&lt;/h2&gt;Neben vielen wissenswerten Informationen zu den verschiedenen Groovy- und Grails-Technologien ist Kopenhagen nicht nur wegen der gr8conf eine Reise wert. Die Stadt ist wunderschön und bietet im Vergleich zu den meisten Städten in Deutschland vielfältige und interessante Gebäudearchitekturen.</description><link>http://blog.exensio.de/2016/06/ruckblick-zur-gr8conf-in-kopenhagen.html</link><author>noreply@blogger.com (Tobias Kraft)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-TqbBIkpjGjU/V1Sbvo2fb_I/AAAAAAAAAz4/e0ZYo6brXLk212sMjNxeQTaC--U4LPUYgCLcB/s72-c/DSC_0111.JPG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-5971978304312987499</guid><pubDate>Tue, 17 May 2016 05:59:00 +0000</pubDate><atom:updated>2016-05-17T09:19:37.142+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ElasticSearch</category><category domain="http://www.blogger.com/atom/ns#">Lucene</category><category domain="http://www.blogger.com/atom/ns#">Python</category><category domain="http://www.blogger.com/atom/ns#">solr</category><title>Query Turbo für SQL : Elasticsearch, Apache Lucene bzw. Apache Solr vs. SQL Queries</title><description>In diesem Blogpost möchte ich aufzeigen, dass sich Suchmaschinen (in diesem Blogpost gehe ich auf Elasticsearch ein, das wie Apache Solr auf Apache Lucene basiert) auch ausgesprochen effektiv als Turbo für SQL-Queries verwenden lassen. SQL-Queries neigen ab einer gewissen Komplexität (hierarchisch, viele Aggregationen bzw. Joins) dazu, langsam zu werden. So entstehen beispielsweise in Portalen komplexe SQL Statements bei der Abfrage von Personalisierungsregeln (wer darf was sehen). Als prominentes Beispiel kann man hier das Liferay Portal erwähnen. Seit der Liferay-Version 6.2 [1] wird beim Asset Publisher ein Lucene Index anstelle von Datenbankabfragen eingesetzt.&lt;br /&gt;&lt;br /&gt;Mein Vergleich verwendet hingegen die 1,5 Millionen Zeilen, die ich in meinem Blogpost mit dem Thema »Olap Cube vs. Elasticsearch« [2] benutzte. Ich habe hierzu in MySQL eine flache Tabelle (keine Joins) angelegt, auf die entsprechenden Spalten einen Index gesetzt und im Anschluss daran befüllt. Anschließend ermittle ich mit Hilfe einer SQL-Abfrage dieselbe Pivot-Tabelle, die ich in meinem vorigen Blogpost mit Elasticsearch erzeugte. Das Retrieval und das Aufbereiten der Daten für die Pivot-Tabelle erfolgt mit folgendem Python-Skript.&lt;br /&gt;&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/peso0809/107adeb4086831c368f2683ed3c0646e.js&quot;&gt;&lt;/script&gt;&lt;br /&gt;Die Tabelle unten zeigt das Resultat, die Sortierung habe ich noch der Elasticsearch-Query meines letzten Blog-Posts hinzugefügt. Damit ist das von MySQL und Elasticsearch zurückgelieferte Ergebnis gleich und muss nicht innerhalb von Python sortiert werden.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;+-----------+------------------------------------+-------------+-------------+-------------+&lt;br /&gt;| Land      | Kunde                              | Umsatz 1994 | Umsatz 1995 | Umsatz 1996 |&lt;br /&gt;+-----------+------------------------------------+-------------+-------------+-------------+&lt;br /&gt;| Argentina |                                    |             |             |             |&lt;br /&gt;|           | Cactus Comidas para llevar         |       0.00  |   32339.16  |  104296.86  |&lt;br /&gt;|           | Océano Atlántico Ltda.             |       0.00  |   71270.10  |  504599.82  |&lt;br /&gt;|           | Rancho grande                      |       0.00  |  115290.42  |  296329.62  |&lt;br /&gt;| Brazil    |                                    |             |             |             |&lt;br /&gt;|           | Comércio Mineiro                   |  149676.60  |  146333.76  |   56055.82  |&lt;br /&gt;|           | Familia Arquibaldo                 |    5821.80  |  431282.70  |       0.00  |&lt;br /&gt;|           | Gourmet Lanchonetes                |       0.00  |  521745.96  |   83500.20  |&lt;br /&gt;|           | Hanari Carnes                      |  232872.00  |  181903.08  |  944863.26  |&lt;br /&gt;|           | Que Delícia                        |   17747.10  |  491754.30  |  105637.50  |&lt;br /&gt;|           | Queen Cozinha                      |       0.00  | 2704507.80  | 1017204.30  |&lt;br /&gt;|           | Ricardo Adocicados                 |   79852.56  |  485725.92  |  621214.02  |&lt;br /&gt;|           | Tradição Hipermercados             |    2535.30  |  236947.26  |  276141.12  |&lt;br /&gt;|           | Wellington Importadora             |   26235.66  |  108304.26  |  231125.46  |&lt;br /&gt;| Mexico    |                                    |             |             |             |&lt;br /&gt;|           | Ana Trujillo Emparedados y helados |    3023.58  |  104961.42  |   74969.76  |&lt;br /&gt;|           | Antonio Moreno Taquería            |   41316.00  |  353233.02  |  109731.54  |&lt;br /&gt;|           | Centro comercial Moctezuma         |    6103.50  |       0.00  |       0.00  |&lt;br /&gt;|           | Pericles Comidas clásicas          |  101787.60  |  286977.18  |  132695.20  |&lt;br /&gt;|           | Tortuga Restaurante                |  306696.18  |  448316.16  |  137876.06  |&lt;br /&gt;| Venezuela |                                    |             |             |             |&lt;br /&gt;|           | GROSELLA-Restaurante               |  124492.62  |       0.00  |    2835.78  |&lt;br /&gt;|           | HILARIÓN-Abastos                   |  153826.98  | 1487469.90  |  720745.36  |&lt;br /&gt;|           | LILA-Supermercado                  |  248947.68  |  576151.62  |  553818.20  |&lt;br /&gt;|           | LINO-Delicateses                   |       0.00  |  834376.62  |  431038.56  |&lt;br /&gt;+-----------+------------------------------------+-------------+-------------+-------------+&lt;br /&gt;Time taken: 10.31 seconds&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Die gemessene Zeit liegt immer bei ca. 10 Sekunden (MySQL cached nicht) auf meinem Notebook. Vergleiche ich die Zeitdauer mit Elasticsearch, so ergibt sich folgendes Bild. Initial (Caches nicht aktiv) benötigt die Abfrage mit Nested Objects 1,2 Sekunden ohne nur noch 1 Sekunde. Elasticsearch cached bei den nächsten Aufrufen und wir erhalten schließlich Zeiten von ca. 200ms. Hierbei sei zusätzlich erwähnt, dass ich sowohl MySQL als auch Elasticsearch nicht getuned habe.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Fazit&lt;/h3&gt;Sollte man bei der Entwicklung auf komplexe SQL-Queries stoßen, die nicht performant laufen, so kann es eine Überlegung wert sein, eine Suchmaschine wie Elasticsearch zu involvieren. Elasticsearch unterstützt Relationen, mit Nested Objects bzw. Parent-Child. Mein kleiner Test hat gezeigt, dass Nested Objects initial ca. 20 % langsamer sind. Parent-Child-Abfragen sind laut Dokumentation [3] 5-10 mal behäbiger als eine Nested Query. Im Vergleich zu MySQL ist in meinem Testaufbau zu sehen, dass Elasticsearch ca. 10-mal performanter ist. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Links&lt;/h3&gt;[1] &lt;a href=&quot;https://web.liferay.com/en/documentation/liferay-portal/6.2/release-notes&quot;&gt;https://web.liferay.com/en/documentation/liferay-portal/6.2/release-notes&lt;/a&gt;&lt;br /&gt;[2] &lt;a href=&quot;http://blog.exensio.de/2016/04/olap-cube-vs-elasticsearch.html&quot;&gt;http://blog.exensio.de/2016/04/olap-cube-vs-elasticsearch.html&lt;/a&gt;&lt;br /&gt;[3] &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/guide/current/parent-child-performance.html&quot;&gt;https://www.elastic.co/guide/en/elasticsearch/guide/current/parent-child-performance.html&lt;/a&gt;</description><link>http://blog.exensio.de/2016/05/query-turbo-fur-sql-elasticsearch.html</link><author>noreply@blogger.com (Peter Soth)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3612238025779344100</guid><pubDate>Wed, 04 May 2016 15:54:00 +0000</pubDate><atom:updated>2016-05-06T17:16:33.964+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">BPMN</category><category domain="http://www.blogger.com/atom/ns#">EPK</category><category domain="http://www.blogger.com/atom/ns#">Prozessmodellierung</category><title>Geschäftsprozesse mit BPMN Tools wie Bizagi, Yaoqiang oder Camunda Modeler modellieren</title><description>&lt;div class=&quot;MsoNormal&quot;&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-rmmEQLSti0E/Vyoaq8K5n7I/AAAAAAAAB6w/_y0z7hbdgysb4_Fm3DK5ObgxaqZ_hiYUgCLcB/s1600/example_bpmn.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;171&quot; src=&quot;https://3.bp.blogspot.com/-rmmEQLSti0E/Vyoaq8K5n7I/AAAAAAAAB6w/_y0z7hbdgysb4_Fm3DK5ObgxaqZ_hiYUgCLcB/s320/example_bpmn.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11pt; line-height: 107%;&quot;&gt;Nachdem ich zuletzt Prozesse noch vorwiegend mittels der EPK Methode (ereignisgesteuerte Prozessketten) modelliert habe, bin ich aktuell zur Business Process Modell and Notation – kurz BPMN – gewechselt.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Warum? BPMN wird zunehmend in Unternehmen eingesetzt (und an den Hochschulen gelehrt) und es ist ein Hersteller-neutraler Standard. BPMN wurde auch für die Umsetzung von Prozessen durch IT Lösungen entwickelt – unter Nutzung einer BPM Engine.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Zudem ist die Notation einfach zu verstehen und eignet sich daher gut zur Diskussion von Prozessen mit den Fachbereichen – was letztlich mein Hauptgrund für den Einsatz ist.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Beim Entwurf der Prozesse stellt sich sehr schnell die Frage nach einer geeigneten Tool Unterstützung. Auch wenn das „Malen“ erst mal im Vordergrund steht, wollte ich Visio und ähnliche Tools nicht nutzen. Mein erster Versuch mit draw.io war beispielsweise wenig zufriedenstellend.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Mit dem Ausblick auf eine zukünftige umfangreichere Nutzung habe ich Ausschau nach einem kostengünstigen BPMN Modellierungstool gehalten.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 14.6667px; line-height: 15.6933px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Hier kurz meine zusammenfassenden Erkenntnisse:&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif;&quot;&gt;&lt;span style=&quot;font-size: 14.6667px; line-height: 15.6933px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Einen guten Einstieg in die Thematik liefert der Blog „&lt;a href=&quot;http://www.kurze-prozesse.de/&quot;&gt;Kurze Prozesse&lt;/a&gt;“ von Thomas Allweyer, der sich als Experte intensiv dem Thema Geschäftsprozessmanagement und BPM widmet (und bspw. auch ein Buch über BPMN 2.0 geschrieben hat). In seinem Beitrag „&lt;a href=&quot;http://www.kurze-prozesse.de/2016/04/08/kostenfreie-modellierungstools-im-test/&quot;&gt;Kostenfreie Modellierungstools im Test&lt;/a&gt;“ findet sich ein guter Startpunkt für die Suche nach dem geeigneten Tool.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;&lt;span style=&quot;font-size: 11pt; line-height: 107%;&quot;&gt;Eine ältere Version des Modellierungstools von Bizagi hatte ich noch auf meinem Rechner – dieses hatte ich mir mal vor einiger Zeit kurz angeschaut. Der Einstieg war leicht und die Bedienung sehr angenehm. Den vorgeschlagenen Upgrade auf die neueste Version habe durchgeführt. Danach konnte ich das Tool nur noch nach Registrierung verwenden.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;&lt;span style=&quot;font-size: 11pt; line-height: 107%;&quot;&gt;&lt;span style=&quot;font-size: 11pt; line-height: 107%;&quot;&gt;Durch einen Beitrag von Thomas Allweyer habe ich mir noch kurz Yaoqiang angeschaut. Das Tool basiert auf Java und erfüllt alle Ansprüche zum Erstellen der Prozesse. Vom Handling und der Oberflächengestaltung erinnert es mich stark an Visio.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;&lt;span style=&quot;font-size: 11pt; line-height: 107%;&quot;&gt;&lt;span style=&quot;font-size: 11pt; line-height: 107%;&quot;&gt;&lt;span style=&quot;font-size: 11pt; line-height: 107%;&quot;&gt;Ein weiteres Werkzeug habe ich ausprobiert: den Camunda BPMN Modeler. Dieser kann unabhängig von der BPM Plattform von Camunda genutzt werden. Technisch basiert das Tool auf der Web-Modellierungsumgebung bpmn.io. Auf diese war ich bei meiner Web Recherche auch gestoßen und war von der einfachen Bedienung begeistert. Mit dem BPMN Modeler habe ich nun den gleichen Bedienungs-Komfort aber ohne eine notwendige Online Verbindung.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Nach meiner kurzen Evaluierung bin ich beim Camunda Modeler „hängen geblieben“. Kostenfrei, keine Registrierung und sehr einfach und intuitiv zu bedienen. Auch nach einiger Zeit der Nutzung bin ich noch begeistert – die Modellierung geht eminent schnell mit dem Tool. Entsprechende Export Funktionen sind vorhanden, um die Modelle in die von Kunden gewünschten Dokumentationen einzufügen.&lt;/span&gt;&lt;br /&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Eine IT-gestützte Umsetzung war nicht in meinem Fokus. Dennoch könnten diese Modelle später in der Open Source BPM Plattform von Camunda implementiert werden.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot; , sans-serif; font-size: 11.0pt; line-height: 107%;&quot;&gt;Wer sich mit BPMN noch nicht so intensiv auseinander gesetzt hat, findet bei Camunda im Übrigen jede Menge Informationen. Sehr hilfreich sind beispielsweise die &lt;a href=&quot;https://camunda.org/bpmn/examples/&quot;&gt;Best Practices&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div class=&quot;MsoListParagraphCxSpFirst&quot; style=&quot;mso-list: l0 level1 lfo1; text-indent: -18.0pt;&quot;&gt;&lt;br /&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/05/bpmn-tools.html</link><author>noreply@blogger.com (Irving Tschepke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-rmmEQLSti0E/Vyoaq8K5n7I/AAAAAAAAB6w/_y0z7hbdgysb4_Fm3DK5ObgxaqZ_hiYUgCLcB/s72-c/example_bpmn.jpg" height="72" width="72"/><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-5829730962288556204</guid><pubDate>Fri, 29 Apr 2016 10:00:00 +0000</pubDate><atom:updated>2016-04-29T12:00:11.056+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">exensio</category><title>Ergonomische Arbeitsplätze bei exensio</title><description>Wieder einmal eine nichttechnische Information von uns &amp;nbsp;:-).&lt;br /&gt;&lt;br /&gt;Schmerzen, Müdigkeit oder Erschöpfung treten nicht selten nach einem langen Arbeitstag auf. Der Grund hierfür: Einseitige körperliche Belastungen sind ungesund und führen eines Tages zu Problemen. Die Ergonomie am Arbeitsplatz darf keinesfalls zu kurz kommen, da Krankheiten des Bewegungsapparates für die meisten Krankenstandstage verantwortlich sind. Die passende Arbeitsplatzgestaltung sowie eine korrekte Sitzhaltung ist daher äußerst wichtig.&lt;br /&gt;&lt;br /&gt;Wir haben nun all unsere Schreibtische durch elektrisch höhenverstellbare ersetzt. Mal schauen, wann sich die ersten Symptome eines Muskelkaters vom langen Stehen einstellen :-)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://2.bp.blogspot.com/-SlTskGRkOb8/VyMvgogmahI/AAAAAAAAAXU/Yonw29kejqY7BJCoIPyA3vPEMwXq0ED1gCLcB/s1600/exensio_ergonomie_01.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://2.bp.blogspot.com/-SlTskGRkOb8/VyMvgogmahI/AAAAAAAAAXU/Yonw29kejqY7BJCoIPyA3vPEMwXq0ED1gCLcB/s1600/exensio_ergonomie_01.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;</description><link>http://blog.exensio.de/2016/04/ergonomische-arbeitsplatze-bei-exensio.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://2.bp.blogspot.com/-SlTskGRkOb8/VyMvgogmahI/AAAAAAAAAXU/Yonw29kejqY7BJCoIPyA3vPEMwXq0ED1gCLcB/s72-c/exensio_ergonomie_01.jpg" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-775019646012855742</guid><pubDate>Sat, 23 Apr 2016 14:18:00 +0000</pubDate><atom:updated>2016-04-25T16:55:32.813+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Business Intelligence</category><category domain="http://www.blogger.com/atom/ns#">ElasticSearch</category><category domain="http://www.blogger.com/atom/ns#">olap</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>OLAP Cube vs. Elasticsearch</title><description>In diesem Blog-Post möchte ich die Möglichkeiten aufzeigen, die Elasticsearch im Bereich Business Analytics bietet. Als Basis benutzte ich wiederum Testdaten aus der Publikation »Excel 2010 im Controlling« [1], das im Verlag Rheinwerk (früher Galileo Computing) erschienen ist. Diesmal ist es eine CSV-Datei mit 1,5 Millionen Zeilen. Da diese für Excel zu umfangreich ist (~1 Million Zeilen Limit in Excel 2007), wird im Buch PowerPivot und OLAP Cubes (auch als Datenwürfel bezeichnet) in Kombination mit dem Microsoft SQL Server benutzt.&lt;br /&gt;&lt;br /&gt;OLAP ist die Abkürzung für »Online Analytical Processing« und dient der Abfrage von mehrdimensionalen Informationen, analog zu einer Pivot-Tabelle. In unserem Beispiel ist die erste Dimension das Land, die zweite das Produkt und die dritte das Jahr (zeitliche). Die Dimensionen können in einem OLAP-Cube je nach Anforderung flexibel gewählt werden, jedoch sind spätere Änderungen äußerst aufwändig. Des Weiteren gibt es noch die Faktentabellen, die mathematische Auswertungen, wie berechnete Umsätze enthalten. Solch ein Datenbankschema wird auch als Star-Schema bezeichnet. Vorteil des Star-Schemas besteht darin, dass nur eine geringe Anzahl von Joins benötigt werden (bessere Performance bei großen Datenmengen einer RDB).&amp;nbsp;Die Abfrage von OLAP-Cubes erfolgt mit einer speziellen Sprache, genannt MDX (Multidimensional Expressions).&lt;br /&gt;&lt;br /&gt;In Elasticsearch wird dies alles nicht benötigt. Die Daten müssen demzufolge nicht voraggregiert in ein Star-Schema geladen werden, sie werden einfach flach (denormalisiert) in einem JSON-Dokument gespeichert. Will man Relationen in Elasticsearch verwenden, so gibt es die Möglichkeit »Nested Objects« bzw. »Parent/Child Relationships« zu benutzen. In meinem Beispiel habe ich zu Testzwecken »Nested Objects« für die Kunden und die Produkte eingefügt. Man sollte jedoch darauf verzichten, sofern es machbar ist, da dies komplexere Abfragen gegen Elasticsearch bewirkt.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;Folgendes Python-Skript erzeugt das Elasticsearch-Schema:&amp;nbsp; &lt;br /&gt;&lt;script src=&quot;https://gist.github.com/peso0809/369f51951db57003717e3c760fa12312.js&quot;&gt;&lt;/script&gt; Mit folgendem Python-Skript erzeuge ich das JSON-File für den Bulk-Import in Elasticsearch. Es werden auch gleich noch die 1:n und m:n Relationen aufgelöst und als »Nested Objects« gespeichert. Die Datei ist zum Schluss ca. 1 GByte groß, mit dem Linux Befehl split (split -l 700000 olap_test.json ./bulk) habe ich dieses dann in kleinere Happen aufgeteilt und mit mehreren Imports (curl -XPOST localhost:9200/_bulk --data-binary @bulkaa) in Elasticsearch importiert.&lt;script src=&quot;https://gist.github.com/peso0809/0643b8fab81073debf42a9d73c7136b4.js&quot;&gt;&lt;/script&gt;Folgendes Python-Skript zeigt die Abfrage gegen Elasticsearch, die benötigt wird, um die Pivot-Tabelle aufzubauen. Das Skript enthält auch die Query für die Nested Objects. Hierbei sieht man sehr schön, dass diese um einiges komplexer ist. Ich habe auch die Zeiten ausgegeben, die Elasticsearch benötigt. Diese sind beim initialen Aufruf fast gleich. Bei mehrmaligem Aufruf greift der Cache, dann ist die Nested Query um ca. 30% langsamer. Ich habe meinen Elasticsearch-Server in keiner Weise optimiert. Am Ende des Python-Skripts findet sich noch die ausgegebene Tabelle.  &lt;script src=&quot;https://gist.github.com/peso0809/b09c8f14fe7408d405700a1c41053926.js&quot;&gt;&lt;/script&gt;Das Ergebnis sieht folgendermaßen aus: &lt;br /&gt;&lt;pre&gt;+-----------+------------------------------------+-------------+-------------+-------------+&lt;br /&gt;| Land      | Kunde                              | Umsatz 1994 | Umsatz 1995 | Umsatz 1996 |&lt;br /&gt;+-----------+------------------------------------+-------------+-------------+-------------+&lt;br /&gt;| Brazil    |                                    |             |             |             |&lt;br /&gt;|           | Hanari Carnes                      |  232872.00  |  181903.08  |  944863.26  |&lt;br /&gt;|           | Queen Cozinha                      |       0.00  | 2704507.80  | 1017204.30  |&lt;br /&gt;|           | Ricardo Adocicados                 |   79852.56  |  485725.92  |  621214.02  |&lt;br /&gt;|           | Que Delícia                        |   17747.10  |  491754.30  |  105637.50  |&lt;br /&gt;|           | Wellington Importadora             |   26235.66  |  108304.26  |  231125.46  |&lt;br /&gt;|           | Gourmet Lanchonetes                |       0.00  |  521745.96  |   83500.20  |&lt;br /&gt;|           | Familia Arquibaldo                 |    5821.80  |  431282.70  |       0.00  |&lt;br /&gt;|           | Tradição Hipermercados             |    2535.30  |  236947.26  |  276141.12  |&lt;br /&gt;|           | Comércio Mineiro                   |  149676.60  |  146333.76  |   56055.82  |&lt;br /&gt;| Venezuela |                                    |             |             |             |&lt;br /&gt;|           | HILARIÓN-Abastos                   |  153826.98  | 1487469.90  |  720745.36  |&lt;br /&gt;|           | LILA-Supermercado                  |  248947.68  |  576151.62  |  553818.20  |&lt;br /&gt;|           | LINO-Delicateses                   |       0.00  |  834376.62  |  431038.56  |&lt;br /&gt;|           | GROSELLA-Restaurante               |  124492.62  |       0.00  |    2835.78  |&lt;br /&gt;| Mexico    |                                    |             |             |             |&lt;br /&gt;|           | Tortuga Restaurante                |  306696.18  |  448316.16  |  137876.06  |&lt;br /&gt;|           | Antonio Moreno Taquería            |   41316.00  |  353233.02  |  109731.54  |&lt;br /&gt;|           | Pericles Comidas clásicas          |  101787.60  |  286977.18  |  132695.20  |&lt;br /&gt;|           | Ana Trujillo Emparedados y helados |    3023.58  |  104961.42  |   74969.76  |&lt;br /&gt;|           | Centro comercial Moctezuma         |    6103.50  |       0.00  |       0.00  |&lt;br /&gt;| Argentina |                                    |             |             |             |&lt;br /&gt;|           | Cactus Comidas para llevar         |       0.00  |   32339.16  |  104296.86  |&lt;br /&gt;|           | Océano Atlántico Ltda.             |       0.00  |   71270.10  |  504599.82  |&lt;br /&gt;|           | Rancho grande                      |       0.00  |  115290.42  |  296329.62  |&lt;br /&gt;+-----------+------------------------------------+-------------+-------------+-------------+&lt;br /&gt;&lt;/pre&gt;&lt;h3&gt;Fazit&lt;/h3&gt;Anhand dieses Beispiels kann man m.E. überaus schön sehen, dass sich mit Elasticsearch auch im Bereich Business Analytics einiges bewerkstelligen lässt. Man muss kein Star-Schema aufsetzen und dieses über nächtliche Aggregationen laden. Ebenso ist das Erlernen von MDX oder eine Einarbeitung in andere BI-Tools nicht notwendig. Besonders interessant wird solch eine Lösung, wenn man noch die Volltextsuche in dieses Szenario integriert. So könnte man beispielsweise nach dem Kundennamen suchen. Bei einem riesigen Kundenkreis ist dies bestimmt schneller als das Filtern in einer Tree-View in einem klassischen BI-Tool. Einige BI-Tools verfügen auch über eine Suche, aber eine Suchmaschine kann hier beispielsweise mit einer Fuzzy-Search (Kundennamen werden dann auch noch mit Schreibfehlern gefunden) noch mehr punkten.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Links&amp;nbsp;&lt;/h3&gt;[1] &lt;a href=&quot;https://www.rheinwerk-verlag.de/excel-2010-im-controlling_2289/&quot;&gt;https://www.rheinwerk-verlag.de/excel-2010-im-controlling_2289/&lt;/a&gt;</description><link>http://blog.exensio.de/2016/04/olap-cube-vs-elasticsearch.html</link><author>noreply@blogger.com (Peter Soth)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-2433516057854031656</guid><pubDate>Fri, 15 Apr 2016 14:40:00 +0000</pubDate><atom:updated>2016-04-15T16:56:35.183+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><category domain="http://www.blogger.com/atom/ns#">JavaScript</category><category domain="http://www.blogger.com/atom/ns#">Responsive Design</category><title>Latest jQuery with Grails 2 and the resources plugin</title><description>We just updated the front end of an older &lt;a href=&quot;https://grails.org/&quot; target=&quot;_blank&quot;&gt;Grails&lt;/a&gt; 2.1.5 application to &lt;a href=&quot;http://getbootstrap.com/&quot; target=&quot;_blank&quot;&gt;Bootstrap&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The application uses the &lt;a href=&quot;http://grails.org/plugin/resources&quot; target=&quot;_blank&quot;&gt;resources plugin&lt;/a&gt;&amp;nbsp;and due to some other dependencies the &lt;a href=&quot;https://grails.org/plugin/jquery&quot; target=&quot;_blank&quot;&gt;jQuery plugin&lt;/a&gt; is loaded. The jQuery plugin ships with jQuery 1.11.1 and was not updated since 2014. The latest jQuery version as of now is 2.2.3. So how can we update the javascript library without fiddling with dependency excludes or other hacks?&lt;br /&gt;&lt;br /&gt;The resources plugin lets you override single resource files that are loaded in a plugin. The only thing you need is the id of the resource. In this case we have the following definition in the Grails jQuery plugin: &lt;script src=&quot;https://gist.github.com/exblog/2faa1f49165a7dc483997db7fc480ff3.js&quot;&gt;&lt;/script&gt;The id for the javascript file is &#39;js&#39;. The new jQuery version was put in &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;web-app/lib/jquery-2.2.3&lt;/b&gt;&lt;/span&gt;. With the following override in the &lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;b&gt;ApplicationResources.goorvy &lt;/b&gt;&lt;/span&gt;configuration the latest jQuery version is used everywhere: &lt;script src=&quot;https://gist.github.com/exblog/c6cef691ca11f152246b7b3245dda2ab.js&quot;&gt;&lt;/script&gt;This is a simple and fast way to override any javascript or css file that is provided by a Grails plugin. The &lt;a href=&quot;http://grails-plugins.github.io/grails-resources/guide/5.%20Overriding%20resources.html&quot; target=&quot;_blank&quot;&gt;documentation&lt;/a&gt;&amp;nbsp;of the resources plugin has some more informations about overrides.</description><link>http://blog.exensio.de/2016/04/latest-jquery-with-grails-2-and.html</link><author>noreply@blogger.com (Florian Mutter)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-2177472291414764821</guid><pubDate>Tue, 12 Apr 2016 16:18:00 +0000</pubDate><atom:updated>2016-04-15T17:01:05.876+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ElasticSearch</category><category domain="http://www.blogger.com/atom/ns#">Logstash</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>RSS Feeds mit Logstash und Elasticsearch durchsuchen</title><description>In diesem Blogpost möchte ich aufzeigen, wie man RSS Feeds mit Logstash und Elasticsearch durchsuchen kann. Folgendes Logstash-Skript holt sich alle 2 Stunden Informationen aus der Logistikbranche.&lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/930ccc9d45fc6b8f5c7001fc029f9a1a.js&quot;&gt;&lt;/script&gt;Und folgendes Python-Skript ermöglicht das Dursuchen des RSS-Feeds. Die Elasticsearch-Query liefert keine Dubletten (da ja alle 2 Stunden der RSS-Feed indiziert wird) zurück. Dies wird mit Hilfe einer top_hits Aggregation erreicht. &lt;br /&gt;&lt;script src=&quot;https://gist.github.com/exblog/609b75daf4fd49e4ec2a4445f145c0ac.js&quot;&gt;&lt;/script&gt;Und so sieht das Ganze in Aktion aus: &lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-HrU3ZAyrmBA/Vw0gQxUKQzI/AAAAAAAAAW0/L0McNVM-yDMasO4nEw_gNnawPzENHvitQCLcB/s1600/exensio-rss-elastic-search.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;117&quot; src=&quot;https://3.bp.blogspot.com/-HrU3ZAyrmBA/Vw0gQxUKQzI/AAAAAAAAAW0/L0McNVM-yDMasO4nEw_gNnawPzENHvitQCLcB/s400/exensio-rss-elastic-search.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Natürlich kann die Abfrage auch in einer Web-Applikation bereitgestellt werden. Python wurde hier nur zur Veranschaulichung benutzt.</description><link>http://blog.exensio.de/2016/04/rss-feeds-mit-logstash-und.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://3.bp.blogspot.com/-HrU3ZAyrmBA/Vw0gQxUKQzI/AAAAAAAAAW0/L0McNVM-yDMasO4nEw_gNnawPzENHvitQCLcB/s72-c/exensio-rss-elastic-search.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-9178956335778983751</guid><pubDate>Mon, 21 Mar 2016 06:55:00 +0000</pubDate><atom:updated>2016-03-21T09:41:05.634+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ElasticSearch</category><category domain="http://www.blogger.com/atom/ns#">Enterprise Search</category><category domain="http://www.blogger.com/atom/ns#">Konferenz</category><title>CeBIT 2016</title><description>Auf der diesjährigen &lt;a href=&quot;http://www.cebit.de/&quot; target=&quot;_blank&quot;&gt;CeBIT&lt;/a&gt; durfte ich einen Vortrag mit dem Thema &quot;Die Suche macht den Unterschied&quot; halten.  &lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://2.bp.blogspot.com/-FPgBwhU6x2w/Vu8ebTVGnBI/AAAAAAAAAzM/gKfLZZfmBu8EMnOoRQ6RPCPy1b7ZMxLig/s1600/cebit.png&quot; imageanchor=&quot;1&quot; style=&quot;clear: right; float: right; margin-bottom: 1em; margin-left: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://2.bp.blogspot.com/-FPgBwhU6x2w/Vu8ebTVGnBI/AAAAAAAAAzM/gKfLZZfmBu8EMnOoRQ6RPCPy1b7ZMxLig/s320/cebit.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Die Präsentation fand im Rahmen der vom Heise-Verlag organisierten &lt;a href=&quot;http://developerworld.heise.de/&quot; target=&quot;_blank&quot;&gt;developer world&lt;/a&gt; statt. Da ich gleich um 10 Uhr die erste Präsentation hatte, dachte ich, dass sich nicht allzu viele Zuhörer einfinden würden. Zum Glück erwies sich dies als Trugschluss und nach den ersten Vortrags-Minuten gingen die Sitzplätze im Auditorium zu Neige und die neu eingetroffenen Hörer mussten sich mit Stehplätzen begnügen.  &lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;display: table; margin: 0 auto; width: 500px;&quot;&gt;&lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;c64fa3da53e44871949aa39288313c41&quot; data-ratio=&quot;1.41436464088398&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Was gibt es sonst noch zur CeBIT zu sagen?&lt;/h3&gt;Die CeBIT ist nach wie vor ein enormer Besuchermagnet, bei der man alle Altersklassen antrifft, die sich für moderne IT-Technologien interessieren. Erschreckend fand ich dagegen beim Durchschlendern der Hallen, wie beinahe auf jedem Stand die Banner mit den selben Buzzwörtern (IoT, Digitalisierung, ..) versehen waren und zwanghaft die Aufmerksamkeit erringen wollten. &lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-8crOzxs9hJo/Vu8ddH5SHqI/AAAAAAAAAzE/lQPIYLcR3wQoOLeJMPkgNfo3Bhiw8iplw/s1600/DSC_0080.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;225&quot; src=&quot;https://3.bp.blogspot.com/-8crOzxs9hJo/Vu8ddH5SHqI/AAAAAAAAAzE/lQPIYLcR3wQoOLeJMPkgNfo3Bhiw8iplw/s400/DSC_0080.JPG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://2.bp.blogspot.com/-rrsp3SX9wVY/Vu8ddHPvGVI/AAAAAAAAAzA/g4wRBPgUc5gooiL9k1mMxc8g8A2IFBoIg/s1600/DSC_0078.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;225&quot; src=&quot;https://2.bp.blogspot.com/-rrsp3SX9wVY/Vu8ddHPvGVI/AAAAAAAAAzA/g4wRBPgUc5gooiL9k1mMxc8g8A2IFBoIg/s400/DSC_0078.JPG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/03/cebit-2016.html</link><author>noreply@blogger.com (Tobias Kraft)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://2.bp.blogspot.com/-FPgBwhU6x2w/Vu8ebTVGnBI/AAAAAAAAAzM/gKfLZZfmBu8EMnOoRQ6RPCPy1b7ZMxLig/s72-c/cebit.png" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-2909070246567609322</guid><pubDate>Thu, 10 Mar 2016 08:25:00 +0000</pubDate><atom:updated>2016-03-10T09:25:06.812+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Geb</category><category domain="http://www.blogger.com/atom/ns#">java</category><category domain="http://www.blogger.com/atom/ns#">Konferenz</category><category domain="http://www.blogger.com/atom/ns#">Spock</category><title>Javaland 2016</title><description>Dieses Jahr besuchte ich das erste Mal die &lt;a href=&quot;http://www.javaland.eu/&quot; target=&quot;_blank&quot;&gt;Javaland&lt;/a&gt;-Konferenz im Phantasialand in Brühl. Die Lokation ist für eine Konferenz natürlich etwas Außergewöhnliches, und spätestens als am ersten Abend die Fahrgeschäfte aufmachten, leuchteten die Augen der Teilnehmer wie bei kleinen Kindern. &lt;br /&gt;&lt;br /&gt;Mit meinem Kollegen Ralf Müller durfte ich einen Vortrag zum Thema Testen mit Spock und Geb unter Einbeziehung des Fachbereiches halten. Die Problematik der nachvollziehbaren Tests für den Fachbereich scheint viele Entwickler anzusprechen, da sie offensichtlich ähnliche Probleme haben, wie nachträgliche Diskussionen zeigten. &lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;display: table; margin: 0 auto; width: 500px;&quot;&gt;&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;3e2e77dd039b45879579a7b6895e5203&quot; data-ratio=&quot;1.77777777777778&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Die von mir besuchten Sessions auf der Konferenz waren durchweg qualitativ hochwertig. Neben Hype-Themen wie Microservices oder Container, die meiner Wahrnehmung nach aktuell auf jeder Konferenz zu finden sind, gab auch zahlreiche klassische Vorträge zu Java, die einen Besuch wert waren. &lt;br /&gt;&lt;br /&gt;Hier ein Auszug meiner gehörten Vorträge: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;JUnit Lambda - the Next Generation (Jens Schauder)&lt;br /&gt;Netter Überblick über die Neuerungen in der nächsten JUnit Version. Ich ziehe Spock aber aufgrund der Lesbarkeit nach wie vor jederzeit als Testframework vor. &lt;/li&gt;&lt;li&gt;Fun in groovyLand (Dierk König)&lt;br /&gt;Allergrößten Respekt, dass Dierk die ersten 15 Minuten der Session ohne Beamer auskommen musste, und dies bravourös mit seinem gewohnt angenehmen Vortragsstil meisterte. Anschließend zeigte er einige Szenarien auf wie mit groovy kompakt und doch übersichtlich Code produziert werden kann. &lt;/li&gt;&lt;li&gt;Hacking Java (Sean Floyd)&lt;br /&gt;Der Titel-Name war Programm und es wurden Tricks gezeigt, die ich eigentlich nur in Notfällen anwenden möchte.  &lt;/li&gt;&lt;li&gt;Mit Vert.x vom Monolithen zum reaktiven Microservice (Jochen Mader)&lt;br /&gt;Nachdem Jochen zunächst sehr schön auf die Probleme von verteilten Applikationen und damit auch Mikroservices einging, zeigte er auf wie vert.x OutOfTheBox den Übergang von einer monolithischen in eine verteilte Applikation unterstützt. &lt;/li&gt;&lt;li&gt;IoT with Apache ActiveMQ, Camel &amp;amp; Spark (Burr Sutter)&lt;br /&gt;Mit Hilfe von iBeacons, die wir ebenfalls bei unserem letzten ShipIt-Day nutzen, wurden einige IoT-Szenarien aufgezeigt und ich konnte mir Ideen für die Weiterentwicklung unserer eigenen Applikation holen.  &lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-khkHCWhevkE/VuEusSMQWAI/AAAAAAAAAyM/ow1w2H2Zv-M/s1600/DSC_0046.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://4.bp.blogspot.com/-khkHCWhevkE/VuEusSMQWAI/AAAAAAAAAyM/ow1w2H2Zv-M/s200/DSC_0046.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-l693B9lvV00/VuEur3BZ0pI/AAAAAAAAAyE/ngyesfvEIBo/s1600/DSC_0047.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://3.bp.blogspot.com/-l693B9lvV00/VuEur3BZ0pI/AAAAAAAAAyE/ngyesfvEIBo/s200/DSC_0047.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-xXaGxaOO6_s/VuEuryPlDPI/AAAAAAAAAyI/WCxUszNwiH8/s1600/DSC_0049.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://4.bp.blogspot.com/-xXaGxaOO6_s/VuEuryPlDPI/AAAAAAAAAyI/WCxUszNwiH8/s200/DSC_0049.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-UtTk3QIuC8Y/VuEutTdJ9nI/AAAAAAAAAyQ/o4jKFzgsPkA/s1600/DSC_0053.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://4.bp.blogspot.com/-UtTk3QIuC8Y/VuEutTdJ9nI/AAAAAAAAAyQ/o4jKFzgsPkA/s200/DSC_0053.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://2.bp.blogspot.com/-LPpGcgd6qUA/VuEuth91LUI/AAAAAAAAAyU/A5yyIQAAPOE/s1600/DSC_0055.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://2.bp.blogspot.com/-LPpGcgd6qUA/VuEuth91LUI/AAAAAAAAAyU/A5yyIQAAPOE/s200/DSC_0055.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://1.bp.blogspot.com/-Xa6Tc-uV49Q/VuEuuG_75OI/AAAAAAAAAyY/n8vX_10A_Mo/s1600/DSC_0057.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://1.bp.blogspot.com/-Xa6Tc-uV49Q/VuEuuG_75OI/AAAAAAAAAyY/n8vX_10A_Mo/s200/DSC_0057.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://3.bp.blogspot.com/-e1mcKXhUFJY/VuEuu-mbqBI/AAAAAAAAAyc/bXETUym-vf4/s1600/DSC_0059.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://3.bp.blogspot.com/-e1mcKXhUFJY/VuEuu-mbqBI/AAAAAAAAAyc/bXETUym-vf4/s200/DSC_0059.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://4.bp.blogspot.com/-_NfTJks47JU/VuEuvILlqUI/AAAAAAAAAyg/06uOvm1xVts/s1600/DSC_0064.JPG&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;112&quot; src=&quot;https://4.bp.blogspot.com/-_NfTJks47JU/VuEuvILlqUI/AAAAAAAAAyg/06uOvm1xVts/s200/DSC_0064.JPG&quot; width=&quot;200&quot; /&gt;&lt;/a&gt;&lt;/div&gt;</description><link>http://blog.exensio.de/2016/03/javaland-2016.html</link><author>noreply@blogger.com (Tobias Kraft)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://4.bp.blogspot.com/-khkHCWhevkE/VuEusSMQWAI/AAAAAAAAAyM/ow1w2H2Zv-M/s72-c/DSC_0046.JPG" height="72" width="72"/><thr:total>0</thr:total></item></channel></rss>