<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-4466305307772589754</atom:id><lastBuildDate>Wed, 16 May 2012 15:51:54 +0000</lastBuildDate><category>solr</category><category>DWH</category><category>Usability</category><category>User Interface</category><category>JPA</category><category>ETL</category><category>Lucene</category><category>Hibernate</category><category>ActionScript</category><category>socbiz</category><category>Glosse</category><category>socialmedia</category><category>Security</category><category>exensio</category><category>Offshoring</category><category>Open-Source</category><category>Konferenz</category><category>Build Prozess</category><category>Compass Search</category><category>GORM</category><category>Flash</category><category>WebLogic Server</category><category>Apps</category><category>SAP EP</category><category>Grails</category><category>Flex</category><category>Spring</category><category>WebLogic Portal</category><category>Informationsportal</category><category>e20</category><category>Apache Wink</category><category>HTML5</category><category>web20</category><category>LocalConnection</category><category>Kettle</category><category>Content</category><category>MySQL</category><category>REST</category><category>Portal</category><category>Propagation</category><category>AS3</category><category>Virtualisierung</category><category>BlackBerry</category><category>Fail2ban</category><category>ADF</category><category>EJB 3.0</category><category>Tomcat</category><category>Apache Webserver</category><category>EclipseLink</category><category>CMS</category><category>JRockit</category><category>Automatisierter Build</category><category>Liferay</category><category>Excel</category><title>exensio it blog</title><description /><link>http://blog.exensio.de/</link><managingEditor>noreply@blogger.com (Peter Soth)</managingEditor><generator>Blogger</generator><openSearch:totalResults>65</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/blogspot/iQDgu" /><feedburner:info uri="blogspot/iqdgu" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>blogspot/iQDgu</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-1679018207868227070</guid><pubDate>Mon, 07 May 2012 09:14:00 +0000</pubDate><atom:updated>2012-05-07T11:14:29.836+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Fail2ban</category><category domain="http://www.blogger.com/atom/ns#">Security</category><category domain="http://www.blogger.com/atom/ns#">Spring</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Grails-Applikation mit Fail2ban schützen</title><description>&lt;a href="http://www.fail2ban.org/wiki/index.php/Main_Page"&gt;Fail2ban&lt;/a&gt; [1] ist ein Tool, welches Log-Files nach bestimmten Mustern scannt und abhängig von den definierten Filtern IPs für eine gewisse Zeit sperrt. Ein typisches Anwendungsszenario für &lt;b&gt;Fail2ban&lt;/b&gt; ist beispielsweise das Absichern des SSH-Servers: Hat die gleiche IP innerhalb von 10 Minuten eine gewisse Anzahl an fehlgeschlagenen Logins überschritten, wird sie für eine bestimmte Zeit gesperrt. Damit erhält man nicht nur mehr Sicherheit - auch die Log-Files werden übersichtlicher, da sie nicht mit tausenden von fehlgeschlagenen Logins überfüllt werden. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Die eigene Grails-Applikation mit Fail2Ban schützen&lt;/h2&gt;Im Folgenden möchte ich zeigen, wie einfach und schnell die eigene &lt;a href="http://grails.org"&gt;Grails&lt;/a&gt;-Applikation mit Fail2Ban geschützt werden kann. Wir verwenden das SpringSecurity Plugin [2] und wollen eine IP dann sperren, wenn von ihr 5 fehlgeschlagene Logins binnen einer Minute ausgingen.  &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;SpringSecurity AuthenticationFailureEvent&lt;/h3&gt;In Config.groovy definieren wir den Aufruf zu unserem Logger: LoginUtils.logFailedLogin() &lt;br /&gt;&lt;pre class="java" name="code"&gt;grails.plugins.springsecurity.useSecurityEventListener = true&lt;br /&gt;grails {&lt;br /&gt;    plugins {&lt;br /&gt;        springsecurity {&lt;br /&gt;            onAbstractAuthenticationFailureEvent  = { e, appCtx -&amp;gt;&lt;br /&gt;                LoginUtils.logFailedLogin()&lt;br /&gt;                return true&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;Wie geloggt werden soll, definieren wir ebenfalls in der Config.groovy: &lt;br /&gt;&lt;pre class="java" name="code"&gt;log4j = {&lt;br /&gt;    appenders {&lt;br /&gt;        rollingFile name: "failedLoginsFile", maxFileSize: "7MB", 'append': true, file: "/var/log/exensio-demoapp/failedlogins.log",  layout: pattern(conversionPattern: '%d{yyyy-MM-dd HH:mm:ss,SSS} %p %c{2} %m%n')&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    warn failedLoginsFile: 'com.exensio.utils.LoginUtils'&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Der Logger sieht dabei wie folgt aus: &lt;br /&gt;&lt;pre class="java" name="code"&gt;class LoginUtils {&lt;br /&gt;    private static final log = LogFactory.getLog(this)&lt;br /&gt;&lt;br /&gt;    def static logFailedLogin() {&lt;br /&gt;        GrailsWebRequest request = RequestContextHolder.currentRequestAttributes()&lt;br /&gt;        def ip = getRemoteAddress(request)&lt;br /&gt;        log.warn("Failed login attempt for IP: ${ip}")&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static getRemoteAddress(GrailsWebRequest request)  {&lt;br /&gt;        def retVal = request.getRequest().getRemoteAddr()&lt;br /&gt;        // If you're application is behind a proxy, you may have to call&lt;br /&gt;        // a: request.getRequest().getHeader("X-Forwarded-For")&lt;br /&gt;        // b: request.getRequest().getHeader("Client-IP")&lt;br /&gt;        return retVal&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt; &lt;h3&gt;Fail2Ban-Installation&lt;/h3&gt;Unter Debian/Ubuntu kann Fail2Ban einfach über das Paketmanagement installiert werden. Das geht beispielsweise so: &lt;pre class="java" name="code"&gt;&lt;br /&gt;sudo aptitude install fail2ban&lt;br /&gt;&lt;/pre&gt; &lt;h3&gt;Fail2Ban-Konfiguration&lt;/h3&gt;Das Kernstück der Fail2Ban-Konfiguration steckt in der Datei jail.conf. In ihr werden die unterschiedlichen Dienste, sprich Log-Files, definiert, die zu überwachen sind. In unserem Fall sieht der Abschnitt wie folgt aus: &lt;pre class="java" name="code"&gt;[exensio-demoapp]&lt;br /&gt;enabled = true&lt;br /&gt;port = 8080&lt;br /&gt;filter = exensio-demoapp&lt;br /&gt;logpath  = /var/log/exensio-demoapp/failedlogins.log&lt;br /&gt;maxretry = 5&lt;br /&gt;bantime = 600&lt;br /&gt;findtime = 60&lt;br /&gt;&lt;/pre&gt;Die Konfigurationen im Einzelnen: &lt;ul&gt;&lt;li&gt;enabled: Gibt an, ob der Filter überhaupt genutzt werden soll&lt;/li&gt;&lt;li&gt;port: Gibt an, für welchen Port die IP gesperrt werden soll. In unserem Fall läuft die Grails-Applikation auf 8080.&lt;/li&gt;&lt;li&gt;filter: Gibt den Namen des Filters an, siehe nächster Abschnitt&lt;/li&gt;&lt;li&gt;logpath: Der Pfad zur Log-Datei&lt;/li&gt;&lt;li&gt;maxretry: Die Anzahl an fehlgeschlagenen Logins&lt;/li&gt;&lt;li&gt;bantime: Die Zeit in Sekunden, für die eine IP gesperrt werden soll&lt;/li&gt;&lt;li&gt;findtime: Die Zeit in Sekunden, in der die fehlgeschlagenen Logins erfolgen müssen. In unserem Fall müssen 5 Fehl-Logins innerhalb von 60 Sekunden vorkommen.&lt;/li&gt;&lt;/ul&gt; Dabei gibt das in eckigen Klammern geschriebene [exensio-demoapp] an, um welchen Filter es sich handelt. Ein Filter definiert, wie das Muster eines fehlgeschlagenen Logins aussieht. Nach unserem Beispiel in der Methode logFailedLogin() aus der &lt;b&gt;Grails&lt;/b&gt;-Applikation lautet der Pseudo Reguläre Ausdruck: &lt;pre class="java" name="code"&gt;[Definition]&lt;br /&gt;failregex = Failed login attempt for IP: &lt;HOST&gt;&lt;br /&gt;ignoreregex = &lt;br /&gt;&lt;/pre&gt;Die Datei kopieren wir in das filter.d-Verzeichnis von fail2ban, zum Beispiel unter dem Namen exensio-demoapp.conf.  &lt;br/&gt;&lt;br/&gt;&lt;h3&gt;Fail2Ban-Log überprüfen&lt;/h3&gt;Das Fail2Ban-Log-File unter /var/log/fail2ban.log registriert alle gebannten IPs und den Zeitpunkt, an welchem sie wieder freigeschalten wurden.  &lt;pre class="java" name="code"&gt;&lt;br /&gt;2012-05-07 08:28:35,427 fail2ban.jail   : INFO   Creating new jail 'exensio-demoapp'&lt;br /&gt;2012-05-07 08:28:35,427 fail2ban.jail   : INFO   Jail 'exensio-demoapp' uses poller&lt;br /&gt;2012-05-07 08:28:35,438 fail2ban.filter : INFO   Added logfile = /var/log/exensio-demoapp/failedlogins.log&lt;br /&gt;2012-05-07 08:28:35,439 fail2ban.filter : INFO   Set maxRetry = 5&lt;br /&gt;2012-05-07 08:28:35,440 fail2ban.filter : INFO   Set findtime = 60&lt;br /&gt;2012-05-07 08:28:35,440 fail2ban.actions: INFO   Set banTime = 600&lt;br /&gt;2012-05-07 08:28:35,446 fail2ban.jail   : INFO   Jail 'exensio-demoapp' started&lt;br /&gt;2012-05-07 08:28:45,458 fail2ban.actions: WARNING [exensio-demoapp] Ban 192.168.11.30&lt;br /&gt;2012-05-07 08:38:45,466 fail2ban.actions: WARNING [exensio-demoapp] Unban 192.168.11.30&lt;br /&gt;&lt;/pre&gt; &lt;h2&gt;Fazit&lt;/h2&gt;Fail2Ban ist ein einfaches Tool, um Dienste zusätzlich zu schützen und Log-Files übersichtlich zu halten. Es kann in seiner Standard-Konfiguration verwendet werden, um populäre Applikationen wie SSH, Apache, Tomcat, Courier-Imap oder zum Beispiel FTP-Server wie ProFTP oder PureFTP zu sichern. Wie in diesem Beitrag gezeigt wurde, lässt sich darüber hinaus mit wenig Aufwand auch die eigene Grails-Applikation absichern.&lt;br/&gt;Bei der Konfiguration ist jedoch zu beachten, dass eine IP in großen Unternehmen für viele Mitarbeiter gleich ist und so die Anzahl von 'maxRetry' nicht zu klein gewählt werden sollte. Ansonsten wird das ganze Unternehmen für einige Zeit ausgesperrt. &lt;br/&gt;&lt;br/&gt;&lt;h2&gt;Links&lt;/h2&gt;[1] &lt;a href="http://www.fail2ban.org/wiki/index.php/Main_Page"&gt;Fail2Ban Dokumentation&lt;/a&gt;&lt;br/&gt;[2] &lt;a href="http://grails.org/plugin/spring-security-core"&gt;Grails Spring Security Core Plugin&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-1679018207868227070?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/Zr2xg668sY4/grails-applikation-mit-fail2ban.html</link><author>noreply@blogger.com (Manuel Breitfeld)</author><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/05/grails-applikation-mit-fail2ban.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-4164259227349567156</guid><pubDate>Tue, 01 May 2012 11:36:00 +0000</pubDate><atom:updated>2012-05-01T13:36:58.909+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">MySQL</category><category domain="http://www.blogger.com/atom/ns#">Apache Webserver</category><category domain="http://www.blogger.com/atom/ns#">Tomcat</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Teil 3 - Grails in Produktion – mit Apache, Tomcat und MySQL</title><description>&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-oqfGOERpYZg/T5wOrKnvWPI/AAAAAAAAAcM/kVBDbyG9dNg/s1600/grails_tomcat.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="48" src="http://4.bp.blogspot.com/-oqfGOERpYZg/T5wOrKnvWPI/AAAAAAAAAcM/kVBDbyG9dNg/s200/grails_tomcat.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;In diesem Teil &amp;nbsp;meiner Blog-Serie zum Thema &lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt; in Produktion möchte ich auf die Konfigurationsmöglichkeiten eines Tomcat-Clusters eingehen (hier der Link zu &lt;a href="http://blog.exensio.de/2012/03/teil-2-grails-in-produktion-mit-apache.html"&gt;Teil 2&lt;/a&gt; und &lt;a href="http://blog.exensio.de/2012/02/teil-1-grails-in-produktion-mit-apache.html"&gt;Teil 1&lt;/a&gt;). &amp;nbsp;Dieser Teil meiner Blog-Serie mag für manche vielleicht der interessanteste sein. Ich werde auch ab und zu einen Vergleich zum Oracle WebLogic Server herstellen, da ich selbst einmal als Systemberater für BEA (bevor BEA von Oracle gekauft wurde) tätig war. Bei einem Cluster stellt sich gleich folgende Frage:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;In-Memory-Session-Replication oder „nur” Load-Balancing der HTTP-Requests?&lt;/b&gt;&lt;br /&gt;Zunächst einmal möchte ich die Unterschiede beschreiben. Der Vorteil bei In-Memory-Session-Replication liegt darin, dass sich ein User – falls ein Tomcat abstürzt – sich nicht erneut einloggen muss, da die Informationen der HTTP-Session bereits auf den Backup-Server repliziert wurden. Beim einfachen Load-Balancing wird nur die Last (Anmerkung: auch beim In-Memory-Session-Replication wird die Last auf die Tomcat-Server eines Clusters verteilt) auf die unterschiedlichen Tomcat-Server eines Clusters verteilt.&lt;br /&gt;&lt;br /&gt;Bei der In-Memory-Session-Replication wird von einem Tomcat-Server die Daten des HTTP-Session-Objekts vom Primär- zum Backup-Server über das Netzwerk repliziert &lt;i&gt;(Anmerkung: es gibt auch noch die Möglichkeit, eine Datenbank zur Replikation zu benutzen, dieser Weg ist jedoch nicht sehr performant)&lt;/i&gt;. Tomcat unterstützt erst seit Version 5 die Replikation von Primär- zu Backup-Server (dies haben sich die Tomcat Entwickler vom WebLogic Server abgeschaut). Davor replizierte ein Tomcat-Server seine HTTP-Sessions zu allen Tomcats innerhalb eines Clusters. Dies hatte enorme Auswirkungen auf die Netzwerklast und somit auf die Gesamtperformanz des Tomcat-Clusters. Um es gleich vorweg zu nehmen, ist In-Memory-Session-Replication die komplexere Systemkonstellation. Es gibt noch einen einfacheren Weg, in dem „nur“ die HTTP-Requests zwischen den Tomcat-Servern eines Clusters verteilt werden (Load-Balancing).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Was nimmt man nun am besten für eine Grails-Web-Applikation?&lt;/b&gt;&lt;br /&gt;Wir von exensio benutzen eigentlich nur das einfache Load-Balancing, da für die In-Memory-Session-Replication bereits bei der Entwicklung einiges beachtet werden muss. Die meisten unserer Kunden sind nicht gewillt, diesen Mehrpreis zu zahlen, nur damit der User einen transparenten Fail-Over erhält, sprich sich nicht erneut einloggen muss. Folgendes muss beachtet werden:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Alle Objekte, die in der HTTP-Session gespeichert werden müssen serialisierbar (von java.io.Serializable erben) sein. Dies ist per se kein Problem, jedoch habe ich es schon öfters in Projekten erlebt, dass dann doch die eine oder andere Hashmap ein nicht serialisierbares Objekt enthält.&lt;/li&gt;&lt;li&gt;Die HTTP-Session darf nicht größer als 50-70 KByte sein. &amp;nbsp;Hier auch wieder, eigentlich kein Problem, aber auch hier habe ich schon einiges erlebt. Es war dann doch eine Hashmap im HTTP-Session-Objekt, die beispielsweise die Ergebnisse einer Datenbankabfrage enthielt.&lt;/li&gt;&lt;li&gt;Wie gewährleisten wir die Idempotenz, wenn unser Service auf dem Backup-Server erneut aufgerufen wird. Einfaches Beispiel, wir haben in einem Grails-Controller eine Action die zweimal eine save() Methode nacheinander auf unterschiedliche Grails-Domian-Klassen ausführt. Würde es nun zwischen diesen beiden save() Aufrufen zu einem Absturz eines Tomcat-Servers kommen, so würde die Grails-Controller-Action dann erneut auf dem Tomcat-Backup-Server ausgeführt werden. In diesem Fall würde die erste save() Methode erneut ausgeführt werden. Aus unserer Erfahrung heraus ist es gar nicht so einfach, Grails-Actions oder Grails-Services idempotent zu schreiben.&lt;/li&gt;&lt;/ul&gt;Aus den oben aufgeführten Gründen setzen wir unsere Tomcat-Cluster immer nur mit einfachem Load-Balancing auf. Aus meiner Zeit bei BEA weiß ich noch, dass die meisten Kunden (nachdem das Geld nach der Euphorie des Jahrtausendwechsels wieder knapper wurde) auch nur das Load-Balancing benutzt haben. Mich würde hier natürlich interessieren, wie die Meinung anderer zum Thema Grails im Tomcat-Cluster aussieht.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Installation des Tomcat-Clusters&lt;/b&gt;&lt;br /&gt;Hier gibt es verschiedene Möglichkeiten. Da bei unseren Kundenprojekten das Hosting meistens durch einen professionellen Hosting-Provider, mit dem der Kunde bereits zusammenarbeitet, übernommen wird, müssen wir uns nicht um die Installation kümmern. Es ist hier jedoch wichtig darauf hinzuweisen, dass jeder Tomcat in einem eigenen Java-Prozess laufen soll und nicht als virtueller Server &amp;nbsp;(verwaltet über die Tomcat-Management-Applikation host-manager). In diesem Fall teilen sich alle Tomcats (obwohl sie über einen eigenen Port etc. verfügen können) einen Java-Prozess. Eine fehlerhafte Grails-Web-Applikation würde dann den gesamten Tomcat herunterreißen. Wer sich um die Installation selber kümmern muss, dem können folgende URLs empfohlen werden [1][2][3].&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Anmerkung: Die einfachste Form der Installation ist einen Tomcat für jeden Java-Prozess zu installieren. Der physikalische Server enthält dann zwei Tomcat-Verzeichnisse (z.B. srv1 und srv2). Die oben erwähnten Skripte hingegen teilen den Tomcat in einen generellen und serverabhängigen Bereich auf (z.B. &amp;nbsp;common, srv1 und srv2). Der Teil, der in das common-Verzeichnis kommt, kann sich von Version zu Version des Tomcats unterscheiden. Deshalb ist bei diesen Skripten immer zu überprüfen, ob sie mit der benutzten Tomcat-Version funktionieren.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JVM Settings&lt;/b&gt;&lt;br /&gt;Wir benutzen meistens nur leicht modifizierte Standardeinstellungen der JVM für unsere Grails-Applikationen. Die Erfahrung hat gezeigt, dass es nicht zwingend besser ist die JVM extrem zu tunen. Mit folgenden Einstellungen haben wir bisher ganz gute Erfahrungen gemacht:&lt;br /&gt;&lt;pre class="java" name="code" style="display: none;"&gt;JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m&lt;br /&gt;-Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DisableExplicitGC -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;Anmerkung: &amp;nbsp;die beiden letzten Parameter dienen dazu, dass der PermGenSpace wieder freigegeben wird. Je nach Grails-Applikation mögen diese Parameter nicht nötig sein.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;JDBC Connection Pool&lt;/b&gt;&lt;br /&gt;Es ist sinnvoll, den JDBC Connection Pool des Tomcat-Servers zu benutzen. Dieser verfügt über bessere Pooling-Eigenschaften, als der standardmäßig in einer Grails-Applikation (Grails Commons DBCP Pool) benutzte. &amp;nbsp;Des Weiteren kann sehr einfach eine neue Datenbank konfiguriert werden, ohne Code an der Grails Applikation ändern zu müssen. In der Grails Applikation muss folgendes in der DataSource.groovy eingefügt werden.&lt;br /&gt;&lt;pre class="xml" name="code" style="display: none;"&gt;// environment specific settings&lt;br /&gt;environments {&lt;br /&gt;&amp;nbsp; ...&lt;br /&gt;&amp;nbsp; grails_production {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dataSource {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; jndiName &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= "java:comp/env/jdbc/grails_application"&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dialect &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = org.hibernate.dialect.MySQL5InnoDBDialect&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dbCreate &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= 'update'&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Unten habe ich eine unserer Standardkonfigurationen (zu ändern in conf/context.xml) eingefügt, mit der wir bisher gute Erfahrungen gemacht haben. Diese können sich natürlich von Projekt zu Projekt ändern.&lt;br /&gt;&lt;pre class="xml" name="code" style="display: none;"&gt;&lt;context&gt;&lt;br /&gt;&lt;watchedresource&gt;WEB-INF/web.xml&lt;/watchedresource&gt;&lt;br /&gt;&lt;manager pathname=""&gt;&lt;br /&gt;&lt;resource abandonwhenpercentagefull="50" auth="Container" driverclassname="com.mysql.jdbc.Driver" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" initialsize="10" logabandoned="true" maxactive="30" maxidle="20" minevictableidletimemillis="60000" minidle="10" name="jdbc/grails web application" password="xxx" removeabandoned="true" removeabandonedtimeout="60" testonborrow="true" timebetweenevictionrunsmillis="30000" type="javax.sql.DataSource" url="jdbc:mysql://xx.xx.xx.xx:9987/grails_web_application" username="xxx" validationinterval="30000" validationquery="SELECT 1"&gt;&lt;br /&gt;&lt;/resource&gt;&lt;/manager&gt;&lt;br /&gt;&lt;/context&gt;&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;Anmerkung: In unserer Konfiguration wird der Connection-Pool &amp;nbsp;zeitbasiert wieder verringert. Diese zeit-gesteuerte Anpassung der Pool-Größe kann zu Problemen führen, wenn die Connection im Tomcat schon weg ist, aber in MySQL aufgrund des eingestellten Timeouts noch aktiv ist. In diesem Fall wird eine neue Session auf dem MySQL-Server angelegt und dies kann unter Umständen dazu führen, dass die auf dem MySQL-Server eingestellten Connections (MySQL Parameter max_connections) überschritten wird. Aus diesem Grund sollte die maximale Anzahl der Connections über einen Last-Test ermittelt werden und zum Go-Live etwas höher sein. Nach dem Go-Live kann man über das Monitoring [4] eine genauere Größe ermitteln.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Der MySQL JDBC Driver (beispielsweise mysql-connector-java-5.1.10-bin.jar) muss nach tomcat/lib kopiert werden.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Konfiguration der Tomcat-Ports&lt;/b&gt;&lt;br /&gt;Wichtig hierbei ist, dass jeder Tomcat über eigene Ports verfügt, da wir ja 1..n Tomcats auf einem physikalischen Rechner haben. Folgende Werte müssen in der server.xml gesetzt werden: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;AJP Connector Ports &lt;pre class="xml" name="code" style="display: none;"&gt;&lt;connector port="9008" protocol="AJP/1.3" redirectport="9448" uriencoding="UTF-8"&gt;&lt;br /&gt;&lt;/connector&gt;&lt;/pre&gt;Hierbei ist wichtig, dass auch das URIEncoding (&lt;i&gt;Vorsicht: der Code-Formatter hat oben URIEncoding in Kleinbuchstaben gewandelt&lt;/i&gt;) gesetzt wird. Falls nicht werden deutsche Umlaute in einem Formular auf einer .gsp Seite nicht richtig übermittelt.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Server-Ports &lt;pre class="xml" name="code" style="display: none;"&gt;&lt;server debug="0" port="9018" shutdown="SHUTDOWN"&gt;&lt;br /&gt;&lt;/server&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;HTTP Connector Ports (für Admin-Konsole) &lt;pre class="xml" name="code" style="display: none;"&gt;&lt;connector connectiontimeout="20000" maxthreads="150" port="9088" protocol="HTTP/1.1" redirectport="9588" uriencoding="UTF-8"&gt;&lt;br /&gt;&lt;/connector&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Jeder Tomcat Server braucht ein jvmRoute Setting, dieses wird an die SessionID angehängt und muss mit denen in der worker.properties (Apache WS) übereinstimmen.&lt;br /&gt;&lt;pre class="xml" name="code" style="display: none;"&gt;&lt;engine defaulthost="localhost" jvmroute="svr1" name="Catalina"&gt;&lt;br /&gt;&lt;/engine&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Deployment der Grails-Web-Applikation&lt;/b&gt;&lt;br /&gt;Generell stoppen wir hierzu den Tomcat, löschen die Grails-Web-Applikation im webapps-Verzeichnis (z.B. Grails_App.war und das Verzeichnis Grails_App/) kopieren die neue Version der Grails-Web-Applikation in das webapps-Verzeichnis und starten dann wieder den Tomcat. Dies geht natürlich auch alles ohne den Restart, aber mit dem oben beschrieben Weg haben wir die besseren Erfahrungen gemacht.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Monitoring&lt;/b&gt;&lt;br /&gt;Das Monitoring in einer Produktions-Umgebung wird meistens durch Nagios abgedeckt. Für die Last-Tests setzen wir hingegen sehr gerne PSI-Probe [5] ein. Für ein passendes Monitoring-Tool mussten wir eine Weile suchen, da wir hier vom Oracle WebLogic-Server sehr verwöhnt waren, wir denken jedoch, dass PSI-Probe vergleichbar ist. PSI-Probe basiert auf Lambda-Probe, jedoch ist Lambda-Probe veraltet. Mit PSI-Probe kann man sehr viele interessante Werte, wie Anzahl HTTP-Session, JDBC-Sessions, Java-Heap, Java-PermGenSpace etc. analysieren. Unten habe ich noch ein paar Screen-Shots von PSI-Probe angehängt.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-x2Ax6cXMEko/T5wWEBmdeBI/AAAAAAAAAcY/MVv2Om9MHZ0/s1600/grails_psi_probe_04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="206" src="http://2.bp.blogspot.com/-x2Ax6cXMEko/T5wWEBmdeBI/AAAAAAAAAcY/MVv2Om9MHZ0/s320/grails_psi_probe_04.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-D1XE8IclSsM/T5wWIlJIzrI/AAAAAAAAAcg/kBYDMCLY8jQ/s1600/grails_psi_probe_03.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="206" src="http://3.bp.blogspot.com/-D1XE8IclSsM/T5wWIlJIzrI/AAAAAAAAAcg/kBYDMCLY8jQ/s320/grails_psi_probe_03.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-5Q8Zhv_-yBw/T5wWNLTp4II/AAAAAAAAAco/UNlgNHSWluY/s1600/grails_psi_probe_02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="206" src="http://1.bp.blogspot.com/-5Q8Zhv_-yBw/T5wWNLTp4II/AAAAAAAAAco/UNlgNHSWluY/s320/grails_psi_probe_02.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-fKndcqHE-qQ/T5wWQ3Sd5CI/AAAAAAAAAcw/VwIqL_VYZ9M/s1600/grails_psi_probe_01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="206" src="http://3.bp.blogspot.com/-fKndcqHE-qQ/T5wWQ3Sd5CI/AAAAAAAAAcw/VwIqL_VYZ9M/s320/grails_psi_probe_01.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Links&lt;/b&gt;&lt;br /&gt;[1] Clustering Grails - Burt Beckwith - &lt;a href="http://burtbeckwith.com/blog/?p=244"&gt;http://burtbeckwith.com/blog/?p=244&lt;/a&gt;&lt;br /&gt;[2] Basic Apache Tomcat clustering for Grails applications - &lt;a href="http://www.tomcatexpert.com/blog/2010/07/20/basic-tomcat-clustering-grails-applications"&gt;Peter Ledbrook&lt;/a&gt;&lt;br /&gt;[3] Tomcat Cluster Scripts -&lt;a href="https://github.com/acreeger/grails-tomcat-cluster-scripts"&gt; https://github.com/acreeger/grails-tomcat-cluster-scripts&lt;/a&gt;&lt;br /&gt;[4] Nagios - &lt;a href="http://www.nagios.org/"&gt;http://www.nagios.org&lt;/a&gt;&lt;br /&gt;[5] PSI-Probe - &lt;a href="http://code.google.com/p/psi-probe"&gt;http://code.google.com/p/psi-probe&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-4164259227349567156?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/6TOIIwERZRY/teil-3-grails-in-produktion-mit-apache.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-oqfGOERpYZg/T5wOrKnvWPI/AAAAAAAAAcM/kVBDbyG9dNg/s72-c/grails_tomcat.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/05/teil-3-grails-in-produktion-mit-apache.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-5353317251711439686</guid><pubDate>Fri, 27 Apr 2012 13:38:00 +0000</pubDate><atom:updated>2012-04-27T15:44:57.338+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">exensio</category><title>exensio GmbH ist Silber Sponsor des BarCamp 2012 in Karlsruhe</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-6Yol37FzQdQ/T5qfbLJyaUI/AAAAAAAAAcA/dh3eopkWByg/s1600/barcamp_karlsruhe.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-6Yol37FzQdQ/T5qfbLJyaUI/AAAAAAAAAcA/dh3eopkWByg/s1600/barcamp_karlsruhe.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Seit heute ist es offiziell, wir unterstützen das diesjährige BarCamp [1], das am 14. und 15. Juli 2012 hier in Karlsruhe stattfindet. Ein Barcamp wird auch häufig als Unkonferenz bezeichnet, da es – im Vergleich zu einer gewöhnlichen Konferenz - kein vorgefertigtes Programm gibt. Die Inhalte und der Ablauf werden erst bei Konferenzbeginn von den Teilnehmern selbst erstellt. Weitere Infos finden sich in Wikipedia[2].&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Aber warum unterstützt exensio das Barcamp?&lt;/b&gt;&lt;br /&gt;Zum einen erhalten wir hierdurch natürlich etwas Sichtbarkeit in der Öffentlichkeit, was uns bei der Suche nach neuen Mitarbeitern oder vielleicht auch Kunden helfen kann. Wir finden jedoch ehrlich gesagt die Idee eines Barcamps sehr interessant. Hierdurch ist eine neue Form des Gedankenaustauschs möglich.&lt;br /&gt;Bei den Anbietern von &amp;nbsp;Konferenzen zu IT-Themen ist eine gewisse Monopolisierung unübersehbar. So leiern immer die gleichen Präsentatoren (von den großen Anbietern bzw. Softwarehäusern) mantraartig Ihre Folien herunter und das bei hohen Preisen. Bei einem Barcamp hingegen entscheidet die Gruppe, welche Themen für sie interessant sind.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fazit&lt;/b&gt;&lt;br /&gt;Wir freuen uns schon auf das Barcamp 2012 hier in Karlsruhe. &amp;nbsp;Und natürlich ein dickes Lob an das Orga-Team, das solch ein Event - mit viel Einsatz - erst ermöglicht.&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://www.barcamp-karlsruhe.de/"&gt;http://www.barcamp-karlsruhe.de&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://de.wikipedia.org/wiki/Barcamp"&gt;http://de.wikipedia.org/wiki/Barcamp&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-5353317251711439686?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/A_gQVxLIOG4/exensio-gmbh-ist-silber-sponsor-des.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-6Yol37FzQdQ/T5qfbLJyaUI/AAAAAAAAAcA/dh3eopkWByg/s72-c/barcamp_karlsruhe.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/04/exensio-gmbh-ist-silber-sponsor-des.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3501400332486872255</guid><pubDate>Mon, 09 Apr 2012 10:18:00 +0000</pubDate><atom:updated>2012-04-10T09:48:51.368+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">GORM</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Erfahrungen bei der Migration von Grails 1.3.x nach 2.0.x</title><description>Nachdem für das &lt;a href="http://www.grails.org/" target="_blank"&gt;Grails&lt;/a&gt;-Framework die Version 2.0 im Dezember 2011 freigegeben wurde, stellt sich für bestehende Projekte, die auf älteren Grails-Versionen realisiert bzw. begonnen wurden, die Frage nach der Migration. Die Analyse, ob sich eine Migration lohnt muss für jedes Projekt individuell durchgeführt werden, da ein entsprechender Aufwand dahinter steckt. Klar ist aber auch, dass Projekte, die noch länger laufen und weiterentwickelt werden an einer Migration kaum vorbeikommen.  &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Warum  sollte man migrieren?&lt;/h2&gt;&lt;br /&gt;Wie im User Guide [1] beschrieben gibt es mit Grails 2.0 zahlreiche Neuerungen, die entsprechende Mehrwerte bieten. Außerdem ist davon auszugehen, dass neue Plugins sowie die Weiterentwicklungen bestehender Plugins auf die Version 2.x setzen. Damit würden diese nicht zur Verfügung stehen, bzw. müssten selbst auf Tauglichkeit für ältere Version angepasst und getestet werden.  &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Was ist zu beachten bei der Migration?&lt;/h2&gt;&lt;br /&gt;Auf unserem Blogeintrag &lt;a href="http://blog.exensio.de/2012/02/grails-20-upgrade-guide.html"&gt;Grails 2.0 Upgrade Guide&lt;/a&gt; sind die entsprechenden Seiten zusammengefasst, mit denen man auf jeden Fall vor Beginn der Migration auseinandersetzen sollte. Darüber hinaus sind die Informationen über Änderungen, die potentiell zu Problemen nach der Migration führen, im Grails User Guide [2] hilfreich.  &lt;br /&gt;&lt;br /&gt;Neben dem geplanten Bug-Fix Release 2.0.1 gab es in den letzten Tagen zwei weitere Bug-Fix-Releases, so dass zwischenzeitlich die aktuellste Version 2.0.3 ist [3]. Mit dem Release 2.0.2 wurde eine erhebliche Security-Lücke im Bereich des Data-Binding behoben [4]. Leider schlichen sich auch ein paar gravierende Probleme mit Domain-Klassen und Entwicklungsumgebungen ein, so dass kurze Zeit später die Version 2.0.3 herausgebracht wurde. &lt;br /&gt;&lt;br /&gt;Wenn eine Migration ansteht sollte man deshalb unbedingt auf die momentan aktuellste Grails-Version 2.0.3 migrieren.  &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Fallen und Probleme bei der Migration&lt;/h2&gt;&lt;br /&gt;Nachfolgend werden Hinweise gegeben und auf Probleme eingegangen, die im Rahmen von Migrationen bei exensio aufgetreten sind. Es wird nur auf ausgewählte Fälle eingegangen, da es viele Hinweise schon im Upgrade-Guide gibt.   &lt;br /&gt;&lt;br /&gt;&lt;b&gt;DataSource.groovy&lt;/b&gt;&lt;br /&gt;Wurde bisher für Entwicklung oder Tests die mitgelieferte HSQL Datenbank verwendet, dann sollte nach Möglichkeit durch Anpassung der Settings in der Datei &lt;i&gt;DataSource.groovy&lt;/i&gt; auf die H2 Datenbank gewechselt werden. Mit H2 kann die DB-Konsole direkt aus der Grails-Webapplikation aufrufen werden. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;executeQuery Methode&lt;/b&gt;&lt;br /&gt;Schon in älteren Grails-Versionen wurde angekündigt, dass zukünftig in Domain-Klassen für die executeQuery-Methode die Parameter nicht mehr als String übergeben werden können. Mit der Version 2.0 änderte sich die Methoden-Signatur endgültig.  &lt;br /&gt;&lt;pre class="java" name="code"&gt;def rev = Template.executeQuery('from Template t where t.ui = ? and t.revision = (select max(tMax.revision) from Template tMax where tMax.ui = ? ) ', ui, ui)&lt;br /&gt;&lt;/pre&gt;Die Migration erfolgt hier einfach, in dem die Parameter wie nachfolgend aufgezeigt als Liste übergeben werden: &lt;br /&gt;&lt;pre class="java" name="code"&gt;def rev = Template.executeQuery('from Template t where t.ui = ? and t.revision = (select max(tMax.revision) from Template tMax where tMax.ui = ? ) ', [ui, ui])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;groovyPagesTemplateEngine&lt;/b&gt;&lt;br /&gt;In Services wird die Variable &lt;i&gt;groovyPagesTemplateEngine&lt;/i&gt; über Spring injiziert und kann für das Erzeugen von Page-Templates verwendet werden. Aus den Templates können wiederum entsprechende GSP-Seiten erzeugt werden. Bei einem migriertem Projekt wird von diesem Mechanismus intensiv Gebrauch gemacht und die entsprechenden Service-Methoden werden von Controllern und Taglibs aufgerufen. Nach der Migration startete allerdings der Server aufgrund von Initialisierungs-Problemen der Variable groovyPagesTemplateEngine durch Spring nicht mehr.  &lt;br /&gt;&lt;br /&gt;Lösung war hier die Variable &lt;i&gt;groovyPagesTemplateEngine&lt;/i&gt; nicht mehr in den Services zu deklarieren. Stattdessen wird, wie nachfolgend dargestellt, die TemplateEngine in einer  Helper-Klasse erzeugt und kann von den Services abgefragt werden. &lt;br /&gt;&lt;pre class="java" name="code"&gt;public synchronized static GroovyPagesTemplateEngine getEngine() {&lt;br /&gt;  if (engine == null) {&lt;br /&gt;    engine = getApplicationContext().getBean(GroovyPagesTemplateEngine.BEAN_ID)&lt;br /&gt;  }&lt;br /&gt;  return engine&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Transiente Attribute in Domain-Klassen&lt;/b&gt;&lt;br /&gt;Bedingt durch die Behebung der Sicherheitslücke in Grails 2.0.2 fließen transiente, statische oder dynamisch getypte Variablen in Domain-Klassen standardmäßig nicht mehr in das Data-Binding ein. Um dennoch ein Data-Binding zu erreichen steht, wie unten beispielhaft skizziert, das Attribut &lt;i&gt;bindable&lt;/i&gt; zur Verfügung. &lt;br /&gt;&lt;pre class="java" name="code"&gt;def attachment&lt;br /&gt;static transients = ['attachment']&lt;br /&gt;static constraints = {&lt;br /&gt;  attachment bindable: true // Required since Grails 2 for tranisent attributes&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;afterInterceptor&lt;/b&gt;&lt;br /&gt;Über den &lt;i&gt;afterInterceptor&lt;/i&gt; [5] kann in Controller-Actions  nach deren Aufruf eingegriffen werden. Bei einer bestehenden exensio-Applikation wurde bisher im &lt;i&gt;afterInterceptor&lt;/i&gt; unter bestimmten Bedingungen ein Redirect durchgeführt.  &lt;br /&gt;&lt;pre class="java" name="code"&gt;def runAfterAction (model, modelAndView) {&lt;br /&gt;  // Redirect&lt;br /&gt;  if(model.redirectParams) {&lt;br /&gt;    redirect( model.redirectParams )&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Nach Durchführung der Migration funktionierte der Redirect nicht mehr, bzw. führte nicht auf die gewünschten Controller. Das Problem konnte nur gelöst werden, in dem der Redirect aus dem &lt;i&gt;afterInterceptor&lt;/i&gt; entfernt wurde und direkt am Ende der betroffenen Actions eingefügt wurde.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Abstrakte Domain-Klassen&lt;/b&gt;&lt;br /&gt;Eine wesentliche Änderung mit Grails 2.0 ist der Umgang mit Vererbung innerhalb von Domain-Klassen. Eine abstrakte Vater-Klasse resultiert ab Grails 2.0 in einer eigenen Datenbank-Tabelle. Damit würde sich für eine migrierte Applikation das Datenbankschema ändern, was in der Regel unerwünscht ist. Außerdem machen für neu erstellte Grails 2.0 Anwendungen zentrale Vaterklassen durchaus Sinn, die nicht in einer separaten Tabelle resultieren. In diesen Klassen können bspw. Attribute wie der Version-Count, das Erstellungs- oder Änderungsdatum modelliert werden. Diese Attribute sollen direkt als Spalten in der Datenbank-Tabelle der eigentlichen Domain-Klasse resultieren, um zusätzliche JOINS zu vermeiden. &lt;br /&gt;&lt;br /&gt;Dies kann einfach erreichr werden durch Ablage der abstrakten Domain-Klassen im src-Verzeichnis anstatt im Domain-Klassen-Verzeichnis.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Generieren von Links&lt;/b&gt;&lt;br /&gt;In bestimmten Fällen ist es notwendig in Services Links zu generieren. Dies war bisher ziemlich umständlich, da die TagLibrary entsprechend im Service verfügbar gemacht werden musste, um dann den entsprechenden Aufruf für die Generierung durchführen zu können: &lt;br /&gt;&lt;pre class="java" name="code"&gt;def href = g.createLink(controller:'content', action:'show', id:c.id)&lt;br /&gt;&lt;/pre&gt;Ab Grails 2.0 geht dies eleganter über die Variable LinkGenerator, die über Spring direkt injiziert wird.  &lt;br /&gt;&lt;pre class="java" name="code"&gt;def href = grailsLinkGenerator.link(controller:'content', action:'show', id:c.id)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Fazit&lt;/h2&gt;&lt;br /&gt;Die Migration ist bei größeren Projekten kein Selbstläufer und muss entsprechend eingeplant werden. Es gibt viele Hilfestellungen, man muss aber auch damit rechnen auf Probleme stoßen zu denen man im ersten Moment keine direkte Hilfe im Netz findet.  &lt;br /&gt;Nichtsdestotrotz macht die Version 2.0.3 jetzt einen stabilen Eindruck auf die man migrieren kann. Für den 30. April ist bereits Grails 2.1 angekündigt. Laut Jira sind für dieses Release aktuell ca. 100 Erweiterungen und Bugfixes vorgesehen. Dies zeigt, dass die Weiterentwicklung stetig voran schreitet und spätestens dann sollte man sich mit dem Thema der Migration befassen.   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://grails.org/doc/2.0.x/guide/introduction.html#whatsNew" target="_blank"&gt;Neuerungen in Grails 2.0&lt;/a&gt; &lt;br /&gt;[2] &lt;a href="http://grails.org/doc/latest/guide/gettingStarted.html#upgradingFromPreviousVersionsOfGrails" target="_blank"&gt;Upgrading from previous versions of Grails&lt;/a&gt; &lt;br /&gt;[3] &lt;a href="http://www.grails.org/blog/view/admin/Grails+2.0.3+Released" target="_blank"&gt;Grails 2.0.3 Release Ankündigung&lt;/a&gt; &lt;br /&gt;[4] &lt;a href="http://blog.springsource.org/2012/03/28/secure-data-binding-with-grails/" target="_blank"&gt;Secure data binding with Grails&lt;/a&gt; &lt;br /&gt;[5] &lt;a href="http://grails.org/doc/latest/ref/Controllers/afterInterceptor.html" target="_blank"&gt;afterInterceptor&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-3501400332486872255?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/VF6HTUvkeoI/erfahrungen-bei-der-migration-von.html</link><author>noreply@blogger.com (Tobias Kraft)</author><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/04/erfahrungen-bei-der-migration-von.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-4089275613686816119</guid><pubDate>Mon, 02 Apr 2012 05:16:00 +0000</pubDate><atom:updated>2012-04-04T21:01:22.121+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">socialmedia</category><category domain="http://www.blogger.com/atom/ns#">Konferenz</category><title>Impressionen von der SMX München 2012</title><description>Vergangene Woche habe ich am 27. und 28. März an der SMX - der Search Marketing Expo - 2012 in München teilgenommen. In diesem Blogbeitrag schildere ich meine Erfahrungen zur Konferenz im Allgemeinen und einige Erkenntnisse aus den einzelnen Vorträgen.&lt;br /&gt;Insgesamt wurden parallel in vier großen Räumen Vorträge zu unterschiedlichen Themengebieten rund um &lt;a href="http://de.wikipedia.org/wiki/Suchmaschinenoptimierung"&gt;SEO&lt;/a&gt; und &lt;a href="http://de.wikipedia.org/wiki/Suchmaschinenmarketing"&gt;SEA&lt;/a&gt; gehalten. Die Keynotes von &lt;a href="http://randfishkin.com/blog/"&gt;Rand Fishkin&lt;/a&gt;, &lt;a href="http://www.willcritchlow.com/"&gt;Will Critchlow&lt;/a&gt; und &lt;a href="http://www.xing.com/profile/Wolfgang_Henseler"&gt;Prof. Wolfgang Henseler&lt;/a&gt; fanden einzeln im großen Ballsaal statt.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://2.bp.blogspot.com/-w8HOpEdl0As/T3k5gpzooRI/AAAAAAAAAEg/zSXXY5m-fOM/s1600/smx-2012_keynote.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/-w8HOpEdl0As/T3k5gpzooRI/AAAAAAAAAEg/zSXXY5m-fOM/s320/smx-2012_keynote.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5726671634319319314" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Viral-Marketing-Perfektion und SEO-Katastrophe&lt;/h2&gt;&lt;br /&gt;Ein spannendes Beispiel zu tollem viralem Marketing und gleichzeitig nur mäßigem SEO nannte Rand in seiner Keynote. Dollarshaveclub verkauft Rasierer und hat mit &lt;a href="http://www.youtube.com/watch?v=ZUG9qYTJMsI"&gt;seinem Video auf Youtube&lt;/a&gt; fast 4 Millionen Views. Durch die losgetretene Welle kommt die Firma den ersten Bestellungen schon nicht mehr hinter her.&lt;br /&gt;Jedoch - sucht man nach typischen Keywords zum Thema "Rasierer, Rasierer monatlich, Rasierer im Abo, Rasierer für einen Dollar" befindet sich die Webseite nie unter den Top 10 in Google. (Aufgrund der Keynote und der Tatsache, dass das mittlerweile von vielen als Beispiel herangezogen wird, befindet sich die Firma tatsächlich doch indirekt unter den Top 10 - nämlich bei Blogs und Foren, die genau darüber berichten.)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;KML Sitemap für Local Searches&lt;/h2&gt;&lt;br /&gt;Mithilfe einer KML Sitemap erleichtert man Google das Auffinden des eigenen Unternehmens auf der Landkarte und ermöglicht so, dass bei der Suche nach dem Unternehmen auch gleich der passende Kartenausschnitt aus Google Maps angezeigt wird. Das ist zum einen hilfreich für den Nutzer, zum anderen wirkt dadurch der Suchtreffer in Google sofort "größer" und sticht eher ins Auge des Suchenden. Mehr dazu findet man bei Martijn Beijk und seinem Tutorial &lt;a href="http://www.martijnbeijk.com/tutorial/using-kml-for-local-seo/"&gt;KML and sitemaps for SEO – The definitive guide&lt;/a&gt; [1]. &lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Social Networks und Suche&lt;/h2&gt;&lt;br /&gt;In allen Vorträgen, in denen es um die soziale Komponente der heutigen Suchmaschinen ging, wurde betont, wie wichtig es ist, neue Beiträge auf Google+ zu teilen und/oder +1en. Zusätzlich helfen Twitter, Facebook, you name it... Interessant ist, dass eine auf Google+ geteilte URL sofort in den Google Index aufgenommen wird - diese Chance eines schnellen Indizierens sollte man sich also nicht entgehen lassen.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.google.com/plus/bin/answer.py?hl=en&amp;answer=1713320"&gt;Google+ Ripples&lt;/a&gt; [2] ist eine geniale Visualisierung von Google+ Shares - jeder Content in Google+ kann über Ripples gewissermaßen nachverfolgt werden: Ripples zeigt an, welche Circles den Content weitergeteilt haben, wer aus den Circles den größten Einfluss auf die Weiterverteilung hatte, usw. Genial! Einfach mal selbst bei einem beliebigen Beitrag ausprobieren. Auf seomoz wird &lt;a href="http://www.seomoz.org/blog/using-google-plus-ripples-to-connect-with-influencers"&gt;Ripples im Detail vorgestellt&lt;/a&gt; [3].&lt;br /&gt;&lt;br /&gt;Ein weiterer kleiner Tipp: Sind Ihnen die Personenbilder bei Top-Suchergebnissen in Google aufgefallen? Allein dadurch wird ein Link interessanter. Der Clue - das ist auch einfach für den eigenen Content zu erreichen. Das Stichwort heißt rel=author und Scott Hanselmann zeigt die &lt;a href="http://www.hanselman.com/blog/EmbraceAuthorshipTheImportanceOfRelmeAndRelauthorOnYourContentsSEOAndGoogle.aspx"&gt;Funktionsweise schön an einem Beispiel&lt;/a&gt; [4].&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Large Scale Linkbuilding&lt;/h2&gt;&lt;br /&gt;Die SEO-Gemeinde beschäftigt auch im Jahre 2012 noch die Frage, wie eine Webseite am meisten Links von wichtigen Domains bekommt. Interessante Vorschläge beinhalteten unter anderem:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Ausschreibung eines Stipendiums: Die Kosten sind berechenbar und eine Fülle an neuer Links ist gewiss. Dabei kommen die Links nicht "nur" von kleineren privaten Seiten - mit etwas Nachdruck bringt man auch die eher langsamer tickenden Universitäten dazu, auf das neue Stipendium zu verlinken. Mit geschicktem Marketing lassen sich natürlich noch weitere Kanäle bedienen.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Sponsoring von kleineren "Goodies": Mit dem Sponsoring von Stickern, Kugelschreibern, Blocks, USB-Sticks oder Schlüsselbändern für eine lokale Konferenz oder beispielsweise einem Barcamp sind die Kosten im moderaten Bereich - das Firmen-Logo und der Link zur Firmen-Website sind mindestens auf der Konferenz jedoch präsent.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;OpenGraph für Facebook&lt;/h2&gt;&lt;br /&gt;Damit die eigene Webseite auch in Facebook Shares gut aussieht, sollte man sich mit &lt;a href="https://developers.facebook.com/docs/opengraph/"&gt;OpenGraph&lt;/a&gt; [5] beschäftigen. Damit lässt sich steuern, welches Bild, welcher Titel und welche sonstigen Meta-Informationen in Facebook angezeigt werden, wenn Content der eigenen Webseite geshared wird. Auf BlueGlass gibt es dazu die &lt;a href="http://www.blueglass.com/blog/unraveling-facebook-open-graph-part-1/"&gt;perfekte Anleitung&lt;/a&gt; [6].&lt;br /&gt;Weitere interessante Möglichkeiten der Facebook APIs sind unter anderem auch, dass man die Interaktion eines Nutzers auf der eigenen Unternehmenswebseite auf dessen News Stream in Facebook pushen kann. Als Beispiel seien hier Zeitungen, allen voran der &lt;a href="http://www.guardian.co.uk/"&gt;Guardian&lt;/a&gt;, genannt: Habe ich in Facebook erlaubt, dass der Guardian, die von mir gelesenen Artikel auf meiner Facebook-Seite publizieren darf, wird dies fortan mit allen Artikeln gemacht - stets mit Link zurück zum Artikel. Das klingt auf den ersten Blick vielleicht etwas schräg, es sollte aber schnell klar werden, dass der Guardian damit ungemein viele potentielle neue Leser erhält. Nämlich mindestens jeden meiner Freunde. Und sobald einer meiner Freunde das gleiche macht, spannt sich der Netzwerk-Graph weiter,...&lt;br /&gt;Das Beispiel macht natürlich in dieser Weise nur für Zeitungen Sinn. Andere Szenarien wären das Anschauen eines Videos, einer Präsentation oder ähnliches. Ganz nach dem Motto: &lt;i&gt;Max Mustermann schaut gerade das Video "Grails in Produktion - Teil 1" auf &lt;a href="http://www.exensio.de"&gt;exensio.de&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;SMX After Dark&lt;/h2&gt;&lt;br /&gt;Der erste Tag der SMX schloss mit dem Beginn der SMX After Dark auf der Praterinsel ab. Die Party war riesig und das folgende Bild zeigt eine der vielen Tanzflächen ganz zu Beginn der Veranstaltung - später waren sie alle voll, die Tanzflächen. ;-)&lt;br /&gt;&lt;a target="_blank" href="http://2.bp.blogspot.com/-8rIDgwYYUq0/T3lFbfpZieI/AAAAAAAAAEs/22SoKP7Tq1o/s1600/smx-2012_praterinsel-after-dark-party1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/-8rIDgwYYUq0/T3lFbfpZieI/AAAAAAAAAEs/22SoKP7Tq1o/s320/smx-2012_praterinsel-after-dark-party1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5726684739832220130" /&gt;&lt;/a&gt;&lt;br /&gt;Da gleichzeitig zur SMX auch die &lt;a href="http://www.internetworld-messe.de/"&gt;E-Commerce Messe Internet World&lt;/a&gt; in München stattfand, waren viele Internet-affine Leute auf die After-Party gegangen, die sich nett bei dem ein oder anderen Drink und dem köstlichen Essen austauschen konnten.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Fazit&lt;/h2&gt;&lt;br /&gt;Für mich persönlich war die SMX 2012 interessant und hatte viel an Informationen zu bieten, was ich so in der Form noch nicht kannte. Der Fokus liegt stark auf SEO und SEA und somit dreht sich im Prinzip alles um Google und/oder Bing. Die meisten Besucher kommen daher auch aus den Bereichen des Online Marketings oder ganz speziell der SEO-Abteilung.&lt;br /&gt;Schade war, dass das ganze Thema Enterprise Search in keiner Session erwähnt wurde.&lt;br /&gt;&lt;br /&gt;&lt;a target="_blank" href="http://3.bp.blogspot.com/-BxbDZLsyTtY/T3lHg8oUPbI/AAAAAAAAAE4/dwF2T2D72xU/s1600/smx-2012_praterinsel-after-dark-party2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/-BxbDZLsyTtY/T3lHg8oUPbI/AAAAAAAAAE4/dwF2T2D72xU/s320/smx-2012_praterinsel-after-dark-party2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5726687032534908338" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Weitere Berichte zur SMX 2012 in München&lt;/h2&gt;&lt;br /&gt;SMX München 2012 Recap: &lt;a href="http://www.121watt.de/blog/5402/smx-munchen-recap-2012/"&gt;121WATT: SMX München 2012 Recap&lt;/a&gt;&lt;br /&gt;SMX Recap 2012: &lt;a href="http://www.mindshape.de/blog/seo/smx-recap-2012.html"&gt;Mindshape: SMX Recap 2012&lt;/a&gt;&lt;br /&gt;Recap &amp; Faszinationspunkte: &lt;a href="http://www.linkwissenschaft.de/smx-muenchen-recap-2012/327/"&gt;Jan Kutschera: SMX München Recap 2012&lt;/a&gt;&lt;a href="http://www.seonauten.com/smx-2012-recap-faszinationspunkte/"&gt;Seonauten: SMX 2012 – Recap &amp; Faszinationspunkte&lt;/a&gt;&lt;br /&gt;Lustiges Gezwitscher: &lt;a href="http://www.seo-united.de/blog/seo/tweetgefluster-von-der-smx-munchen-2012.htm"&gt;Tweetgeflüster von der SMX München 2012&lt;/a&gt;&lt;br /&gt;Recap mit Video-Tipps: &lt;a href="http://felixbeilharz.de/smx-recap-inkl-video-tipps-von-rand-fishkin/"&gt;SMX – Recap inkl. Video-Tipps von Rand Fishkin&lt;/a&gt;&lt;br /&gt;Auch in 2012 toll: &lt;a href="http://www.tekka.de/2012/03/30/smx-munchen-2012/"&gt;SMX München: Auch 2012 toll!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://www.martijnbeijk.com/tutorial/using-kml-for-local-seo/"&gt;KML and sitemaps for SEO – The definitive guide&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://support.google.com/plus/bin/answer.py?hl=en&amp;answer=1713320"&gt;Google: About Google+ Ripples&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://www.seomoz.org/blog/using-google-plus-ripples-to-connect-with-influencers"&gt;Using Google+ Ripples to Connect with Influencers&lt;/a&gt;&lt;br /&gt;[4] &lt;a href="http://www.hanselman.com/blog/EmbraceAuthorshipTheImportanceOfRelmeAndRelauthorOnYourContentsSEOAndGoogle.aspx"&gt;Embrace Authorship - The importance of rel=me and rel=author on your content's SEO and Google&lt;/a&gt;&lt;br /&gt;[5] &lt;a href="https://developers.facebook.com/docs/opengraph/"&gt;OpenGraph&lt;/a&gt;&lt;br /&gt;[6] &lt;a href="http://www.blueglass.com/blog/unraveling-facebook-open-graph-part-1/"&gt;Unraveling Facebook Open Graph – Part 1&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-4089275613686816119?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/eq5wGdp4wt0/impressionen-von-der-smx-munchen-2012.html</link><author>noreply@blogger.com (Manuel Breitfeld)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-w8HOpEdl0As/T3k5gpzooRI/AAAAAAAAAEg/zSXXY5m-fOM/s72-c/smx-2012_keynote.jpg" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://blog.exensio.de/2012/04/impressionen-von-der-smx-munchen-2012.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-8020649391383682030</guid><pubDate>Sun, 04 Mar 2012 15:31:00 +0000</pubDate><atom:updated>2012-05-02T11:44:12.146+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">MySQL</category><category domain="http://www.blogger.com/atom/ns#">Apache Webserver</category><category domain="http://www.blogger.com/atom/ns#">Tomcat</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Teil 2 - Grails in Produktion – mit Apache, Tomcat und MySQL</title><description>Im zweiten Teil meiner Blog-Serie (hier geht es zu &lt;a href="http://blog.exensio.de/2012/02/teil-1-grails-in-produktion-mit-apache.html"&gt;Teil 1&lt;/a&gt; bzw. &lt;a href="http://blog.exensio.de/2012/05/teil-3-grails-in-produktion-mit-apache.html"&gt;Teil 3&lt;/a&gt;) möchte ich auf die Konfiguration des Apache Moduls mod_jk innerhalb des Apache Web-Servers eingehen. Hierzu muss die Datei httpd.conf angepasst und eine Datei worker.properties erstellt (die Konfiguration der Ports beschreibe ich dann im Tomcat-Teil meiner Blog-Serie) werden. Des Weiteren werden ich noch kurz die JKStatus Konsole vorstellen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Einstellungen in der Datei httpd.conf:&lt;/b&gt;&lt;br /&gt;Im Listing unten sieht man die Standard-Einstellungen, diese können und sollten dann in jedem Projekt modifiziert bzw. erweitert werden. Folgendes ist anzumerken : &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Bis Zeile 9 - stehen die globalen Einstellungen, wie Lokation des Logfiles, der worker.properties, etc.&lt;/li&gt;&lt;li&gt;Ab Zeile 43 - stehen dann die Einstellungen innerhalb des Virtual-Host Abschnitts. In einer Produktions-Umgebung sollte man dann noch entscheiden, ob die JKStatus-Konsole benutzt werden soll (Zeile 50).&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;pre class="xml" name="code" style="display: none;"&gt;LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so&lt;br /&gt;LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so&lt;br /&gt;JkWorkersFile /etc/apache2/worker.properties &lt;br /&gt;# Where to put jk logs &lt;br /&gt;JkLogFile /var/log/apache2/mod_jk.log &lt;br /&gt;# Set the jk log level [debug/error/info] &lt;br /&gt;JkLogLevel info &lt;br /&gt;# Select the log format &lt;br /&gt;JkLogStampFormat "[%a %b %d %H:%M:%S %Y] " &lt;br /&gt;&lt;br /&gt;&lt;virtualhost *:80=""&gt;&lt;br /&gt;&lt;br /&gt; ServerAdmin webmaster@localhost&lt;br /&gt;&lt;br /&gt; DocumentRoot /var/www&lt;br /&gt; &lt;directory&gt;&lt;br /&gt;  Options FollowSymLinks&lt;br /&gt;  AllowOverride None&lt;br /&gt; &lt;/directory&gt;&lt;br /&gt; &lt;directory var="" www=""&gt;&lt;br /&gt;  Options Indexes FollowSymLinks MultiViews&lt;br /&gt;  AllowOverride None&lt;br /&gt;  Order allow,deny&lt;br /&gt;  allow from all&lt;br /&gt; &lt;/directory&gt;&lt;br /&gt;&lt;br /&gt; ErrorLog /var/log/apache2/error.log&lt;br /&gt;&lt;br /&gt; # Possible values include: debug, info, notice, warn, error, crit,&lt;br /&gt; # alert, emerg.&lt;br /&gt; LogLevel warn&lt;br /&gt;&lt;br /&gt; CustomLog /var/log/apache2/access.log combined&lt;br /&gt;&lt;br /&gt;    Alias /doc/ "/usr/share/doc/"&lt;br /&gt;    &lt;directory "="" doc="" share="" usr=""&gt;&lt;br /&gt;        Options Indexes MultiViews FollowSymLinks&lt;br /&gt;        AllowOverride None&lt;br /&gt;        Order deny,allow&lt;br /&gt;        Deny from all&lt;br /&gt;        Allow from 127.0.0.0/255.0.0.0 ::1/128&lt;br /&gt;    &lt;/directory&gt;&lt;br /&gt; # JkOptions indicate to send SSL KEY SIZE, &lt;br /&gt; JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories &lt;br /&gt; # JkRequestLogFormat set the request format &lt;br /&gt; JkRequestLogFormat "%w %V %T" &lt;br /&gt; # Send all MyWebApp requests to Tomcat&lt;br /&gt; JkMount /MyWebApp/* loadbalancer&lt;br /&gt; # Send JKStatus Console&lt;br /&gt; JkMount /jkstatus/ status&lt;br /&gt;&lt;br /&gt; RewriteEngine On&lt;br /&gt; RewriteRule ^/$ /MyWebApp/ [PT,L]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/virtualhost&gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Einstellungen in der Datei worker.properties (/etc/apache2): &lt;/b&gt;&lt;br /&gt;Diese finden sich im Listing unten. Diese worker.properties führt ein Load-Balancing der Http-Requests auf 4 Tomcat-Server durch (mit einem Apache-WS davor). Sollen die 4 Tomcats die Requests von 2 Apache-WS-Servern erhalten, so bräuchte man 2 worker.properties. Ich würde dann jedoch weiterhin die Namen der Server global durchnummerieren, sprich svr1..svr4 und nicht svr1/svr2 für den ersten Apache-WS und erneut svr1/svr2 für den zweiten Apache-WS, da der Servername an die JSESSIONID angehängt wird und man somit einfacher herausfinden kann, an welchen Server der HttpRequest ging, um dann beispielsweise schneller das zugehörige Logfile zu finden. Zeile 29 ist noch erwähnenswert: Das Modul mod_jk geht standardmäßig von max. 3 Servern aus, auf die die Last verteilt werden soll. Aus diesem Grund ist hier der Wert auf 4 angepasst worden.&lt;br /&gt;&lt;pre class="xml" name="code" style="display: none;"&gt;worker.list=svr1,svr2,svr3,svr4,loadbalancer,status&lt;br /&gt;worker.svr1.type=ajp13&lt;br /&gt;worker.svr1.host=xx.xx.xx.xx&lt;br /&gt;worker.svr1.port=9008&lt;br /&gt;worker.svr1.lbfactor=1&lt;br /&gt;worker.svr1.socket_keepalive=1&lt;br /&gt;worker.svr1.socket_timeout=300&lt;br /&gt;worker.svr2.type=ajp13&lt;br /&gt;worker.svr2.host=xx.xx.xx.xx&lt;br /&gt;worker.svr2.port=9009&lt;br /&gt;worker.svr2.lbfactor=1&lt;br /&gt;worker.svr2.socket_keepalive=1&lt;br /&gt;worker.svr2.socket_timeout=300&lt;br /&gt;worker.svr3.type=ajp13&lt;br /&gt;worker.svr3.host=xx.xx.xx.xx&lt;br /&gt;worker.svr3.port=9008&lt;br /&gt;worker.svr3.lbfactor=1&lt;br /&gt;worker.svr3.socket_keepalive=1&lt;br /&gt;worker.svr3.socket_timeout=300&lt;br /&gt;worker.svr4.type=ajp13&lt;br /&gt;worker.svr4.host=xx.xx.xx.xx&lt;br /&gt;worker.svr4.port=9009&lt;br /&gt;worker.svr4.lbfactor=1&lt;br /&gt;worker.svr4.socket_keepalive=1&lt;br /&gt;worker.svr4.socket_timeout=300&lt;br /&gt;worker.loadbalancer.type=lb&lt;br /&gt;worker.loadbalancer.sticky_session=1&lt;br /&gt;# Adjust to the number of workers (4 in our case)&lt;br /&gt;worker.retries=4&lt;br /&gt;worker.loadbalancer.balance_workers=svr1,svr2,svr3,svr4&lt;br /&gt;worker.status.type=status&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;JKStatus-Konsole:&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-nFuHCine4Vg/T1OHiCFaeeI/AAAAAAAAAXg/3-It2DBM2C0/s1600/exensio_blog_grails_apache_tomcat_mod_jk.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="167" src="http://4.bp.blogspot.com/-nFuHCine4Vg/T1OHiCFaeeI/AAAAAAAAAXg/3-It2DBM2C0/s320/exensio_blog_grails_apache_tomcat_mod_jk.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Diese ist im Bild rechts zu sehen. Meines Erachtens ist diese Konsole während der Lasttests ein sehr nützliches Hilfsmittel. In Produktion sollte dann jedoch eher Nagios benutzt werden. Man sieht in der Konsole beispielsweise sehr schön, ob sich die Last gleichmäßig auf alle Tomcat-Server verteilt. Auch bekommt man sehr schnell mit, wenn ein Tomcat Probleme hat. Hierbei sind folgende Angaben (rote Umrandung im Bild rechts)&amp;nbsp;von besonderem Interesse: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Busy (Current number of busy connections)&lt;/li&gt;&lt;li&gt;Max (Maximum number of busy connections).&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;Bei hohen Werten hat der Tomcat Probleme, meistens hängen dann Tomcat-Threads, beispielsweise verursacht durch eine überlastete Datenbank.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-8020649391383682030?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/CjPK7IDjdIU/teil-2-grails-in-produktion-mit-apache.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-nFuHCine4Vg/T1OHiCFaeeI/AAAAAAAAAXg/3-It2DBM2C0/s72-c/exensio_blog_grails_apache_tomcat_mod_jk.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/03/teil-2-grails-in-produktion-mit-apache.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-4490374344548906153</guid><pubDate>Mon, 13 Feb 2012 08:19:00 +0000</pubDate><atom:updated>2012-05-01T13:38:51.687+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">MySQL</category><category domain="http://www.blogger.com/atom/ns#">Apache Webserver</category><category domain="http://www.blogger.com/atom/ns#">Tomcat</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Teil 1 - Grails in Produktion – mit Apache, Tomcat und MySQL</title><description>Mit diesem Blog-Post möchte ich die Schritte, die nötig sind, um eine &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt; Applikation produktiv zu stellen, beschreiben. Dieses Thema werde ich in aufeinanderfolgende Blog-Posts aufteilen. Die Aufteilung sieht folgendermaßen aus:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Teil 1 – Allgemeines zur Systemarchitektur und Ergänzungen in Grails&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.exensio.de/2012/03/teil-2-grails-in-produktion-mit-apache.html"&gt;Teil 2 – Apache Web Server&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.exensio.de/2012/05/teil-3-grails-in-produktion-mit-apache.html"&gt;Teil 3 – Tomcat&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Teil 4 – MySQL&lt;/li&gt;&lt;li&gt;Teil 5 – Load Tests&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Systemarchitektur&lt;/b&gt;&lt;br /&gt;Das Bild rechts beschreibt die gewählte Systemarchitektur. Diese besteht aus folgenden Komponenten: &lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-N3nFgIBVcV0/Tzf4J-lJoyI/AAAAAAAAAXQ/U54sYdR0V8I/s1600/exensio_blog_grails_apache_tomcat_mysql_system_architektur.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="189" src="http://2.bp.blogspot.com/-N3nFgIBVcV0/Tzf4J-lJoyI/AAAAAAAAAXQ/U54sYdR0V8I/s320/exensio_blog_grails_apache_tomcat_mysql_system_architektur.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Load-Balancer – dieser kann sowohl auf Soft-, wie auch auf Hardware basieren. Meistens wird hier Hardware favorisiert. Wichtig ist, dass der Load-Balancer „Sticky Sessions“ unterstützt, sprich einen User-Request immer wieder an den ursprünglichen Apache WS weiterleitet.&lt;/li&gt;&lt;li&gt;Apache Web Server – hier benutzen wir mod_jk zur Kommunikation zwischen Apache WS und Tomcat. Gründe hierfür sind: sehr ausgereift und wir benutzen meistens keine SSL Verschlüsselung zwischen Apache WS und Tomcat. Falls SSL notwendig ist, sollte eher mod_proxy_http benutzt werden [1].&amp;nbsp;&lt;/li&gt;&lt;li&gt;Tomcat – hier ist wichtig zu erwähnen, dass wir nur ein Load-Balancing für die Requests durchführen, also kein Cluster mit Session Replication. Dies reicht in den meisten Fällen vollkommen aus. Nachteilig hierbei ist, dass ein User sich erneut anmelden muss, falls eine Tomcat-Instanz abstürzt. Als Nachteile für ein Cluster können folgende Punkte aufgeführt werden: &lt;ul&gt;&lt;li&gt;Performanz – jede Session wird auf einen Backup-Server (in-memory) über das Netzwerk repliziert. Bei sehr vielen Sessions (und vielen Tomcat-Instanzen im Cluster) kann dies eine sehr hohe Netzwerklast verursachen. &amp;nbsp;Die Sessions können auch in einer Datenbank persistiert werden. Dies ist jedoch nicht performanter.&lt;/li&gt;&lt;li&gt;Bei der Entwicklung muss beispielsweise beachtet werden, dass alle Objekte in der HTTP-Session serialisierbar sind. Auch darf die http-Session nicht zu groß sein (max. 50 – 70 KByte). Des Weiteren darf beispielsweise keine Hibernate-Session in einem HTTP-Objekt gespeichert werden. Obwohl wir wissen, dass dies Anfängerfehler sind, treten diese Fälle trotzdem sehr oft auf. Insbesondere in hektischen Projektphasen. Dies bedeutet schließlich, dass ein Cluster höhere Aufwände verursacht.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;MySQL – wir verwenden auch sehr gerne PostgreSQL. Jedoch ist MySQL bei den Hosting Providern unserer Kunden öfters vertreten. Deshalb wird hier auf MySQL eingegangen. Wichtig ist hier, sich über einen Fail-Over-Szenario im klaren zu sein. Es gibt mehrere Möglichkeiten, beispielsweise Linux-Cluster, VM-Ware-Cluster, Sequoia, etc. Die Hosting-Provider unserer Kunden setzen hier meistens ein Linux-Cluster ein.&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Ergänzungen in Grails&lt;/b&gt;&lt;br /&gt;Folgende Ergänzungen sollten meines Erachtens in Grails hinzugefügt werden: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;GSP-Seite mit folgenden Informationen: &lt;ul&gt;&lt;li&gt;Information über die für den Build des WAR-Files benutzte Revision-Nummer des Sourcecode-Systems (Subversion in meinem Fall).&amp;nbsp;&lt;/li&gt;&lt;li&gt;Ausgabe von allen Cookies. Hier ist insbesondere die JSESSIONID von Interesse, da mod_jk den in der workers.properties gewählten Servernamen an die JSESSIONID anhängt.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Konfiguration des Connection-Pools im Tomcat. Dieser wird dann als JNDI Connection-Pool in der Grails-Applikation benutzt. Dies hat den Vorteil, dass eine neue Datenbank mit anderen Settings, ohne ein erneutes Kompilieren der Grails-Applikation, benutzt werden kann.&lt;/li&gt;&lt;li&gt;Ausgabe der Logfiles in ${CATALINA_HOME}/logs. Nun könnte jemand auf die Idee kommen, dies über einen JNDI Eintrag steuern zu wollen, wie in meinem Blog [3] beschrieben. Hierbei ist jedoch das Problem, dass die Config.groovy vor der resources.groovy (die den Zugriff auf JNDI durchführt) aufgerufen wird.&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Revision aus Subversion während Grails War-File Build ermitteln&lt;/b&gt;&lt;br /&gt;Der Code unten basiert auf einem Code-Snippet von StackOverflow [2]. Ich habe diesen modifiziert (Zeile 32), so dass die Revision-Nummer angezeigt wird. Dieser Code muss der Datei _Events.groovy hinzugefügt werden. &lt;br /&gt;&lt;pre class="xml" name="code"&gt;import org.tmatesoft.svn.core.SVNException&lt;br /&gt;import org.tmatesoft.svn.core.wc.SVNRevision&lt;br /&gt;import org.tmatesoft.svn.core.wc.SVNInfo&lt;br /&gt;import org.tmatesoft.svn.core.wc.SVNWCClient&lt;br /&gt;import org.tmatesoft.svn.core.wc.SVNClientManager&lt;br /&gt;import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory&lt;br /&gt;import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl&lt;br /&gt;import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory&lt;br /&gt;&lt;br /&gt;// Create revision info in case of a WAR build&lt;br /&gt;eventWarStart = { type -&amp;gt;&lt;br /&gt;&lt;br /&gt;    println "******************* eventWarStart *****************"&lt;br /&gt;    try {&lt;br /&gt;        // initialise SVNKit&lt;br /&gt;        DAVRepositoryFactory.setup();&lt;br /&gt;        SVNRepositoryFactoryImpl.setup();&lt;br /&gt;        FSRepositoryFactory.setup();&lt;br /&gt;&lt;br /&gt;        SVNClientManager clientManager = SVNClientManager.newInstance();&lt;br /&gt;        println "clientManager = " + clientManager.toString();&lt;br /&gt;        SVNWCClient wcClient = clientManager.getWCClient();&lt;br /&gt;        println "wcClient = " + wcClient.toString();&lt;br /&gt;&lt;br /&gt;        // the svnkit equivalent of "svn info"&lt;br /&gt;        File baseFile = new File(basedir);&lt;br /&gt;&lt;br /&gt;        println "baseFile = " + baseFile.toString();&lt;br /&gt;        SVNInfo svninfo = wcClient.doInfo(baseFile, SVNRevision.WORKING);&lt;br /&gt;        println "svninfo = " + svninfo.toString();&lt;br /&gt;&lt;br /&gt;        def version = svninfo.revision.number as String&lt;br /&gt;        println "Setting Version to: ${version}"&lt;br /&gt;        metadata.'app.version' = "${version}".toString()&lt;br /&gt;        metadata.persist()&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;    catch (SVNException ex) {&lt;br /&gt;        //something went wrong&lt;br /&gt;        println "**************** SVN exception **************"&lt;br /&gt;        println ex.getMessage();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;} // End eventWarStart()  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Während des Builds wird die Revisions-Nummer in der Datei application.properties (siehe unten Zeile 6) geändert.&lt;br /&gt;&lt;pre class="xml" name="code"&gt;#Grails Metadata file&lt;br /&gt;#Sat Jan 21 16:17:44 CET 2012&lt;br /&gt;app.grails.version=1.3.7&lt;br /&gt;app.name=MyGrailsProject&lt;br /&gt;app.servlet.version=2.4&lt;br /&gt;app.version=455&lt;br /&gt;plugins.aop-reloading-fix=0.1&lt;br /&gt;plugins.batch-launcher=0.5.6&lt;br /&gt;plugins.csv=0.3.1&lt;br /&gt;plugins.fixtures=1.1&lt;br /&gt;plugins.hibernate=1.3.7&lt;br /&gt;plugins.jquery=1.7.1&lt;br /&gt;plugins.jquery-ui=1.8.15&lt;br /&gt;plugins.mail=1.0-SNAPSHOT&lt;br /&gt;plugins.resources=1.0.2&lt;br /&gt;plugins.spring-security-core=1.2.4&lt;br /&gt;plugins.tomcat=1.3.7&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In der BuildConfig.groovy muss dann noch überprüft werden, ob das War-File nicht die Revisionsnummer angehängt bekommen hat. Sonst hätte der Name des War-Files folgenden Aufbau : MyProject-455.war, mit dem Nachteil, dass sich jedes Mal die Url der Grails-Applikation ändern würde.&lt;br /&gt;&lt;pre class="xml" name="code"&gt;grails.project.class.dir = "target/classes"&lt;br /&gt;grails.project.test.class.dir = "target/test-classes"&lt;br /&gt;grails.project.test.reports.dir = "target/test-reports"&lt;br /&gt;grails.project.war.file = "target/${appName}.war"&lt;br /&gt;grails.project.dependency.resolution = {&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Das Ganze kann in einer GSP-Seite (inkl. Ausgabe der Cookies) folgendermaßen dargestellt werden: &lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;%--&lt;br /&gt;  Created by IntelliJ IDEA.&lt;br /&gt;  User: Peter Soth&lt;br /&gt;  Date: 11.01.12&lt;br /&gt;  Time: 11:49&lt;br /&gt;  To change this template use File | Settings | File Templates.&lt;br /&gt;--%&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&amp;gt;&lt;br /&gt;    &amp;lt;meta name="layout" content="main"/&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Info:&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The following revision has been used for the build of this WAR.&lt;/h3&gt;&lt;br /&gt;REV: ${grailsApplication.metadata.'app.version'}&lt;br /&gt;&lt;h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Show all cookies&lt;/h3&gt;&lt;br /&gt;&lt;g:each in="${request.cookies}" var="cookie"&gt;&lt;br /&gt;    NAME: ${cookie.name} VALUE: ${cookie.value}&lt;br /&gt;&lt;/g:each&gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Tomcat JDBC Connection-Pool mittels JNDI einbinden&lt;/b&gt;&lt;br /&gt;Hierzu wird in DataSource.groovy folgendes eingetragen: &lt;br /&gt;&lt;pre class="xml" name="code"&gt;// environment specific settings&lt;br /&gt;environments {&lt;br /&gt;    production {&lt;br /&gt;        dataSource {&lt;br /&gt;            jndiName        = "java:comp/env/jdbc/production"&lt;br /&gt;            dialect         = org.hibernate.dialect.MySQL5InnoDBDialect&lt;br /&gt;            dbCreate        = 'update'&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;Im Blog-Post zum Tomcat zeige ich dann, wie dies im Tomcat konfiguriert wird.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Logging in CATALINA_HOME festlegen&lt;/b&gt;&lt;br /&gt;Mit folgendem Code-Snippet werden die Logs-Files der Grails-Applikation in das Log-Verzeichnis des Tomcat-Servers geschrieben. Hierzu muss die Variable logDirectory in der log4j-Konfiguration in Config.groovy benutzt werden. &lt;br /&gt;&lt;pre class="xml" name="code"&gt;// request parameters to mask when logging exceptions&lt;br /&gt;grails.exceptionresolver.params.exclude = ['password']&lt;br /&gt;&lt;br /&gt;// set per-environment serverURL stem for creating absolute links&lt;br /&gt;environments {&lt;br /&gt; ...&lt;br /&gt;    production {&lt;br /&gt;        grails.serverURL = "http://www.changeme.com"&lt;br /&gt;        //tomcat based logging&lt;br /&gt;        def catalinaHome = System.getenv('CATALINA_HOME')&lt;br /&gt;        if (!catalinaHome) catalinaHome = '.'   // falls nicht gesetzt&lt;br /&gt;        def String grailsLogDir = "${catalinaHome}/logs/"&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;[1] &lt;a href="http://www.tomcatexpert.com/blog/2010/06/16/deciding-between-modjk-modproxyhttp-and-modproxyajp"&gt;Tomcat Expert Blog&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://stackoverflow.com/questions/5263995/grails-add-svn-revision-to-app-version"&gt;StackOverflow: SVN Revisionsnummer in Grails einbinden&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://blog.exensio.de/2012/01/grails-jndi-werte-im-embedded-tomcat.html"&gt;Grails : JNDI Werte im Embedded Tomcat setzen&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-4490374344548906153?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/d1MTjsOYOZU/teil-1-grails-in-produktion-mit-apache.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-N3nFgIBVcV0/Tzf4J-lJoyI/AAAAAAAAAXQ/U54sYdR0V8I/s72-c/exensio_blog_grails_apache_tomcat_mysql_system_architektur.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/02/teil-1-grails-in-produktion-mit-apache.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3707911597787693899</guid><pubDate>Mon, 06 Feb 2012 08:54:00 +0000</pubDate><atom:updated>2012-02-06T09:54:45.267+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Grails 2.0 Upgrade Guide</title><description>&lt;br /&gt;Auf Google+ [1] hat das &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt;-Team die Grails Community über Ihre Erfahrungen bei der Migration auf Grails 2.0 befragt. Um es kurz zu machen: Bei kleinen Applikationen ist eine Migration sehr einfach, bei großen Applikationen gibt es jedoch Probleme. Vor allem bei der Migration von Tests gibt es Probleme. Laut Grails Team soll man auf Grails 2.0.1 [2] warten, sofern man die Tests auch migrieren möchte. Dies dürfte bei den meisten Projekten – wie auch bei uns - der Fall sein. Und hier geht es zum Upgrade Guide von Peter Ledbrook [3].&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="https://plus.google.com/117411438136918964913/posts/axyCZk1P5L5"&gt;https://plus.google.com/117411438136918964913/posts/axyCZk1P5L5&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="https://plus.google.com/117411438136918964913/posts/TFw4YvNfQXX"&gt;https://plus.google.com/117411438136918964913/posts/TFw4YvNfQXX&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://pledbrook.github.com/grails-howtos/en/upgradeToGrails2.html"&gt;http://pledbrook.github.com/grails-howtos/en/upgradeToGrails2.html&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-3707911597787693899?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/9_YhQIybg80/grails-20-upgrade-guide.html</link><author>noreply@blogger.com (Peter Soth)</author><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/02/grails-20-upgrade-guide.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-8707846592899013297</guid><pubDate>Sun, 05 Feb 2012 17:05:00 +0000</pubDate><atom:updated>2012-02-05T18:05:42.187+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">web20</category><category domain="http://www.blogger.com/atom/ns#">socialmedia</category><category domain="http://www.blogger.com/atom/ns#">exensio</category><category domain="http://www.blogger.com/atom/ns#">socbiz</category><title>Recruiting 2.0 – exensio auf Youtube - IT Berater (w/m) mit hohem *PZU-Faktor gesucht</title><description>&lt;iframe allowfullscreen="" frameborder="0" height="240" src="http://www.youtube.com/embed/HmO27ZszfXE?rel=0" width="320"&gt;&lt;/iframe&gt;&lt;br /&gt;Unter Recruiting 2.0 versteht &amp;nbsp;man die Benutzung von Web 2.0 Diensten, wie Xing, Facebook, Twitter, Google+ und Youtube zur Mitarbeitergewinnung. Bisher sind wir bei exensio auch den klassischen Weg mit Anzeigen in Jobbörsen gegangen. Vor allem für kleinere Unternehmen hat dies jedoch den Nachteil, dass Stellen- ausschreibungen leider in der Masse untergehen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Warum neue Kollegen über einen Youtube Kanal suchen?&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;Uns wurde schnell klar, dass wir einen anderen Weg versuchen mussten und als Software-Ingenieure auch professionelle Unterstützung hierfür benötigen würden. Mit dem Kommunikationsdesigner Michael Starzmann von gadget Strategie + Design [1][2] hatten wir endlich den Richtigen gefunden, der sich voll und ganz auf unserer Wellenlänge befindet. gadget zeichnet meiner Meinung nach vor allem durch tragfähige sowie angemessene Lösungen aus, denn wir hatten kein Budget für ein ganzes Filmteam etc. Weitere Infos finden sich auf dem gadget Blog [3]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fazit&lt;/b&gt;&lt;br /&gt;Um es gleich vorweg zu nehmen: Mit dem Hochladen eines Videos auf Youtube steigen nicht über Nacht die Zahl der Bewerbungen an. Unsere Intension war hierbei eine andere: Wir sehen das Youtube Video mehr als Möglichkeit, uns unseren potentiellen neuen Mitarbeitern in 30 Sekunden vorzustellen und vielleicht etwas mehr von der exensio „Idee“ rüberzubringen, als dies mit einer statischen Web-Seite oder einer PDF-Datei möglich ist. Das sehr positive Feedback, das wir bisher erhalten haben, zeigt uns, dass es der richtige Weg ist - wir würden es auf jeden Fall wieder machen. Des Weiteren ist zu erwähnen, dass das Video länger für uns arbeitet, als eine Anzeige auf einem Jobportal.&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://www.gadget.de/"&gt;http://www.gadget.de&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://blog.gadget.de/"&gt;http://blog.gadget.de&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://blog.gadget.de/?p=163"&gt;http://blog.gadget.de/?p=163&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-8707846592899013297?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/NLQd4YIQ8Ro/recruiting-20-exensio-auf-youtube-it.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/HmO27ZszfXE/default.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/02/recruiting-20-exensio-auf-youtube-it.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-2265726432079675890</guid><pubDate>Thu, 02 Feb 2012 17:48:00 +0000</pubDate><atom:updated>2012-02-02T18:58:59.243+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Vermeiden von ClassCastExceptions beim Reloading  in Grails-Applikationen</title><description>&lt;h2&gt; Problem&lt;/h2&gt;Einer der Hauptvorteile von &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt; gegenüber anderen Frameworks bzw. Sprachen ist die schnelle Entwicklung. Bei laufendem Server können Änderungen vorgenommen und diese sind ohne einen lang dauernden Publizierungsvorgang verfügbar. &lt;br /&gt;Unter bestimmten Umständen funktioniert allerdings der Reload von Änderungen in Controllern oder Services nicht bei laufendem Server. Nimmt man eine Änderung vor und lädt anschließend über den Browser die Seite neu, dann resultiert dies in eine ClassCast-Exception, die nur durch einen Server-Neustart zu beheben ist. Das Problem tritt unseren Beobachtungen zufolge insbesondere im Zusammenhang mit dem Spring-Cache-Plugin auf, das Annotation verwendet. Auch bei anderen Annotationstypen ist das Problem schon aufgetaucht und  bekannt [1] &lt;br /&gt;&lt;br /&gt;&lt;h2&gt; Lösung&lt;/h2&gt;Ab der Grails-Version 2.0 ist dieses Problem behoben. Für andere Grails-Versionen lässt sich das Problem durch Installation des „AOP Reloading Fix“ Plugins [2] beheben. Dies funktioniert standardmäßig allerdings nur für die Umgebung (Environment) &lt;i&gt;Development&lt;/i&gt;.  &lt;br /&gt;Wird eine eigene Umgebung für die Entwicklung eingerichtet, z.B. zum Umsetzen von Batches, dann werden die Erweiterungen des Plugins nicht angezogen. Durch Setzen der Variable &lt;i&gt;grails.reload.enabled&lt;/i&gt; beim Starten der Anwendung kann dies umgangen werden und das Plugin wird angezogen. Die folgende Abbildung zeigt in IntelliJ den Befehl zum Starten der Umgebung &lt;i&gt;devbatch&lt;/i&gt;. Zusätzlich werden die beiden Variablen &lt;i&gt;grails.reload.enabled=true&lt;/i&gt; und &lt;i&gt;grails.reload.location=.&lt;/i&gt; übergeben.  &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-4N3xqkgD1O4/TyrJfOKs1II/AAAAAAAAARo/avDSM9QwFSA/s1600/aop_reload.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="156" src="http://1.bp.blogspot.com/-4N3xqkgD1O4/TyrJfOKs1II/AAAAAAAAARo/avDSM9QwFSA/s320/aop_reload.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt; Links&lt;/h2&gt;[1] &lt;a href="http://jira.grails.org/browse/GRAILS-6370"&gt;http://jira.grails.org/browse/GRAILS-6370&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://grails.org/plugin/aop-reloading-fix"&gt;AOP Reloading Fix Plugin&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-2265726432079675890?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/vJ5Aj8_Vh1U/vermeiden-von-classcastexceptions-beim.html</link><author>noreply@blogger.com (Tobias Kraft)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-4N3xqkgD1O4/TyrJfOKs1II/AAAAAAAAARo/avDSM9QwFSA/s72-c/aop_reload.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/02/vermeiden-von-classcastexceptions-beim.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-1298703952107985903</guid><pubDate>Mon, 30 Jan 2012 18:39:00 +0000</pubDate><atom:updated>2012-01-31T08:14:02.084+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Grails : JNDI Werte im Embedded Tomcat setzen</title><description>JNDI eignet sich sehr gut, um einer Web-Applikation von außen (über den Tomcat) Parameter zur Verfügung zu stellen.  Die JNDI Einstellungen werden in Tomcat in der context.xml vorgenommen. Entwickelt man in &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt; (beispielsweise mit IntelliJ), so läuft der Tomcat jedoch im Embedded Mode. Dies bedeutet, dass keine context.xml vorhanden ist, die editierbar wäre.  In den folgenden Code-Beispielen möchte ich zeigen, wie ein JNDI Wert ausgelesen und im Embedded Tomcat gesetzt werden kann. Dies ist beispielsweise zum Testen sehr nützlich.&lt;br /&gt;&lt;br /&gt;So würde das Setzen eines JNDI Parameters in der Context.xml (auf dem Produktionsserver) aussehen: &lt;br /&gt;&lt;pre class="xml" name="code"&gt;&lt;context&gt;&lt;br /&gt;  ...&lt;br /&gt;  &lt;environment name="jnditest'" override="true" type="java.lang.String" value="Grails JNDI Test String"&gt;&lt;br /&gt;  ...&lt;br /&gt;  &lt;/environment&gt;&lt;br /&gt;&lt;/context&gt;&lt;br /&gt;&lt;/pre&gt;In der Grails Test-Umgebung werden dann in der Datei _Events.groovy die JNDI Werte gesetzt. Hier muss beachtet werden, dass MyWebAppName durch den richtigen Namen der Web Applikation ersetzt wird. In dem Beispiel unten ist es nicht nötig, das Grails Tomcat Plugin zu modifizieren, wie es in den Grails Mailing-Listen diskutiert wurde:&lt;br /&gt;&lt;pre class="xml" name="code"&gt;eventConfigureTomcat = {tomcat -&amp;gt;&lt;br /&gt;    println "### Start Tomcat configuration"&lt;br /&gt;&lt;br /&gt;    try {&lt;br /&gt;        def environment = tomcat.class.classLoader.loadClass('org.apache.catalina.deploy.ContextEnvironment').newInstance()&lt;br /&gt;    &lt;br /&gt;        environment.name = 'jnditest'&lt;br /&gt;        environment.type = 'java.lang.String'&lt;br /&gt;        environment.value = 'Grails JNDI Test String'&lt;br /&gt;        environment.override = Boolean.TRUE&lt;br /&gt;    &lt;br /&gt;        def context = tomcat.host.findChild('/MyWebAppName')&lt;br /&gt;        context.namingResources.addEnvironment environment&lt;br /&gt;    }&lt;br /&gt;    catch (Exception e)&lt;br /&gt;    {&lt;br /&gt;        e.printStackTrace()&lt;br /&gt;    }&lt;br /&gt;    println "### End Tomcat configuration"&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Auslesen in der resources.groovy. So funktioniert es sowohl in der Test- als auch in der Produktions-Umgebung. In dem Beispiel unten wird jedoch überprüft, ob Grails im Entwicklungsmodus läuft: &lt;br /&gt;&lt;pre class="xml" name="code"&gt;import org.springframework.web.servlet.i18n.SessionLocaleResolver&lt;br /&gt;&lt;br /&gt;// Place your Spring DSL code here&lt;br /&gt;beans = {&lt;br /&gt;    localeResolver(SessionLocaleResolver) {       &lt;br /&gt;        Locale.setDefault(Locale.GERMAN)&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    if (grails.util.GrailsUtil.environment.equals('development')) {&lt;br /&gt;        jnditest(org.springframework.jndi.JndiObjectFactoryBean) {&lt;br /&gt;            jndiName = 'java:/comp/env/jnditest'&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Links:&lt;br /&gt;[1]&amp;nbsp;&lt;a href="http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Environment Entries"&gt;http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Environment Entries&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-1298703952107985903?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/CpIWkQ9FfVY/grails-jndi-werte-im-embedded-tomcat.html</link><author>noreply@blogger.com (Peter Soth)</author><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/01/grails-jndi-werte-im-embedded-tomcat.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-8498042511834283189</guid><pubDate>Thu, 12 Jan 2012 14:56:00 +0000</pubDate><atom:updated>2012-01-12T16:30:35.292+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Apache Webserver</category><category domain="http://www.blogger.com/atom/ns#">AS3</category><category domain="http://www.blogger.com/atom/ns#">Flash</category><title>Langsame Netzwerk-Geschwindigkeit mittels Apache-Webserver simulieren</title><description>&lt;h2&gt;Einleitung&lt;/h2&gt;Im Bereich der Web-Entwicklung gibt es viele unterschiedliche Szenarien, die zu testen sind, bevor eine Änderung "live" gehen kann. Neben den typischen Kompatibilität-Tests auf Betriebssystem, Browser und Bildschirmauflösung ist auch die Netzwerk-Geschwindigkeit eine Komponente, der Beachtung geschenkt werden sollte.&lt;br /&gt;Insbesondere wenn Ressourcen nachgeladen werden müssen, ist es wichtig zu testen, wie die Web-Applikation bei verschiedenen Übertragungsgeschwindigkeiten reagiert.&lt;br /&gt;&lt;br /&gt;In einem aktuellen Projekt haben wir eine Flash/AS3-Applikation getestet, die JSON-Daten per asynchronem Request vom Server erhält und daraufhin externe Bilddateien in die Applikation nachlädt. In erster Linie musste also sichergestellt werden, dass die Applikation auch bei langsamer Übertragungsrate und gleichzeitig hoher Anzahl nachzuladender Bilder intuitiv zu bedienen bleibt (sprich: Einführung von Ladebalken, Deaktivierung von bestimmten Elementen, etc.).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Das Tool "Throttle"&lt;/h2&gt;Während es für den Apache Webserver mittlerweile auch Module gibt, die das "throttling" übernehmen können sollen, gibt es damit relativ schnell Kompatibilitätsprobleme zwischen den unterschiedlichen Webserver Versionen.&lt;br /&gt;Als zuverlässig hat sich das kleine auf Pipe-Basis [1] operierende Tool &lt;a href="http://klicman.org/throttle/"&gt;Throttle&lt;/a&gt; [2] herausgestellt. Unter Linux erfolgt die Installation einfach mit dem gewohnten Dreisatz "./configure &amp;&amp; make &amp;&amp; make install".&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Apache Webserver und Throttle&lt;/h2&gt;Pipe-Tools lassen sich auf einfache Weise in den Apache Webserver einbinden (Stichwort SetOutputFilter [3]). Im Folgenden ist die Beispiel-Konfiguration für ein Bandbreiten-Limit von 56K angegeben:&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&lt;br /&gt;# 56KB/s filter definition&lt;br /&gt;ExtFilterDefine ksec56 mode=output cmd="/usr/local/bin/throttle 57344" preservescontentlength &lt;br /&gt;# Use filter (e.g. in Location or VirtualHost directive)&lt;br /&gt;SetOutputFilter ksec56&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Der Filter kann beispielsweise innerhalb einer belieben Location- or VirtualHost-Anweisung verwendet werden.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Fazit&lt;/h2&gt;Mittels Throttle und dem Apache Webserver können auch verschiedene Übertragungsgeschwindigkeiten einfach in die Tests bei der Web-Entwicklung einbezogen werden. Mithilfe der Location- oder VirtualHost-Anweisung kann die Beschränkung nur für einzelne Verzeichnisse aktiviert werden - perfekt um langsame externe Server zu simulieren.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Links&lt;/h2&gt;[1] &lt;a href="http://de.wikipedia.org/wiki/Pipe_(Informatik)" target="_blank"&gt;Pipe auf Wikipedia&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://klicman.org/throttle/" target="_blank"&gt;Website zu Throttle&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://httpd.apache.org/docs/2.1/mod/core.html#setoutputfilter" target="_blank"&gt;Dokumentation zu SetOutputFilter&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-8498042511834283189?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/NlkI30FTh0o/langsame-netzwerk-geschwindigkeit.html</link><author>noreply@blogger.com (Manuel Breitfeld)</author><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2012/01/langsame-netzwerk-geschwindigkeit.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-9102526117200317412</guid><pubDate>Thu, 22 Dec 2011 16:50:00 +0000</pubDate><atom:updated>2011-12-22T17:50:27.312+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">exensio</category><title>exensio wünscht ein frohes Fest und ein erfolgreiches neues Jahr</title><description>&lt;br /&gt;&lt;div style="text-align: center;"&gt;Unsere besten Wünsche&lt;/div&gt;&lt;div style="text-align: center;"&gt;für ein frohes Weihnachtsfest&lt;/div&gt;&lt;div style="text-align: center;"&gt;und ein glückliches, erfolgreiches neues Jahr.&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-JXiBoEnFy8A/TvNc0lvdXzI/AAAAAAAAARM/U5MFnI6Y7DU/s1600/weihnachtskarte_sos_kinderdorf.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="227" src="http://1.bp.blogspot.com/-JXiBoEnFy8A/TvNc0lvdXzI/AAAAAAAAARM/U5MFnI6Y7DU/s320/weihnachtskarte_sos_kinderdorf.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;Auch in diesem Jahr verwenden wir den von&lt;/div&gt;&lt;div style="text-align: center;"&gt;uns für Weihnachtsgeschenke vorgesehenen Betrag zu Gunsten einer Spende an die&lt;/div&gt;&lt;div style="text-align: center;"&gt;Marc Soth Stiftung in der Trägerschaft der SOS Kinderdorf Stiftung.&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-u959FQDfOuE/TvNe6jcXHEI/AAAAAAAAARY/wS9xrarHBZ0/s1600/sos_kinderdorf.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="149" src="http://1.bp.blogspot.com/-u959FQDfOuE/TvNe6jcXHEI/AAAAAAAAARY/wS9xrarHBZ0/s200/sos_kinderdorf.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-9102526117200317412?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/gLhxS5IbDIk/exensio-wunscht-ein-frohes-fest-und-ein.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-JXiBoEnFy8A/TvNc0lvdXzI/AAAAAAAAARM/U5MFnI6Y7DU/s72-c/weihnachtskarte_sos_kinderdorf.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/12/exensio-wunscht-ein-frohes-fest-und-ein.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-821054521627970407</guid><pubDate>Thu, 22 Dec 2011 13:52:00 +0000</pubDate><atom:updated>2011-12-22T15:57:12.719+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">GORM</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Criteria List Queries bei Many-To-Many Beziehungen in Grails</title><description>&lt;h2&gt; Einleitung&lt;/h2&gt;In diesem Beitrag wird gezeigt, wie n:m Beziehungen in &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt;&amp;nbsp;(Stichwort 'hasMany') innerhalb einer Query abgefragt werden können.&lt;br /&gt;Als Beispiel betrachten wir die Beziehung zwischen einer Person und eines Projekts. Eine Person kann in mehreren Projekten involviert sein. In einem Projekt arbeiten wiederum mehrere Personen. Die Modellierung in Domain-Klassen könnte wie folgt (vereinfacht) aussehen&lt;br /&gt;&lt;pre class="java" name="code"&gt;class Person {&lt;br /&gt;String firstname&lt;br /&gt;String lastname&lt;br /&gt;static hasMany = [projects:Project]&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Project {&lt;br /&gt;String name&lt;br /&gt;static hasMany = [persons:Person]&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt; Datenbank-Abfragen&lt;/h2&gt;Im Folgenden sollen zwei Abfragen betrachtet werden:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Liefere alle Personen, deren Vorname "Max" oder "Moritz" ist.&lt;/li&gt;&lt;li&gt;Liefere alle Projekte, bei welchen Personen mit Vorname "Max" oder "Moritz" beteiligt sind.&lt;/li&gt;&lt;/ol&gt;Die erste Abfrage kann einfach mit dem dynamischen Finder findAllBy*InList [1] in Grails realisiert werden.&lt;br /&gt;&lt;pre class="java" name="code"&gt;def firstnames = ["Max", "Moritz"]&lt;br /&gt;def result = Person.findAllByFirstnameInList(firstnames)&lt;/pre&gt;&lt;br /&gt;Die zweite Abfrage kann nicht mehr über einen dynamischen Finder abgehandelt werden. Hierfür verwenden wir ein Criteria [2]. Criteria-Abfragen sind eine geschickte Möglichkeit, um komplexe Queries in Grails-Syntax relativ übersichtlich zu schreiben. Die zweite Abfrage lässt sich wie folgt realisieren:&lt;br /&gt;&lt;pre class="java" name="code"&gt;def firstnames = ["Max", "Moritz"]&lt;br /&gt;def c = Project.createCriteria()&lt;br /&gt;def result = c.list() {&lt;br /&gt;persons {&lt;br /&gt;    inList("firstname", firstnames)&lt;br /&gt;}&lt;br /&gt;resultTransformer Criteria.DISTINCT_ROOT_ENTITY&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Innerhalb der list-Closure des Criterias kann auf die einzelnen Attribute der Domain-Klasse zugegriffen werden - im Beispiel greifen wir auf die Assoziation "persons" zu. Mit der nächsten Closure wird sichergestellt, dass nur jene Personen zurückgeliefert werden, deren Vorname in der angegebenen Liste enthalten ist.&lt;br /&gt;&lt;br /&gt;Sowohl der findAllBy-Finder als auch das list-Criteria akzeptieren die typischen Parameter wie &lt;span style="font-style: italic;"&gt;max&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;offset&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;sort &lt;/span&gt;oder &lt;span style="font-style: italic;"&gt;order&lt;/span&gt;, die vor allem bei Web-Applikationen für tabellarische Darstellungen unumgänglich sind.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt; Links&lt;/h2&gt;[1] &lt;a href="http://www.grails.org/doc/1.4.x/ref/Domain%20Classes/findAllBy.html" target="_blank"&gt;findAllBy in der Grails-Dokumentation&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://www.grails.org/doc/1.4.x/ref/Domain%20Classes/createCriteria.html" target="_blank"&gt;createCriteria in der Grails-Dokumentation&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-821054521627970407?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/kUYaXfgLXhQ/criteria-list-queries-bei-many-to-many.html</link><author>noreply@blogger.com (Manuel Breitfeld)</author><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/12/criteria-list-queries-bei-many-to-many.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-1654020689043310689</guid><pubDate>Tue, 22 Nov 2011 21:32:00 +0000</pubDate><atom:updated>2011-11-22T10:01:00.608+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Datenbank-Migrationen mit Grails</title><description>&lt;b&gt;Problemstellung&lt;/b&gt;&lt;br /&gt;Wird für eine Applikation, die darunterliegende Datenbank ausgetauscht, dann sind im Idealfall keine Änderungen im Anwendungscode notwendig. Dies sollte zumindest gelten wenn die Applikation Standard-SQL einsetzt. Unabhängig davon müssen aber die Daten von der ursprünglichen Datenbank in die Zieldatenbank überspielt werden. Für eine &lt;a href="http://www.grails.org/"&gt;Grails&lt;/a&gt;-Applikation standen wir genau vor dieser Herausforderung, wobei von einer MySQL-Datenbank auf eine PostgreSQL-Datenbank migriert wurde.  &lt;br /&gt;&lt;br /&gt;Hierfür gibt es nun mehrere Möglichkeiten. Relativ einfach erscheint das Durchführen eines Datenbank-Exports, anschließendes modifizieren der Daten und abschließendes  Importieren in PostgreSQL. Leider hat bei keinem der verfügbaren Tools zur Modifizierung (siehe [1]) der Import funktioniert, d.h. die Daten konnten nicht korrekt für PostgreSQL modifiziert werden.  Des Weiteren gibt es kommerzielle Tools wie bspw. easyfrom, die über eine entsprechende Oberfläche die Migration von der Quell- zur Zieldatenbank ermöglichen.  Eine weitere Möglichkeit ist die Verwendung eines Grails-Plugins wie beispielsweise DB Stuff [2]. Mit dem Plugin können Daten aus einer DB in XML abgespeichert werden  und von XML wiederum in eine Datenbank eingelesen werden. &lt;br /&gt;&lt;br /&gt;In unserem Fall traten Probleme bezüglich der unterschiedlichen Datentypen zwischen MySql und PostgreSQL auf. Außerdem ist das Handling von DB-Relationen mit dieser Art von Plugins eher schwierig bzw. nicht möglich. Aufgrund der Historie hatten wir auch einige Spalten im Originalschema, für die es kein Mapping mehr in den Grails-Domain-Klassen gab. Sie waren also unbenutzt und sollten möglichst automatisiert entfernt werden.  &lt;br /&gt;Der Entschluss fiel schließlich zur Erstellung einer eigenen kleinen Migrationssuite. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Migrationsidee&lt;/b&gt;&lt;br /&gt;Die Idee zur Durchführung ist relativ einfach. Über Grails Domain-Klassen werden die Daten aus der alten DB ausgelesen und anschließend werden die Inhalte  der Domain-Objekte direkt in die neue Datenbank gespeichert.  &lt;br /&gt;Folgende Punkte sind hierbei zu beachten und müssen gelöst werden:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Zugriff auf zwei Datenbanken in einer Grails-Applikation&lt;/li&gt;&lt;li&gt;Transaktionen: Abhängig von der Datenmenge ist ein entsprechendes Transaktionshandling notwendig&lt;/li&gt;&lt;li&gt;Definition von fachlichen Schlüsseln, um Relationen in der Ziel-Datenbank wieder zu erstellen&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Migrationsdurchführung&lt;/b&gt;&lt;br /&gt;Für den Zugriff auf zwei Datenbanken wurde das Datasources Plugin [3] eingesetzt. Die Standard-Konfiguration für Datenbanken in der Datei DataSource.groovy zeigte auf die alte DB und war wie bisher mit allen bestehenden Domain-Klassen verknüpft. &lt;br /&gt;Die bestehenden Domain-Klassen wurden alle in ein neues Package kopiert und über das Datasources Plugin mit der neuen DB verknüpft.  Hierfür können, wie nachfolgend dargestellt, in der Konfigurations-Datei des Plugins die zu verknüpfenden Domain-Klassen angegeben werden.  Des Weiteren kann auch angegeben werden welche Services per Default auf die konfigurierte Data-Quelle zugreifen.   &lt;br /&gt;&lt;pre class="java" name="code"&gt;datasources = {&lt;br /&gt; datasource(name: 'dsPostgresMigration') {&lt;br /&gt;  domainClasses([com.exensio.timesheet.migrate.RenderReportLevel,...])&lt;br /&gt;  readOnly(false)&lt;br /&gt;  pooled(true)&lt;br /&gt;  dialect(org.hibernate.dialect.PostgreSQLDialect)&lt;br /&gt;  driverClassName('org.postgresql.Driver')&lt;br /&gt;  url('jdbc:postgresql://192.168.11.211:5432/extime')&lt;br /&gt;  username('...')&lt;br /&gt;  password('...')&lt;br /&gt;  dbCreate('update') &lt;br /&gt;  pooled(true)&lt;br /&gt;  services(['migration'])&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Für die eigentliche Migration ist der MigrationService zuständig. Der Service enthält für jedes zu migrierende Domain-Klassen-Geflecht eine Methode.  Im einfachsten Fall führt eine Methode die Migration für genau eine Domain-Klasse und damit Datenbanktabelle durch. Das nachfolgende Code-Fragment zeigt wie im ersten Schritt alle zu migrierenden Domain-Objekte ausgelesen werden. Anschließend wird über diese iteriert und bei jedem  Schleifendurchlauf alle Attribute bis auf die technische ID vom alten Domain-Objekt in ein neu erstelltes Domain-Objekt kopiert und gespeichert.  &lt;br /&gt;&lt;pre class="java" name="code"&gt;def migrateRenderReportLevel() {&lt;br /&gt; def renderReportLevels = com.exensio.timesheet.RenderReportLevel.list()&lt;br /&gt; def domainClass = new DefaultGrailsDomainClass(RenderReportLevel.class)&lt;br /&gt;&lt;br /&gt; renderReportLevels.each {oldDomainObject -&amp;gt;&lt;br /&gt;  def newDomainMap = [:]&lt;br /&gt;  domainClass.persistentProperties.each { property -&amp;gt;&lt;br /&gt;   newDomainMap[property.name] = oldDomainObject[property.name]&lt;br /&gt;  }&lt;br /&gt;  RenderReportLevel newDomainObject = new RenderReportLevel(newDomainMap)&lt;br /&gt;  newDomainObject.save(flush: true)&lt;br /&gt;  if (newDomainObject.hasErrors()) {&lt;br /&gt;   handleErrors(newDomainObject)&lt;br /&gt;  }&lt;br /&gt;  else {&lt;br /&gt;   log.info "${newDomainObject.class.simpleName} ${oldDomainObject.id} migrated"&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Durch die Nutzung eines Service und die Aufspaltung in mehrere Methoden kann der Ablauf der Migration einfach in mehrere Transaktionen eingeteilt werden.  Die Hauptschwierigkeit bei der Migration ist die Auflösung der Beziehungen. In vielen Fällen kann die Migration über mehrere Objekte in einer Methode direkt erfolgen. Allerdings gibt es auch Domain-Klassen, die von mehreren anderen referenziert werden. Hier ist darauf zu achten, dass die Migration nur einmal erfolgt und die Beziehungen anschließend über fachliche Schlüssel erstellt werden.  &lt;br /&gt;In unserem Fall gibt es die beiden Domain-Klassen User und Role, die in einer Methode migriert wurden. Die Klasse User wird auch von der Klasse Project referenziert,  die wiederum in einer separaten Methode migriert wurde. Diese Migration-Methode sucht sich über den eindeutigen Login-Namen den entsprechenden User aus der Tabelle und setzt die Beziehung.  &lt;br /&gt;&lt;pre class="java" name="code"&gt;Employee existing = Employee.findByUsername(oldDomainObject.projectManager.username)&lt;br /&gt;if (existing) {&lt;br /&gt; newDomainObject.projectManager = existing&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Zusammenfassung&lt;/b&gt;&lt;br /&gt;Das vorgestellte Verfahren für eine Datenbankmigration erfordert zwar etwas Programmierarbeit, ist aber dank Grails in kurzer Zeit umzusetzen.  Es bietet sich insbesondere an wenn bei der Migration Sonderfälle zu beachten sind, wie bspw. das Entfernen nicht mehr benötigter Spalten.  &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Links&lt;/b&gt;&lt;br /&gt;[1] &lt;a href="http://wiki.postgresql.org/wiki/Converting_from_other_Databases_to_PostgreSQL#MySQL" target="_blank"&gt;Converting from other Databases to PostgreSQL&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://grails.org/plugin/db-stuff" target="_blank"&gt;DB Stuff Plugin&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://grails.org/plugin/datasources" target="_blank"&gt;Datasources Plugin&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-1654020689043310689?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/9yKV9nznsyw/datenbank-migrationen-mit-grails.html</link><author>noreply@blogger.com (Tobias Kraft)</author><thr:total>3</thr:total><georss:featurename>Spessart, 76275 Ettlingen, Deutschland</georss:featurename><georss:point>48.913343 8.433569</georss:point><georss:box>48.9081255 8.4236985 48.9185605 8.4434395</georss:box><feedburner:origLink>http://blog.exensio.de/2011/11/datenbank-migrationen-mit-grails.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-6224734467127204107</guid><pubDate>Sun, 20 Nov 2011 16:16:00 +0000</pubDate><atom:updated>2011-11-20T18:05:01.337+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Usability</category><title>Verbesserung der Usability mittels Faceted Search</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-dEPy8LFtCTw/Tsko-Z5CD7I/AAAAAAAAAMw/7Ye8W1JKJos/s1600/search.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="174" src="http://2.bp.blogspot.com/-dEPy8LFtCTw/Tsko-Z5CD7I/AAAAAAAAAMw/7Ye8W1JKJos/s200/search.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;Die Idee der Faceted Search basiert auf der Facettenklassifikation [1][2]. Diese wurde 1933 von dem indischen Mathematiker und Bibliothekar S. R. Ranganathan [3] entwickelt, um die Bestände der Universitätsbibliothek von Madras zu katalogisieren. Bei der Facettenklassifikation werden Objekte des Wissensbereichs nicht in eine starre Baumstruktur eingegliedert, sondern durch mehrere voneinander unabhängige Gesichtspunkte definiert. In folgendem Blogeintrag möchte ich kurz beschreiben, wie User mittels Faceted Search schneller und präziser Informationen finden können und somit die Usability von (Web-) Applikationen gesteigert werden kann.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Anwendungsbeispiele&lt;/b&gt;&lt;br /&gt;Die Faceted Search ist heute vor allem bei Online Shops anzutreffen. Als prominentestes Beispiel kann hier Amazon genannt werden. Die Faceted Search setzt sich jedoch auch immer mehr bei der Verwaltung und späteren Suche von Informationen, wie Dokumenten oder Emails durch. Als Beispiel kann hier Google Mail betrachtet werden. Im Vergleich zu Outlook werden Mails nicht hierarchisch abgelegt, sondern mit Label versehen. Label sind auch unter dem Begriff Tag bekannt. Eine Hierarchie lässt sich beispielsweise unter Benutzung von Pfadnamen realisieren, wie es auch bei Google Mail gemacht wird.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Vorteile&lt;/b&gt;&lt;br /&gt;Beim Ablegen von Dokumenten trifft man oft auf die Problematik, dass ein Dokument eigentlich in &amp;nbsp;mehreren Knoten einer Baumstruktur abgelegt werden soll. Dies ist bei einer starren Baumstruktur nicht möglich (Google Mail versus Outlook). Bei der Faceted Search werden die Dokumente mit Tags versehen (verschlagwortet) und können später in verschiedenen Knoten angezeigt (gefiltert)werden. Ein Nebeneffekt der Verschlagwortung ist, dass die Dokumente eindeutig klassifiziert werden. Dies hat den großen Vorteil – im Vergleich zu einer Volltextsuche, dass Informationen präziser und schneller gefunden werden können. Bei einer Volltextsuche wird für die Dokumente beim Indizieren ein Wortvektor ermittelt. In der Suchergebnismenge wird dann die Relevanz eines Suchbegriffs über den Wortvektor ermittelt. Das Problem hierbei ist, dass die Relevanz nur eine Annäherung darstellt. Der semantische Bezug zum eigentlichen Suchwort ist meist nicht gegeben. So erreicht beispielsweise Google erst unter Einbeziehung von Wikipedia bessere Suchergebnisse.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Voraussetzung für den Einsatz einer Faceted Search&lt;/b&gt;&lt;br /&gt;Die wichtigste Voraussetzung für die Benutzung von Faceted Search ist die Erstellung einer Tag Taxonomie. &amp;nbsp;Diese kann beispielweise aus der Menüstruktur abgeleitet werden. Wichtiger Tipp hier ist, nicht mehr als 4 Hierarchieebenen aus der Menüstruktur zu übernehmen. &amp;nbsp;Die Tags werden dann später zur Verschlagwortung durch den Editor herangezogen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Beispiel&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-xTKMGbGiTjw/TskoKzX01tI/AAAAAAAAAMo/29C8cxm5gUE/s1600/Dokumente.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-xTKMGbGiTjw/TskoKzX01tI/AAAAAAAAAMo/29C8cxm5gUE/s320/Dokumente.png" width="282" /&gt;&lt;/a&gt;&lt;/div&gt;Als Beispiel (siehe Wireframe rechts) möchte ich das Dokumenten-Center unserer &lt;a href="http://exensio.blogspot.com/2011/05/unsere-enterprise-20-plattform.html"&gt;Enterprise 2.0 Applikation&lt;/a&gt; heranziehen. Auf der linken Seite wird die Faceted Search angezeigt. In unserem Fall ist sie hierarchisch. Eine flache Struktur wäre auch denkbar. &amp;nbsp;Durch das Markieren der Check-Boxen wird die Suchergebnismenge in der Mitte eingeschränkt, sprich die Dokumente werden gefiltert. Auf der rechten Seite sind technische Filter (oder Navigatoren) platziert, mit denen die Suchergebnismenge nochmals um Aspekte, wie Dokumententyp oder Zeitraum eingeschränkt werden können.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fazit&lt;/b&gt;&lt;br /&gt;In unseren Kundenprojekten haben wir die&amp;nbsp;Erfahrung gemacht, dass Benutzer schneller und präziser die gewünschten Informationen mittels Facted Search - im Vergleich zur Volltextsuche - finden. Hierdurch kann die Usability von (Web-)Applikationen enorm gesteigert werden. Nicht verschweigen sollte man jedoch, dass es eine gewisse Zeit für den Benutzer bedarf, bis er sich von einer hierarchischen Menüstruktur gelöst hat.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Links&lt;/b&gt;&lt;br /&gt;[1] &lt;a href="http://de.wikipedia.org/wiki/Facettenklassifikation"&gt;http://de.wikipedia.org/wiki/Facettenklassifikation&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://de.wikipedia.org/wiki/Colon-Klassifikation"&gt;http://de.wikipedia.org/wiki/Colon-Klassifikation&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://de.wikipedia.org/wiki/S._R._Ranganathan"&gt;http://de.wikipedia.org/wiki/S._R._Ranganathan&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-6224734467127204107?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/D50R09AnyT4/verbesserung-der-usability-mittels.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-dEPy8LFtCTw/Tsko-Z5CD7I/AAAAAAAAAMw/7Ye8W1JKJos/s72-c/search.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/11/verbesserung-der-usability-mittels.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-13369217851198519</guid><pubDate>Sun, 30 Oct 2011 15:36:00 +0000</pubDate><atom:updated>2011-11-24T11:44:12.546+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Excel</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Excel Prozesse und warum es sinnvoll ist, diese durch Grails Web Applikationen zu ersetzen</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-WwyiVSpMDJg/Tq1uK0BOVZI/AAAAAAAAAKY/gL7viKdDkJ4/s1600/processSmall.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://4.bp.blogspot.com/-WwyiVSpMDJg/Tq1uK0BOVZI/AAAAAAAAAKY/gL7viKdDkJ4/s200/processSmall.jpg" width="150" /&gt;&lt;/a&gt;&lt;/div&gt;Excel gilt in Fachabteilungen als das Schweizer Taschenmesser um verschiedenste Prozesse abzubilden. So ist ein Prozess auf den ersten Blick schnell aufgesetzt und das ohne die Involvierung der IT-Abteilung, die den Fachabteilungen bekanntlich meistens zu langsam ist.&lt;br /&gt;&lt;br /&gt;Als fiktiven Prozess können wir hier beispielsweise den Export eines Excel-Sheets aus dem SAP System heranziehen. Dieses Excel-Sheet wird dann per Mail oder Fileshare zwischen den unterschiedlichen Abteilungen (oder auch mit externen Dienstleistern)  verteilt, die jeweils einen oder mehrere Prozessschritte in diesem Excel-Sheet abarbeiten. Zum Schluss soll dieses Excel Sheet wieder in das SAP System  importiert werden.&lt;br /&gt;&lt;br /&gt;Einige Leser werden sich nun fragen, wo hier das Problem liegt, da ja genauso in ihrem Unternehmen gearbeitet wird. Zunächst einmal funktioniert das Ganze natürlich auch per Excel-Sheet. Es wird jedoch leicht übersehen, dass diese Excel-Prozesse auf Dauer teurer sind, als wenn sie über eine Software-Lösung abgebildet werden.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Was ist an einem Excel-Prozess suboptimal?&lt;/b&gt;&lt;br /&gt;Folgende Punkte können anhand unseres fiktiven Prozesses als nachteilig aufgeführt werden:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Alle im Prozess beteiligten Personen wissen nie, ob sie wirklich die aktuelle Version haben.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Mit MS Sharepoint ist es zwar möglich, ein Excel Sheet in einer Gruppe  zu bearbeiten. Dies hat jedoch den Nachteil, dass keine Drittsysteme eingebunden werden können, mit der Folge, dass sich Falscheingaben – wie beispielsweise eine falsche Email-Adresse – einschleichen können. Diese Informationen sollten jedoch direkt aus den Drittsystemen, wie in diesem Fall aus dem Verzeichnisdienst (beispielsweise Active Directory) gezogen werden.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Sollen externe Dienstleister integriert werden, müsste Sharepoint über ein Extranet geöffnet werden. Viele Firmen scheuen sich jedoch momentan noch, aus Gründen der Sicherheit, Sharepoint nach außen zu öffnen.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Der abschließende Import in das SAP System ist sehr fehleranfällig, da es schon reicht, dass jemand im Excel-Sheet versehentlich eine Falschangabe (beispielweise Formatänderung der Zelle, etc.) gemacht hat.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Alle Prozessbeteiligten müssen über die gleiche Excel-Version verfügen. Dies ist dann vor allem problematisch, wenn externe Dienstleister integriert werden sollen.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Die Unterstützung von mobilen Endgeräten (iPad, iPhone oder Android) ist nicht möglich.&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Was sind die Alternativen?&lt;/b&gt;&lt;br /&gt;Der Königsweg wäre ganz klar, die Prozesse mittels einer unternehmensübergreifen BPM bzw. SOA Strategie abzudecken. Als größtes Problem ist hierbei jedoch aufzuführen, dass solch ein Projekt sehr langwierig ist und die Vorurteile des Fachbereichs gegenüber der IT (zu langsam) sicherlich bekräftigt.&lt;br /&gt;&lt;br /&gt;Ein Mittelweg wäre den Excel Prozess mit einer Web Applikation abzubilden. Wir benutzen hier sehr gerne das Open-Source-Framework &lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt;, mit diesem Framework ist eine schnelle Entwicklung möglich.&lt;br /&gt;&lt;br /&gt;Was wären die Vorteile - am Beispiel - unseres fiktiven Prozesses:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In der ersten Phase könnte der Export und Import des Excel-Sheets aus dem SAP System bestehen bleiben. Es ist natürlich auch möglich, auf das SAP System direkt mittels SAPJco oder Web-Services zuzugreifen. Dies hängt ganz von den Wünschen des Kunden ab.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Alle Prozessbeteiligten erhalten eine aktuelle Sicht auf Ihre Daten. Und nur auf ihre Daten. Wir haben in diesem Kontext schon Excel-Sheets mit 5000 und mehr Zeilen gesehen. Ich denke jeder kann sich vorstellen, dass es hier leicht zu Fehleingaben kommen kann.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Externe Dienstleister können über ein Extranet (z.B. XML-Schnittstelle) bedient werden. Da das &lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt; Framework auf der Java JVM aufbaut, kann hier der gesamte Java Security Stack benutzt werden.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Der abschließende Import in das SAP System könnte direkt über SAPJco oder einen Web-Service erfolgen. Falls der Import über Excel gewählt wird, kann auf jeden Fall sichergestellt werden, dass das zu importierend Excel-Sheet sauber ist.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Fazit&amp;nbsp;&lt;/b&gt;&lt;br /&gt;Auf vielen Veranstaltungen bekommen wir positives Feedback, wenn wir unseren Mittelweg der Excel-Prozess-Optimierung vorstellen. So ist vielen Unternehmen schnell ersichtlich, dass ein Excel-Prozess auf lange Sicht viel teurer kommt, als eine saubere Software-Lösung. Der Mittelweg über eine &lt;a href="http://grails.org/"&gt;Grails&lt;/a&gt; Web Applikation ist somit – aus unserer Sicht – eine sehr gute Lösung für Firmen, die noch nicht bereit sind für den unternehmensübergreifenden BPM/SOA Ansatz.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-13369217851198519?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/4bmsCpEP5S0/excel-prozesse-und-warum-es-sinnvoll.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-WwyiVSpMDJg/Tq1uK0BOVZI/AAAAAAAAAKY/gL7viKdDkJ4/s72-c/processSmall.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/10/excel-prozesse-und-warum-es-sinnvoll.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-114726002024437669</guid><pubDate>Sat, 01 Oct 2011 16:31:00 +0000</pubDate><atom:updated>2011-10-03T17:30:15.360+02:00</atom:updated><title>Wir benutzen nun das CRM System Highrise von 37signals.com</title><description>&lt;br /&gt;Mit diesem Blogeintrag möchte ich kurz über die von uns gesammelten Erfahrungen, bei der Evaluierung unseres neuen CRM Systems, berichten. Bisher haben wir hierzu eine Kombination aus Outlook und Excel benutzt, mit den bei dieser Kombination typischen Problemen. Ein Anlass diesen Prozess zu optimieren bot sich letzte Woche, als wir von einer Veranstaltung zurück kamen. Wir hatten uns vorgenommen, eine kleine Evaluierung durchzuführen und falls wir nicht fündig werden, ein kleines CRM System - basierend auf dem Grails Framework - selbst zu schreiben. Unsere Projekt-Zeiterfassung haben wir bereits - nach einer erfolglosen Suche - mit dem Grails Framework implementiert [1]. Für uns waren folgende Kriterien besonders wichtig:&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-wqLGftW071M/Toc_CLgfR1I/AAAAAAAAAJY/XWV2JhNDZQM/s1600/37signals.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="292" src="http://1.bp.blogspot.com/-wqLGftW071M/Toc_CLgfR1I/AAAAAAAAAJY/XWV2JhNDZQM/s320/37signals.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Source: 37signals.com&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;ul&gt;&lt;li&gt;Die Anwendung sollte sehr einfach zu bedienen sein&lt;/li&gt;&lt;li&gt;Die Anwendung sollte keine lange Einarbeitungszeit erfordern&lt;/li&gt;&lt;li&gt;Die Anwendung sollte als Software as a Service (SaaS) verfügbar sein.&lt;/li&gt;&lt;li&gt;Einfacher Import von Kontakten, ohne ein Browser-Plugin installieren zu müssen&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Welche Anbieter haben wir uns angeschaut?&lt;/b&gt;&lt;br /&gt;Folgende Lösungen sind von uns evaluiert worden:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;CAS PIA [2]&lt;/li&gt;&lt;li&gt;SageCRM.com [3]&lt;/li&gt;&lt;li&gt;Salesforce [4]&lt;/li&gt;&lt;/ul&gt;Schnell mussten wir feststellen, dass unsere Kriterien, wie beispielsweise Einfachheit, von keinem der Systeme erfüllt wurde. Zufällig erinnerten wir uns, dass auf der Homepage der Firma 37signals.com auch ein CRM System angeboten wird. Die Firma 37signals.com ist wohl den meisten als Anbieter der Projektmanagement-Lösung Basecamp bekannt. Aus Basecamp wurde später Ruby on Rails [5] extrahiert und Ruby on Rails ist wiederum der Initiator des Opensource-Projekts Grails[6]. Nun wussten wir, dass wir richtig waren :-).&lt;br /&gt;&lt;br/&gt;&lt;b&gt;Was gefällt uns an Highrise von 37signals.com besonders?&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Das System sehr einfach und selbsterklärend aufgebaut&lt;/li&gt;&lt;li&gt;Die Lösung ist als SaaS verfügbar&lt;/li&gt;&lt;li&gt;Kontakte können einfach mittels Excel, CSV oder vCard importiert werden&lt;/li&gt;&lt;li&gt;Es können verschiedene Drittsystem (z.B. für den Mailversand) als Add-Ons angebunden werden&lt;/li&gt;&lt;li&gt;Wir können Kontakte mit Schlagworten („Tags“) versehen werden. Diese Vorgehensweise ist viel besser, als ein Kommentarfeld.&lt;/li&gt;&lt;li&gt;Emails können mit Outlook versendet werden. In der BCC Zeile gibt man eine Dropbox-Email-Adresse an. Die Mail wird dann automatisch zu dem Activity Stream des Kontakts hinzugefügt. Dies ist einfach nur genial!&lt;/li&gt;&lt;/ul&gt;Weitere Infos zu Highrise finden sich hier [7]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fazit&lt;/b&gt;&lt;br /&gt;Wir sind wirklich sehr begeistert von dieser Lösung. Die anderen Anbieter verfügen selbstredend über einen viel größeren Funktionsumfang. Diesen brauchen wir jedoch nicht. Highrise sollte man bei einer CRM-Evaluierung auf jeden Fall in Betracht ziehen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Links&lt;/b&gt;&lt;br /&gt;[1] &lt;a href="http://exensio.blogspot.com/2010/10/erfahrungsbericht-ablosung-von-excel.html"&gt;Erfahrungsbericht: Ablösung einer Excel-basierten Zeiterfassung durch eine Grails Web-Applikation&lt;/a&gt; &lt;br /&gt;[2] &lt;a href="http://www.cas-pia.de/"&gt;CAS PIA&amp;nbsp;&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://de.sagecrm.com/"&gt;SageCRM.com&lt;/a&gt;&lt;br /&gt;[4]&amp;nbsp;&lt;a href="http://www.salesforce.com/"&gt;Salesforce&lt;/a&gt;&lt;br /&gt;[5] &lt;a href="http://rubyonrails.org/"&gt;Homepage Ruby on Rails&lt;/a&gt;&lt;br /&gt;[6] &lt;a href="http://www.grails.org/"&gt;Homepage Grails Framework&lt;/a&gt;&lt;br /&gt;[7]&amp;nbsp;&lt;a href="http://highrisehq.com/tour/"&gt;Highrise Tour&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-114726002024437669?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/0lwVhmfK_WI/wir-benutzen-nun-das-crm-system.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-wqLGftW071M/Toc_CLgfR1I/AAAAAAAAAJY/XWV2JhNDZQM/s72-c/37signals.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/10/wir-benutzen-nun-das-crm-system.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-5473167057609698220</guid><pubDate>Fri, 30 Sep 2011 16:46:00 +0000</pubDate><atom:updated>2011-10-03T18:32:17.547+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">socialmedia</category><category domain="http://www.blogger.com/atom/ns#">socbiz</category><title>Social Media und das Thema Sicherheit</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-KRav5QbLxh8/TongtZVvVII/AAAAAAAAAJg/zEtmvyn-0Y8/s1600/SocMediaSecurity_small.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="199" src="http://2.bp.blogspot.com/-KRav5QbLxh8/TongtZVvVII/AAAAAAAAAJg/zEtmvyn-0Y8/s200/SocMediaSecurity_small.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;In den letzten Wochen habe ich wieder sehr viele Blog-Posts gelesen, in denen immer wieder mantraartig auf die mangelnde Bereitschaft deutscher Unternehmen, sich mit dem Thema Social Media zu beschäftigen, hingewiesen wird. Laut zahlreicher Studien (z.B. [1]) lehnen demzufolge knapp 86% aller deutschen Unternehmen Social Media aus Sicherheitsgründen ab.&lt;br /&gt;Auf Veranstaltungen zum Thema Social Media wird von Agenturen meist nur aufgezeigt, wie wichtig es ist, dabei zu sein. Sicherheitsthemen werden gerne ausgeblendet, da dies dem neuen Geschäftsfeld nicht zuträglich ist.&lt;br /&gt;Ich möchte hier nicht gegen Social Media wettern, aber ich finde es immer besser, wenn man sich der Gefahr bewusst ist. Nur dann kann adäquat reagiert werden. Des Weiteren ist es meines Erachtens sehr wichtig, die IT-Abteilung von Anfang an, bei den sicherheitsrelevanten Themen, zu involvieren. Ein Alleingang der Marketing- bzw. Personalabteilung ist nicht anzuraten. Aber wo lauern jetzt genau die Gefahren?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ein kleiner Exkurs in die Welt der Virenscanner&lt;/b&gt;&lt;br /&gt;Durch einen Virenscanner wird verhindert, dass sich Schädlinge (Malware) - wie Computerviren, Computerwürmer oder Trojanische Pferde - auf einem PC einnisten können. Hierzu arbeiten die Hersteller vor allem mit 2 Verfahren, den Virensignaturen und Heuristiken (Suche nach Merkmalen eines Computervirus). Leider sind Virenscanner nicht 100% zuverlässig. So können Virensignaturen erst vom Hersteller zum Download angeboten werden, wenn diesem der neue Virustyp bekannt ist (Problem der Zero-Day-Attacke [2]).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Was macht Facebook und Co nun so gefährlich?&amp;nbsp;&lt;/b&gt;&lt;br /&gt;Ein Angriff ohne Social Media benutzt beispielsweise  Massenemails. Bei dieser Angriffsform wird darauf vertraut, dass ein gewisser Prozentsatz unwissentlich auf einen Link klickt. Mit Social Media Netzwerken, wie Facebook, Xing oder Google+ können Angreifer mit einer viel kleineren Anzahl von Mails auskommen und somit (theoretisch) fast punktgenau Malware auf den PC eines Mitarbeiters einschleusen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Wie könnte so ein Angriffsszenario aussehen?&lt;/b&gt;&lt;br /&gt;So kann beispielsweise über Xing der Vor- und Nachname von Mitarbeitern einer bestimmten Firma (und vielfach sogar die Abteilung) ermittelt werden. Dann ist es ein leichtes sich die Emailadressen zusammenzusetzen. Ohne Xing müssten die Emailadressen durchprobiert werden. Die Vornamen würden einer Vornamenliste (die es im Internet gibt) entnommen, die Nachnahmen würden permutiert werden. So wäre beispielsweise meine Email-Adresse sehr schnell ermittelt, da mein Nachname nur aus 4 Buchstaben besteht. Bei dieser Vorgehensweise müssen jedoch sehr viele Mails – auch viele mit falschen Mailadressen – an den Mailserver  der anzugreifenden Firma versendet werden, deshalb wird solch ein Angriff mit einer hohen Wahrscheinlichkeit auffallen.  Bei der Social Media Variante erreichen alle Mails ohne Verdacht die Empfänger. Virenscanner, die im Mailserver installiert sind, können keine Muster erkennen, da es Emails sind, die individuell für einen kleinen Kreis von Adressaten erstellt wurden. Klickt dann ein Mitarbeiter auf einen Link innerhalb der Mail, so wird der Schädling (Malware) heruntergeladen. Diese wird vom Virenscanner wahrscheinlich nicht erkannt, da es sich um einen ganz neuen und individuell für diesen Angriff entwickelten Virus handelt.&lt;br /&gt;Facebook ist aufgrund seiner sehr hohen Anzahl von Mitgliedern besonders interessant für Angreifer, vergleichbar mit Windows in Bezug auf Linux. Aus diesem Grund ist es wohl wahrscheinlicher, sich über Facebook Malware   einzuschleppen, als über Xing. Ein weiteres Sicherheitsproblem ergibt sich bei Facebook und Co. dadurch, dass ich von meinen Kontakten (Freunde und Bekannten) Nachrichten erhalte - und nicht von einer unbekannten Phishing-Mail-Adresse -, die ich für vertrauenswürdig halte. Die Wahrscheinlichkeit, dass ich auf einen Link, der mir von einem Freund über Facebook geschickt wurde,  klicke, ist somit weitaus größer. Durch Social Media erhalten Angreifer somit erstmalig die Möglichkeit sehr gezielte Angriffe durchzuführen.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fazit&lt;/b&gt;&lt;br /&gt;Durch Social Media wird eine neue Qualität von Angriffen stattfinden. Jedes Unternehmen muss für sich den Nutzen und die Gefahren von Social Media abwägen. Folgende Punkte sind meines Erachtens beim Einstieg in diese Thematik zu beachten:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Mitarbeiter müssen für das Thema Sicherheit im Kontext von Social Media sensibilisiert werden. Wichtig wäre es auch, eine IT-Security-Strategie in den Social Media Guide mit aufzunehmen. Hier könnte dann auch verankert werden, dass es beispielsweise wichtig ist, ein sicheres Passwort bei Facebook und Co. zu verwenden.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Brauchen alle Mitarbeiter Zugriff auf Social Media? Dies ist eine wichtige Frage. Meistens benötigt nur die Marketing oder Corporate Communications Abteilung einen direkten Zugang. Die restlichen Mitarbeiter könnten sich auch über Ihr Smart-Phone - während der Mittagspause - bei Facebook oder Xing einwählen. Den Zugriff der Marketingabteilung könnte man beispielsweise über eine Bitbox [3] absichern.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Des Weiteren wäre die Benennung eines zentralen Ansprechpartners wichtig. Zum einen können sich Mitarbeiter mit Fragen an diese Person wenden und zum anderen kann diese Person dann das Krisenmanagement koordinieren. Social Media wird zukünftig ein weiteres Aufgabengebiet für den Chief Security Officer darstellen.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Links&lt;/b&gt;&lt;br /&gt;[1] &lt;a href="http://www.itespresso.de/2011/09/12/studie-deutsche-unternehmen-blocken-social-media-am-haufigsten/"&gt;http://www.itespresso.de/2011/09/12/studie-deutsche-unternehmen-blocken-social-media-am-haufigsten/&lt;/a&gt;&lt;br /&gt;[2]&lt;a href="http://de.wikipedia.org/wiki/Zero-Day-Exploit#Zero-Day-Exploit"&gt; http://de.wikipedia.org/wiki/Zero-Day-Exploit#Zero-Day-Exploit&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://www.sirrix.de/content/pages/BitBox"&gt;http://www.sirrix.de/content/pages/BitBox&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Weitere Infos zu diesem Thema&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.heise.de/newsticker/meldung/Klick-Diebstahl-auf-Facebook-breitet-sich-aus-1207165.html"&gt;http://www.heise.de/newsticker/meldung/Klick-Diebstahl-auf-Facebook-breitet-sich-aus-1207165.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://exensio.blogspot.com/2011/07/facebook-und-die-problematik-mit-der.html"&gt; http://exensio.blogspot.com/2011/07/facebook-und-die-problematik-mit-der.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-5473167057609698220?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/YvE-PJZ7V4o/social-media-und-das-thema-sicherheit.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-KRav5QbLxh8/TongtZVvVII/AAAAAAAAAJg/zEtmvyn-0Y8/s72-c/SocMediaSecurity_small.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/09/social-media-und-das-thema-sicherheit.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-5533212688736736404</guid><pubDate>Thu, 25 Aug 2011 13:32:00 +0000</pubDate><atom:updated>2011-08-25T17:26:12.471+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">solr</category><category domain="http://www.blogger.com/atom/ns#">e20</category><category domain="http://www.blogger.com/atom/ns#">User Interface</category><title>Das Such-Interface in der exensio Enterprise 2.0 Plattform</title><description>Im Artikel &lt;a href="http://exensio.blogspot.com/2011/07/fuzzy-search-und-meinten-sie-in-solr.html"&gt;Fuzzy Search und "Meinten Sie?" in Apache Solr&lt;/a&gt; habe ich bereits erwähnt, dass wir in unserer &lt;a href="http://exensio.blogspot.com/2011/05/unsere-enterprise-20-plattform.html"&gt;Enterprise 2.0 Plattform&lt;/a&gt; auf Apache Solr als Suchmaschine setzen. In diesem Artikel gehe ich auf das User Interface unserer Suche innerhalb unseres Portals ein.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Prinzipien eines User Interfaces einer Suche&lt;/h2&gt;In jeder besseren Suche kann man nicht nur nach Begriffen suchen - man kann auch im Anschluss die zurückgelieferte Ergebnismenge mithilfe nützlicher Filter weiter einschränken. Bekannte Filteroptionen sind unter anderem das Datum oder der Dateityp.
&lt;br /&gt;
&lt;br /&gt;Hilfreich sind solche Filter insbesondere dadurch, dass man die gesamte Ergebnismenge schrittweise (per Klick) verfeinern kann, um letztendlich aus einem großen "Topf" an Daten die relevanten Informationen zu erhalten.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Einsatz innerhalb des Enterprise 2.0 Portals&lt;/h2&gt;In unserem Portal ist die Suche eine zentrale Komponente, die in verschiedenen Portlets zur Filterung der Inhalte verwendet wird. Im Folgenden gehe ich auf das User Interface der "eigenständigen" Suche ein.&lt;ol&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Eingabe von Suchbegriffen:&lt;/b&gt; Eingegeben werden kann alles, was Apache Solr unterstützt. Eine Übersicht über die Syntax und die boolschen Operatoren findet sich unter [1].&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Auto-complete:&lt;/b&gt; Dabei werden die Auto-complete Vorschläge zur Laufzeit anhand der aktuell im Index vorhandenen Daten über Apache Solr ermittelt.&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Administrations-Tools:&lt;/b&gt; Nützliche Funktionen rundum die Indizierung können von berechtigten Benutzern direkt über die Suchseite aufgerufen werden.&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Sortierung:&lt;/b&gt; Die Sortierung nach Relevanz ist Standard und erfolgt über den von Apache Solr ermittelten Score. Alternativ wird eine Sortierung nach Datum angeboten.&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Filter (Navigatoren/Facets):&lt;/b&gt; Die Filter lassen sich in unterschiedliche Kategorien einteilen. Sie können benutzt werden, um Dokumente nach Datum, Typ, Autor, Kategorie o.ä. zu filtern. In &lt;b&gt;Screenshot 2&lt;/b&gt; ist dargestellt, wie sich solche Filter sukzessive anwenden lassen um von einer großen Ergebnismenge auf ein paar gezielt herausgesuchte Ergebnisse zu kommen.&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Meta-Informationen:&lt;/b&gt; Jeder Treffer enthält nützliche Meta-Informationen wie das Datum der letzten Aktualisierung oder - im Fall von Dokumenten - die Dateigröße.&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Teaser und Highlighting:&lt;/b&gt; Zu jedem Treffer wird ein Teaser angezeigt, bei dem die gesuchten Begriffe hervorgehoben werden.&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Blätterung:&lt;/b&gt; Die Blätterung erlaubt das schnelle Durchsuchen der Ergebnismenge.&lt;/li&gt;
&lt;br /&gt;&lt;li&gt;&lt;b&gt;Tag-Cloud:&lt;/b&gt; Die Tag-Cloud kann über beliebige Informationen gebildet werden. In diesem Fall werden die am häufigsten Begriffe, die im Kontext des aktuellen Suchbegriffs auftauchen, angezeigt (groß = häufig, klein = weniger häufig). Gleiches lässt sich auch problemlos auf strukturierte Daten wie Tags anwenden.&lt;/li&gt;
&lt;br /&gt;&lt;/ol&gt;
&lt;br /&gt;&lt;h2&gt;Screenshots der Suche&lt;/h2&gt;&lt;table class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;" align="center" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;
&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-hI65bqSJwPA/TlZbP9oCkcI/AAAAAAAAACw/K9P0jXlLQYM/s1600/exensio-enterprise20-search-tooltips.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 324px; height: 400px;" src="http://2.bp.blogspot.com/-hI65bqSJwPA/TlZbP9oCkcI/AAAAAAAAACw/K9P0jXlLQYM/s400/exensio-enterprise20-search-tooltips.png" alt="" id="BLOGGER_PHOTO_ID_5644799512754164162" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Suche nach exensio GmbH&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;
&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-L__aK0IVm4w/TlZcYzHD4SI/AAAAAAAAAC4/zYW1qQAbd7I/s1600/exensio-enterprise20-search-active-filter.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 339px;" src="http://3.bp.blogspot.com/-L__aK0IVm4w/TlZcYzHD4SI/AAAAAAAAAC4/zYW1qQAbd7I/s400/exensio-enterprise20-search-active-filter.png" alt="" id="BLOGGER_PHOTO_ID_5644800764061933858" border="0" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Suche nach exensio GmbH mit anschließender Filterung auf Blog-Beiträge mit Tag "exensio" im Zeitraum ab 1. August 2011&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;[1] &lt;a href="http://lucene.apache.org/java/3_3_0/queryparsersyntax.html"&gt;http://lucene.apache.org/java/3_3_0/queryparsersyntax.html&lt;/a&gt;
&lt;br /&gt;[2] &lt;a href="http://wiki.apache.org/solr/SolrRelevancyCookbook"&gt;http://wiki.apache.org/solr/SolrRelevancyCookbook&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-5533212688736736404?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/uUZ2TmfYxgU/das-such-interface-in-der-exensio.html</link><author>noreply@blogger.com (Manuel Breitfeld)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-hI65bqSJwPA/TlZbP9oCkcI/AAAAAAAAACw/K9P0jXlLQYM/s72-c/exensio-enterprise20-search-tooltips.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/08/das-such-interface-in-der-exensio.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-7562316286708896806</guid><pubDate>Sat, 20 Aug 2011 14:14:00 +0000</pubDate><atom:updated>2011-08-20T16:14:58.430+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Open-Source</category><category domain="http://www.blogger.com/atom/ns#">Kettle</category><category domain="http://www.blogger.com/atom/ns#">ETL</category><category domain="http://www.blogger.com/atom/ns#">DWH</category><title>ETL-Prozesse mit Pentaho Kettle umsetzen</title><description>&lt;div&gt;Ein wichtiger Aspekt beim Aufbau eines Data Warehouses ist der Befüllungs-Prozess, der über den sogenannten ETL-Vorgang [1] erfolgt. Hierbei werden Daten von verschiedenen Quell-Systemen extrahiert, anschließend ggfs. transformiert und im abschließenden Schritt in das Data Warehouse geladen. &lt;br /&gt;Zur Unterstützung des  ETL-Vorgangs stehen zahlreiche Tools aus dem kommerziellen und Open-Source Umfeld zur Verfügung. Generell bringen Data Warehouse Lösungen selbst schon ein entsprechendes Tool bzw. Toolunterstützung mit. &lt;br /&gt;Alternativ kann man natürlich den gesamten ETL-Prozess auch „von Hand“ umsetzen. Dies ist aufgrund der Komplexität mit einem entsprechenden Aufwand verbunden. Deshalb wird i.d.R. auf ETL-Tools zurückgegriffen, die vor allen Dingen die folgenden Anforderungen erfüllen: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Integration von verschiedenen Quell-Systemen&lt;/li&gt;
 &lt;li&gt;Skalierbarkeit&lt;/li&gt;
 &lt;li&gt;Erweiterbarkeit für die Integration von weiteren Systemen&lt;/li&gt;
 &lt;li&gt;Unterstützung für Daten-Transformationen (z.B. Aggregation, Filterung, …)&lt;/li&gt;
 &lt;li&gt;ausführliche Test-, Debug- und Logging-Möglichkeiten&lt;/li&gt;
 &lt;/ul&gt;&lt;br /&gt;Ein ausgereiftes ETL-Tool, das unter anderem diese Anforderungen erfüllt ist Kettle. Kettle ist ein Open-Source Produkt und stammt von der Firma Pentaho [2], die auch die gleichnamige DWH- bzw. BI-Lösung anbietet. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Kettle in der Entwicklung&lt;/b&gt; &lt;br /&gt;Dreh- und Angelpunkt ist in Kettle das Designer-Tool Spoon. Mit dessen Unterstützung werden die sogenannten Jobs und Transformationen definiert. Die Transformationen sind für das eigentliche ETL-Handling zuständig. Jobs sind dagegen für die Einhaltung der Reihenfolge sowie die Verwaltung (z.B. auch Fehlerhandling)  verantwortlich und können mehrere Transformationen enthalten. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-epvnQRVy2_M/TkDQMoKzWYI/AAAAAAAAAME/nCgt7trsF_o/s1600/kettle_sample_tranf.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 298px;" src="http://4.bp.blogspot.com/-epvnQRVy2_M/TkDQMoKzWYI/AAAAAAAAAME/nCgt7trsF_o/s320/kettle_sample_tranf.png" alt="" id="BLOGGER_PHOTO_ID_5638735648827595138" border="0" /&gt;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;Die vorherige Abbildung zeigt eine Transformation in der Designer-Sicht von Spoon. Im ersten Schritt werden aus einem Verzeichnis CSV-Dateien eingelesen. Beim Einlesen kann über einen Regex-Ausdruck  definiert werden welche Dateien eingelesen werden. Aus den CSV-Dateien werden die benötigten Werte extrahiert und bei Bedarf auch formatiert. Da die Daten in ein relationales Datenbankschema geladen werden sollen müssen zunächst entsprechende Fremdschlüssel über Lookups ermittelt werden. Nach der Ermittlung des nächsten freien Primärschlüssels für die Zieltabelle kann abschließend die Einfüge-Operation vorgenommen werden. &lt;br /&gt;&lt;br /&gt;Der Aufbau der Transformation sowie die Definition der einzelnen Schritte wurden allesamt mit Spoon vorgenommen. Das vorgestellte Beispiel zeigt nur eine kleine Auswahl an möglichen Schritten, die durchgeführt werden können. Spoon bietet ein sehr große Palette an vordefinierten Elementen, die für Transformationen eingesetzt werden können (z.B. Ausführung von Pragrammcode zur Konvertierung oder FTP-Transfer zum Abholen von Dateien). &lt;br /&gt;&lt;br /&gt;Das Testen und Debuggen der Transformation wird direkt in Spoon durchgeführt und ermöglicht so eine schnelle Verifikation. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fazit&lt;/b&gt; &lt;br /&gt;Würde  man die vorgestellte Transformation komplett in Eigenarbeit umsetzen wäre ein wesentlich höherer Zeitaufwand notwendig und auch Erweiterungen bzw. Änderungen würden  höher zu Buche schlagen. Kettle eignet sich, aufgrund seiner zahlreichen Funktionen, neben der Nutzung als ETL Tool auch zur Durchführung von Migrations-Projekten oder als Import-Werkzeug für Daten in OLTP-Datenbanken. &lt;br /&gt;&lt;br /&gt;Kettle ist ein ausgereiftes und verbreitetes Werkzeug, was sich in der Statistik mit ca. 15.000 Downloads pro Monat bei Sourceforge [3] widerspiegelt. &lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://en.wikipedia.org/wiki/Extract,_transform,_load"&gt;http://en.wikipedia.org/wiki/Extract,_transform,_load&lt;/a&gt; &lt;br /&gt;[2] &lt;a href="http://www.pentaho.com/"&gt;http://www.pentaho.com/&lt;/a&gt; &lt;br /&gt;[3] &lt;a href="http://sourceforge.net/projects/pentaho/files/Data%20Integration/stats/timeline"&gt;http://sourceforge.net/projects/pentaho/files/Data%20Integration/stats/timeline&lt;/a&gt; &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-7562316286708896806?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/mO4firrkvFA/etl-prozesse-mit-pentaho-kettle.html</link><author>noreply@blogger.com (Tobias Kraft)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-epvnQRVy2_M/TkDQMoKzWYI/AAAAAAAAAME/nCgt7trsF_o/s72-c/kettle_sample_tranf.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/08/etl-prozesse-mit-pentaho-kettle.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-6830608629766824954</guid><pubDate>Fri, 19 Aug 2011 16:12:00 +0000</pubDate><atom:updated>2011-10-03T17:33:33.528+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Portal</category><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Building a Portal with Grails-Framework</title><description>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;In this blog post I will describe how we have implemented a web portal by using only the Grails Framework [1]. Our approach differs from the Grails Portlets Plugin in the fact, that in our case the portlets are running directly in a Grails application and not as a JSR 168 portlet in a Liferay portal.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why do we need a Grails Portal?&lt;/b&gt;&lt;br /&gt;exensio has a long experience in the development of portal solutions. So far we have used portal solutions from the major manufacturers like Oracle. On the other hand, we use the Grails framework for developing Web applications more and more. Thus the idea &amp;nbsp;to combine both was close. Our solution offers the possibility to embed a Grails controller as a portlet within a Grails application. Below I've included screenshots showing this feature.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Building Blocks of the Grails Portal&lt;/b&gt;&lt;br /&gt;A portal consists mainly of the following building blocks:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Portal&lt;/li&gt;&lt;li&gt;Page contains one or more portlets. A Portal can contain one or more pages.&lt;/li&gt;&lt;li&gt;Portlet-Instance of a Portlet. Each Portlet can reside on the same or another page.&lt;/li&gt;&lt;li&gt;Portlet Preferences. Each portlet can have specific preferences. For instance, &amp;nbsp;a path to the root node of content.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The wireframe below depicts these building blocks:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-fTm5UTQTeXw/Tk6EpExAXEI/AAAAAAAAAFE/XLSvleqVU_k/s1600/mockup.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="185" src="http://4.bp.blogspot.com/-fTm5UTQTeXw/Tk6EpExAXEI/AAAAAAAAAFE/XLSvleqVU_k/s320/mockup.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;The Link Issue of the Grails Portal&lt;/b&gt;&lt;br /&gt;The generation of links must be implemented in a portal different than in a Grails application. The problem in a portal is that a click on a link must be redirected to the portlet on which the click has been executed.&lt;br /&gt;There are different ways to solve this problem. The easiest way is to use Ajax or Flash to implement the portlets. This was not our preferred solution. Our solution should be based on standard GSP pages. We solved the link problem by implementing a portal controller which gets the requests first. A link in our Grails Portal looks the following:&lt;br /&gt;&lt;br /&gt;http://server:port/enterprise20/default/MicroBlog?po_67_portlet_action=save#po_67&lt;br /&gt;&lt;br /&gt;The link contains all the necessary information like portal (since the portal can contain one or more portals), page, portlet instance and the action which should be executed in the instance of that portlet. The portal controller loops over all the portlets which reside on the executed page, renders each portlet and returns the whole portal page back to the browser.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Some Screenshots showing the Functionality&lt;/b&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-m6CyHMIQ9ug/Tk6Ht_zzyFI/AAAAAAAAAFI/npW2XtHr6cI/s1600/e20_01.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-m6CyHMIQ9ug/Tk6Ht_zzyFI/AAAAAAAAAFI/npW2XtHr6cI/s400/e20_01.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Grails Portal displaying two portlets&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-tSh6ROA17ZM/Tk6IzIUwOCI/AAAAAAAAAFQ/92UsMbTULts/s1600/e20_02.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-tSh6ROA17ZM/Tk6IzIUwOCI/AAAAAAAAAFQ/92UsMbTULts/s400/e20_02.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Adding new values to portlet on right hand side.&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-yeErm_8j-Fk/Tk6JMIa3FkI/AAAAAAAAAFU/uKgeCUzGL_s/s1600/e20_03.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-yeErm_8j-Fk/Tk6JMIa3FkI/AAAAAAAAAFU/uKgeCUzGL_s/s400/e20_03.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Error is shown at portlet level.&amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-fEac5o3Cf0o/Tk6JqGfYjpI/AAAAAAAAAFY/eWGWsDYTKHI/s1600/e20_04.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-fEac5o3Cf0o/Tk6JqGfYjpI/AAAAAAAAAFY/eWGWsDYTKHI/s400/e20_04.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Page is shown after entering correct value.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusion&lt;/b&gt;&lt;br /&gt;As you can see it is possible to implement a portal based on the Grails framework. This portal acts like a portal from the major vendors but is much easier and faster to implement. &lt;br/&gt;&lt;br/&gt;&lt;b&gt;Links&lt;/b&gt;&lt;/br&gt;[1] &lt;a href="http://www.grails.org/"&gt;Homepage Grails Framework&lt;/a&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-6830608629766824954?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/t9N6QdgNhEo/building-portal-with-grails-framework.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-fTm5UTQTeXw/Tk6EpExAXEI/AAAAAAAAAFE/XLSvleqVU_k/s72-c/mockup.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/08/building-portal-with-grails-framework.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3889531953038227766</guid><pubDate>Tue, 09 Aug 2011 07:33:00 +0000</pubDate><atom:updated>2011-12-22T17:34:23.940+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">exensio</category><title>exensio bekommt Nachwuchs ...</title><description>natürlich nicht exensio, sondern unser Kollege Xuetao ist Vater geworden. Hierzu wollen wir auf diesem Weg noch einmal recht herzlich gratulieren. Aufgrund des Fachkräftemangels in Deutschland wollen wir sogleich den Nachwuchs unseres Kollegen an die Firma binden. Hierzu kamen wir auf die geniale Idee, einen Strampler mit dem exensio Firmenlogo zu verschenken :-)&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-JitBoogVXzg/Tj-ZA0y8icI/AAAAAAAAAB8/RT11GBJGpVQ/s1600/xuetao_baby.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-JitBoogVXzg/Tj-ZA0y8icI/AAAAAAAAAB8/RT11GBJGpVQ/s320/xuetao_baby.png" width="240" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-3889531953038227766?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/fYsT_tRqLhc/exensio-bekommt-nachwuchs.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-JitBoogVXzg/Tj-ZA0y8icI/AAAAAAAAAB8/RT11GBJGpVQ/s72-c/xuetao_baby.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/08/exensio-bekommt-nachwuchs.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-3671407778930282876</guid><pubDate>Mon, 08 Aug 2011 09:30:00 +0000</pubDate><atom:updated>2011-10-03T17:35:38.189+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Grails</category><title>Grails Entwicklung mit IntelliJ</title><description>&lt;div&gt;Ein guter Editor reicht dem Puristen für die Entwicklung von Grails Applikationen aus. Werden die Projekte größer stellt sich jedoch die Frage, welche Entwicklungsumgebung (IDE) benutzt werden soll. Aktuell gibt es zwei IDEs, die in der Grails-Entwicklergemeinde benutzt werden:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SpringSource Tool Suite (STS) [1]&lt;br /&gt;STS basiert auf Eclipse, dies hat den Vorteil, dass das reichhaltige Angebot von Eclipse-Plugins benutzt werden kann. Dies hat jedoch auch den Nachteil, dass ein schlecht implementiertes Plugin das ganze Eclipse runterreißen kann.&lt;/li&gt;&lt;li&gt;IntelliJ IDEA [2]&lt;br /&gt;Basiert nicht auf Eclipse. Im Settings-Dialog kann die Eclipse-Keymap eingestellt werden, um die tief verinnerlichten Eclipse-Short-Cuts weiterbenutzen zu können. Als Nachteil könnte bei IntelliJ vielleicht aufgeführt werden, dass Spring Insight (Profiling Aufsatz für den Tomcat) nicht "out of the box" integriert ist. Zudem ist die Ulimate Edition (nur diese unterstützt die Entwicklung von Grails Applikationen) kostenpflichtig.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Wir haben bei exensio bisher STS benutzt, haben in letzter Zeit jedoch vermehrt gehört, dass die Entwicklung mit IntelliJ schneller vonstattengeht. Um es kurz zu machen, IntelliJ scheint unserer Meinung nach wirklich eine gelungene IDE zu sein. Vor allem viele Kleinigkeiten finden wir sehr beachtenswert. Eine Liste mit allen Groovy und Grails Funktionalitäten finden sich hier [3][4]. Folgende Punkte haben uns bei IntelliJ beeindruckt:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Stabilität:&lt;br /&gt;Bei STS war oft das deployte WAR irgendwie inkonsistent und es erschienen irgendwelche komischen Fehlermeldungen. Durch ein “grails clean” war die Applikation wieder deploybar, aber dieser Prozess war auf Dauer zu nervig.&lt;/li&gt;&lt;li&gt;Einfacherer Setup:&lt;br /&gt;Bei Eclipse gibt es so viele Settings, sodass leicht etwas übersehen wird. Bei IntelliJ ist alles, was ein Grails-Entwickler benötigt, vorab konfiguriert.&lt;/li&gt;&lt;li&gt;Debugging:&lt;br /&gt;Das Debugging von Closures ist bei IntelliJ "out of the box" möglich. Bei STS muss dies erst konfiguriert werden [5]. War bei uns in der STS 2.7.1 Version vorab gesetzt, das Debugging von Closures haben wir jedoch nicht hinbekommen. Des Weiteren ist es sehr mühsam, (wenn überhaupt möglich) die Variablen zu inspizieren.&lt;/li&gt;&lt;li&gt;Übersichtlichkeit:&lt;br /&gt;Wir finden IntelliJ übersichtlicher. So hat man immer die Gruppe (Domain-Klasse, Controller, Views und Test) im Blick:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-qJZiy-iWFCo/Tj-p6QjYmYI/AAAAAAAAACA/6oOO3b508Y8/s1600/intellij1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="198" src="http://2.bp.blogspot.com/-qJZiy-iWFCo/Tj-p6QjYmYI/AAAAAAAAACA/6oOO3b508Y8/s320/intellij1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Oder es ist einfach möglich, per Klick von einer Action in einem Controller in die GSP-Seite zu springen:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-N8te1AHEHyY/Tj-q1KCJWpI/AAAAAAAAACE/DpkX7u1SWvc/s1600/intellij2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="198" src="http://1.bp.blogspot.com/-N8te1AHEHyY/Tj-q1KCJWpI/AAAAAAAAACE/DpkX7u1SWvc/s320/intellij2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Des Weiteren ist kann ein ER-Diagramm einer Domain-Klasse in Beziehung zu den anderen angezeigt werden. Hier ein Beispiel eines Star Schemas, das wir mit Grails GORM modelliert haben. Diese Funktionalität ist sehr nützlich, wenn das Datenmodell anfängt zu wachsen.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-HGpIIpuiVPk/Tj-rMiB9f0I/AAAAAAAAACI/s7Ti9Lr1t9s/s1600/intellij3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="180" src="http://2.bp.blogspot.com/-HGpIIpuiVPk/Tj-rMiB9f0I/AAAAAAAAACI/s7Ti9Lr1t9s/s320/intellij3.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Fazit&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Wir wollen hier keine Empfehlung geben, welche Groovy/Grails IDE nun die bessere ist, da die Wahl einer IDE für einen Entwickler einer Glaubensfrage gleicht ;-) . Jedoch fällt auf, dass IntelliJ sehr viele Kleinigkeiten anbietet, die in Summe die Grails-Entwicklung wirklich vereinfacht und beschleunigt. Es fällt auch auf, dass bei IntelliJ die Entwickler ermuntert werden, Verbesserungsvorschläge und Wünsche einzubringen, dies merkt man unweigerlich bei der täglichen Arbeit. Wer sich selber überzeugen möchte, kann sich eine Testlizenz herunterladen, die 30 Tage gültig ist.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Links&lt;/b&gt;&lt;br /&gt;[1] &lt;a href="http://www.springsource.com/developer/sts"&gt;http://www.springsource.com/developer/sts&lt;/a&gt;&lt;br /&gt;[2] &lt;a href="http://www.jetbrains.com/idea"&gt;http://www.jetbrains.com/idea&lt;/a&gt;&lt;br /&gt;[3] &lt;a href="http://www.jetbrains.com/idea/features/groovy_grails.html"&gt;http://www.jetbrains.com/idea/features/groovy_grails.html&lt;/a&gt;&lt;br /&gt;[4] &lt;a href="http://blogs.jetbrains.com/idea/tag/grails/"&gt;http://blogs.jetbrains.com/idea/tag/grails/&lt;/a&gt;&lt;br /&gt;[5] &lt;a href="http://blog.springsource.com/2010/11/30/new-groovy-debug-support-in-sts-2-5-1/"&gt;http://blog.springsource.com/2010/11/30/new-groovy-debug-support-in-sts-2-5-1/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Weitere nützliche Links zum Thema IntelliJ und Grails&lt;/b&gt;&lt;br /&gt;[1]&amp;nbsp;&lt;a href="http://wiki.jetbrains.net/intellij/Creating_a_simple_Grails_application_with_IntelliJ_IDEA"&gt;http://wiki.jetbrains.net/intellij/Creating_a_simple_Grails_application_with_IntelliJ_IDEA&lt;/a&gt;&lt;br /&gt;[2]&amp;nbsp;&lt;a href="http://wiki.jetbrains.net/intellij/Managing_Grails_plugins"&gt;http://wiki.jetbrains.net/intellij/Managing_Grails_plugins&lt;/a&gt;&lt;br /&gt;[3]&amp;nbsp;&lt;a href="http://www.grails.org/IDEA+Integration"&gt;http://www.grails.org/IDEA+Integration&lt;/a&gt;&lt;br /&gt;[4]&amp;nbsp;&lt;a href="http://www.grails.org"&gt;http://www.grails.org&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-3671407778930282876?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/1M0n2_5sfmY/grails-entwicklung-mit-intellij.html</link><author>noreply@blogger.com (Peter Soth)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-qJZiy-iWFCo/Tj-p6QjYmYI/AAAAAAAAACA/6oOO3b508Y8/s72-c/intellij1.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/08/grails-entwicklung-mit-intellij.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4466305307772589754.post-6299393212628813792</guid><pubDate>Fri, 29 Jul 2011 08:31:00 +0000</pubDate><atom:updated>2011-07-29T11:23:14.693+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">solr</category><category domain="http://www.blogger.com/atom/ns#">e20</category><title>Fuzzy Search und "Meinten Sie?" in Apache Solr</title><description>In unserer &lt;a href="http://exensio.blogspot.com/2011/05/unsere-enterprise-20-plattform.html"&gt;Enterprise 2.0 Plattform&lt;/a&gt; setzen wir die Volltextsuchmaschine Apache Solr, die auf Basis der Such-Bibliothek Lucene arbeitet, mit Begeisterung ein. Dieser Beitrag soll beschreiben, wie dem Benutzer mit einfachen Mitteln bei Tippfehlern geholfen werden kann.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Spellchecker Komponente&lt;/b&gt;&lt;br /&gt;Mit der &lt;i&gt;SpellCheckComponent&lt;/i&gt; [1] teilt Solr Vorschläge zu den vom Benutzer abgesandten Suchtermen mit. Als Grundlage dieser Vorschläge kann ein Feld aus dem Such-Index herangezogen werden.&lt;br /&gt;&lt;br /&gt;Die Konfiguration der Komponente ist bereits in der standardmäßigen schema.xml enthalten. So gilt es nur noch das Vorschläge-Verzeichnis aufzubauen. Solr erledigt dies automatisch, wenn der Parameter &lt;span style="font-size:95%;font-family: courier new;"&gt;spellcheck.build=true&lt;/span&gt; an die Anfrage angehängt wird. Ein Beispiel wäre:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:95%;font-family: courier new;"&gt;http://localhost:8983/solr/spell?q=test%20cotent&amp;amp;spellcheck=true&amp;amp;spellcheck.collate=true&amp;amp;spellcheck.build=true&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Das muss selbstverständlich nicht bei jeder Abfrage gemacht werden.&lt;br /&gt;&lt;br /&gt;Die eigentliche Suchabfrage sieht genau gleich - nur ohne den Parameter - aus. Bemerkenswert ist der Parameter &lt;span style="font-size:95%;font-family: courier new;"&gt;spellcheck.collate=true&lt;/span&gt;, der nicht nur das falsch geschriebene Wort, sondern auch gleich die komplett korrigierte Suchabfrage zurück liefert. So liefert die SpellCheck-Abfrage nach "test cotent" als Vorschlag "test content" zurück.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Fuzzy Search&lt;/b&gt;&lt;br /&gt;Ein weiteres Mittel, das Apache Solr (genauer gesagt: Apache Lucene) bietet, ist die "Fuzzy Search". "Fuzzy Search" steht für Suche mit einer gewissen Unschärfe.&lt;br /&gt;Durch Anhängen einer Tilde an den eigentlichen Suchterm wird angegeben, dass der Suchterm mit Unschärfe betrachtet werden soll. Dies korrigiert zum Beispiel automatisch Tippfehler, liefert aber auch ähnliche Suchtreffer, die möglicherweise passen könnten, als Ergebnis zurück.&lt;br /&gt;Während bei uns die Suche nach "exnsio" keinerlei Treffer hat, findet die Fuzzy Search nach "exnsio~" alle Dokumente, in denen "exensio" auftaucht.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Verwendung in unserer Enterprise 2.0 Plattform&lt;/b&gt;&lt;br /&gt;Sowohl die SpellCheck-Komponente als auch die "Fuzzy Search" bieten eine einfache Möglichkeit, um den Benutzer bei der Suche zu unterstützen und eventuelle Tippfehler (sogar automatisch) zu korrigieren.&lt;br /&gt;In unserer Enterprise 2.0 Plattform verwenden wir beide Möglichkeiten: Wir bieten dem Benutzer Vorschläge wie "Meinten Sie? ..." à la Google und führen gleichzeitig bei wenig Treffern eine Fuzzy Search zum eingegeben Suchterm aus, um dem Benutzer sofort passende Ergebnisse anzeigen zu können.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[1] Ausführliche Beschreibung zur SpellCheck-Komponente: &lt;a href="http://wiki.apache.org/solr/SpellCheckComponent"&gt;http://wiki.apache.org/solr/SpellCheckComponent&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4466305307772589754-6299393212628813792?l=blog.exensio.de' alt='' /&gt;&lt;/div&gt;</description><link>http://feedproxy.google.com/~r/blogspot/iQDgu/~3/AKFYPjphyuQ/fuzzy-search-und-meinten-sie-in-solr.html</link><author>noreply@blogger.com (Manuel Breitfeld)</author><thr:total>0</thr:total><feedburner:origLink>http://blog.exensio.de/2011/07/fuzzy-search-und-meinten-sie-in-solr.html</feedburner:origLink></item></channel></rss>

