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

<channel>
	<title>Ralph&#039;s Blog</title>
	<atom:link href="http://blog.rasc.ch/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://blog.rasc.ch</link>
	<description>Blog über Dies und Das</description>
	<lastBuildDate>Wed, 25 Apr 2012 07:12:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Spring Caching mit Guava Cache</title>
		<link>http://blog.rasc.ch/?p=1926</link>
		<comments>http://blog.rasc.ch/?p=1926#comments</comments>
		<pubDate>Wed, 25 Apr 2012 07:12:58 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[guava]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.rasc.ch/?p=1926</guid>
		<description><![CDATA[Im vorangegangenen Blogpost haben wir gesehen wie man mit Hilfe von @Cacheable und dem Cache Support von Spring Rückgabewerte von Methoden cachen kann. Spring liefert in der Core Library zwei Implementationen mit. Den ConcurrentMapCacheManager, der die Daten in einer ConcurrentMap speichert, und den EhCacheCacheManager der im Hintergrund EhCache benutzt. Weiter gibt es noch den NoOpCacheManager. [...]]]></description>
			<content:encoded><![CDATA[<p>Im <a href="http://blog.rasc.ch/?p=1904">vorangegangenen Blogpost</a> haben wir gesehen wie man mit Hilfe von @Cacheable und dem Cache Support von Spring Rückgabewerte von Methoden cachen kann. </p>
<p>Spring liefert in der Core Library zwei Implementationen mit. Den <a href="http://www.rasc.ch/spring/org/springframework/cache/concurrent/ConcurrentMapCacheManager.html">ConcurrentMapCacheManager</a>, der die Daten in einer ConcurrentMap speichert, und den <a href="http://www.rasc.ch/spring/org/springframework/cache/ehcache/EhCacheCacheManager.html">EhCacheCacheManager</a> der im Hintergrund <a href="http://ehcache.org/">EhCache</a> benutzt. Weiter gibt es noch den <a href="http://www.rasc.ch/spring/org/springframework/cache/support/NoOpCacheManager.html">NoOpCacheManager</a>. Dieser cacht keine Daten und kann nützlich sein für Tests.</p>
<p>Andere Cache Libraries in das Spring Cache System zu integrieren ist nicht schwer. Eine interessante Cacheimplementation ist in der <a href="http://code.google.com/p/guava-libraries/">Google Guava Library</a> enthalten.</p>
<p>Seit Version 10 existiert die Klasse <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/cache/CacheBuilder.html">CacheBuilder</a>. Damit lassen sich verschiedenste Arten von <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/cache/Cache.html">Caches</a> erstellen. Der CacheBuilder kann Caches mit einer maximalen Grösse erstellen oder Caches in denen die Einträge nach einer bestimmten Zeit gelöscht werden. Caches können erstellt werden die <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html">WeakReferences</a> als Key und/oder Value benutzen. Der Guava Cache speichert, wie der ConcurrentMapCache, die Daten nur lokal im Speicher in einer Virtual Machine ab. Für verteilte und/oder persistente Caches sollte man sich den EhCacheCacheManager genauer ansehen.</p>
<p>Caches lassen sich dank des Builder Patterns sehr einfach erstellen. Hier ein Beispiel eines Caches der maximal 10 Einträge enthalten kann und die Einträge 10 Sekunden nach dem Einfügen wieder löscht.</p>
<p></p><pre class="crayon-plain-tag">Cache&lt;Integer,String&gt; cache = CacheBuilder.newBuilder()
         .maximumSize(10)
         .expireAfterWrite(10, TimeUnit.SECONDS)
         .build();

cache.put(1, &quot;one&quot;);		
System.out.println(cache.getIfPresent(1));</pre><p></p>
<p>Werte werden mit put(key, value) eingefügt und mit getIfPresent(key) wieder ausgelesen. Weitere Informationen zum Guava Cache findet man in der Wiki unter <a href="http://code.google.com/p/guava-libraries/wiki/CachesExplained">http://code.google.com/p/guava-libraries/wiki/CachesExplained</a>.</p>
<p>Um nun den Guava Cache mit dem Spring Cache System zu verheiraten benötigen wir zwei Dinge. Erstens eine Klasse die das Interface <a href="http://www.rasc.ch/spring/org/springframework/cache/Cache.html">org.springframework.cache.Cache</a> implementiert und als Zweites einen <a href="http://www.rasc.ch/spring/org/springframework/cache/CacheManager.html">CacheManager</a>.</p>
<p>Die Cache Implementation ist ein simpler Wrapper der einen Guava <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/cache/Cache.html">Cache</a> beinhaltet.</p>
<p></p><pre class="crayon-plain-tag">public class GuavaCache implements Cache {

	private final String name;
	private final com.google.common.cache.Cache&lt;Object, Optional&lt;Object&gt;&gt; store;

	public GuavaCache(String name, com.google.common.cache.Cache&lt;Object, Optional&lt;Object&gt;&gt; store) {
		this.name = name;
		this.store = store;
	}

	@Override
	public String getName() {
		return this.name;
	}

	@Override
	public com.google.common.cache.Cache&lt;Object, Optional&lt;Object&gt;&gt; getNativeCache() {
		return this.store;
	}

	@Override
	public ValueWrapper get(Object key) {
		Optional&lt;Object&gt; value = this.store.getIfPresent(key);
		return (value != null ? new SimpleValueWrapper(value.orNull()) : null);
	}

	@Override
	public void put(Object key, Object value) {
		this.store.put(key, Optional.fromNullable(value));
	}

	@Override
	public void evict(Object key) {
		this.store.invalidate(key);
	}

	@Override
	public void clear() {
		this.store.invalidateAll();
	}
}</pre><p></p>
<p>Ein Sonderfall der behandelt werden muss ist der null Wert. Der Guava Cache erlaubt keine Werte die null sind, aber es kann durchaus sein das eine <a href="http://www.rasc.ch/spring/org/springframework/cache/annotation/Cacheable.html">@Cacheable</a> Methode null zurückgibt. Um den null Wert auch speichern zu können, wird der Wert in ein <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/base/Optional.html">Optional</a> Objekt gewrappt. Optional ist auch Bestandteil der Guava Library. Die Methode Optional.fromNullable(obj) gibt entweder eine Optional Instanz zurück, die das Original Objekt umschliesst, oder wenn der Parameter null ist das Objekt Optional.absent(), eine Optional Instanz die kein Objekt wrappt. Mit der Methode optional.orNull() erhalten wir wieder das Original Objekt oder null. </p>
<p>Als CacheManager benutzen wir in diesem Beispiel die Klasse <a href="http://www.rasc.ch/spring/org/springframework/cache/support/SimpleCacheManager.html">SimpleCacheManager</a>, welche von Spring mitgeliefert wird. Dieser Manager ist für diesen Zweck ausreichend und managt die Namen der Caches zu den tatsächlichen Implementationen.</p>
<p></p><pre class="crayon-plain-tag">@Configuration
@EnableCaching
@ComponentScan(basePackages = { &quot;ch.rasc.caching.guava&quot; })
public class Config {

	@Bean
	public CacheManager cacheManager() {
		SimpleCacheManager cacheManager = new SimpleCacheManager();
		
		Cache&lt;Object, Optional&lt;Object&gt;&gt; oneMinuteCache = CacheBuilder.newBuilder()
				.expireAfterWrite(1, TimeUnit.MINUTES).build();

		Cache&lt;Object, Optional&lt;Object&gt;&gt; maxSizeCache = CacheBuilder.newBuilder()
				.maximumSize(10).build();
		
		cacheManager.setCaches(Arrays.asList(
				new GuavaCache(&quot;oneMinuteCache&quot;, oneMinuteCache),
				new GuavaCache(&quot;maxSizeCache&quot;, maxSizeCache)
				));
		
        return cacheManager;
	}
}</pre><p></p>
<p>Das Beispiel erstellt einen Guava Cache mit einer maximalen Grösse von 10 Einträgen und einen zweiten Cache bei dem die Einträge nach einer Minute wieder gelöscht werden. Diese werden mit den Namen &#8220;oneMinuteCache&#8221; und &#8220;maxSizeCache&#8221; im CacheManager eingetragen.</p>
<p>Nun können wir sehr einfach die Methoden mit @Cacheable annotieren und den gewünschten Cache spezifizieren.</p>
<p></p><pre class="crayon-plain-tag">@Service
public class Calculator {
	@Cacheable(&quot;oneMinuteCache&quot;)
	public BigInteger factorialTimedCache(long n) {
		//...
	}

	@Cacheable(&quot;maxSizeCache&quot;)
	public BigInteger factorialMaxCache(long n) {
	          //...
	}
}</pre><p></p>
<p>Beachten muss man bei diesen Caches das Einträge per Default nicht in einem Hintergrundjob aus dem Cache gelöscht werden. Das Cleanup passiert beim Schreiben oder Lesen eines Eeintrages.</p>
<p>Weitere Informationen zu diesem Thema findet man in der Guava Wiki:<br />
<a href="http://code.google.com/p/guava-libraries/wiki/CachesExplained#Explicit_Removals">http://code.google.com/p/guava-libraries/wiki/CachesExplained#Explicit_Removals</a></p>
<p>Wie in der Wiki beschrieben, wird das Cleanup bei Caches die sehr selten Werte eintragen in den Leseoperationen durchgeführt und kann dadurch das Lesen verlangsamen. Man kann dies vermeiden, indem ein Hintergrundjob gestartet  wird der regelmässig die Methode Cache.cleanUp() aufruft.</p>
<p>Hier ein Beispiel eines Jobs der mit Hilfe von <a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html">ScheduledExecutorService</a> alle 20 Sekunden die Methode cleanUp() von allen Caches aufruft. </p>
<p></p><pre class="crayon-plain-tag">@Service
public class CacheCleanup {

	private ScheduledExecutorService scheduler;

	@Autowired
	CacheManager cacheManager;

	@PreDestroy
	public void shutdown() {		
		scheduler.shutdown();
	}

	@PostConstruct
	public void cacheCleanup() {
		scheduler = Executors.newScheduledThreadPool(1);
		scheduler.scheduleWithFixedDelay(new Runnable() {
			@Override
			public void run() {
				for (String cacheName : cacheManager.getCacheNames()) {
					((GuavaCache) cacheManager.getCache(cacheName)).getNativeCache().cleanUp();
				}
			}
		}, 5, 20, TimeUnit.SECONDS);

	}
}</pre><p></p>
<p>Source Code: <a href="https://github.com/ralscha/playground/tree/master/caching/src/main/java/ch/rasc/caching/guava">https://github.com/ralscha/playground/tree/master/caching/src/main/java/ch/rasc/caching/guava</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1926</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spring Caching</title>
		<link>http://blog.rasc.ch/?p=1904</link>
		<comments>http://blog.rasc.ch/?p=1904#comments</comments>
		<pubDate>Tue, 24 Apr 2012 08:05:18 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.rasc.ch/?p=1904</guid>
		<description><![CDATA[Mit Spring 3.1 wurde die Möglichkeit eingebaut Methoden Aufrufe zu cachen. Dazu werden Methoden, deren Rückgabewert gecacht werden kann mit der Annotation @Cacheable gekennzeichnet. Das Cachesystem von Spring muss dazu entweder mit JavaConfig (@EnableCaching) oder XML (&#60;cache:annotation-driven /&#62;) aktiviert werden. Zusätzlich muss ein CacheManager im ApplicationContext registriert sein, da es keinen sinnvollen Default Wert gibt [...]]]></description>
			<content:encoded><![CDATA[<p>Mit <a href="http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/new-in-3.1.html#d0e1281">Spring 3.1</a> wurde die Möglichkeit eingebaut Methoden Aufrufe zu cachen. Dazu werden Methoden, deren Rückgabewert gecacht werden kann mit der Annotation <a href="http://www.rasc.ch/spring/org/springframework/cache/annotation/Cacheable.html">@Cacheable</a> gekennzeichnet. Das Cachesystem von Spring muss dazu entweder mit JavaConfig (<a href="http://www.rasc.ch/spring/org/springframework/cache/annotation/EnableCaching.html">@EnableCaching</a>) oder XML (&lt;cache:annotation-driven /&gt;) aktiviert werden. Zusätzlich muss ein CacheManager im ApplicationContext registriert sein, da es keinen sinnvollen Default Wert gibt den Spring wählen könnte. Mit der XML Konfiguration muss der CacheManager als Bean mit Namen <strong>cacheManager</strong> eingetragen sein. @EnableCaching sucht mit dem Typ den CacheManager und kann deshalb beliebig benannt werden.</p>
<p>Spring liefert zwei Implementationen des CacheManagers mit. <a href="http://www.rasc.ch/spring/org/springframework/cache/concurrent/ConcurrentMapCacheManager.html">ConcurrentMapCacheManager</a> und <a href="http://www.rasc.ch/spring/org/springframework/cache/ehcache/EhCacheCacheManager.html">EhCacheCacheManager</a>. Für die folgenden Beispiele werden JavaConfig und ConcurrentMap als Cache verwendet.</p>
<p></p><pre class="crayon-plain-tag">@Configuration
@ComponentScan(basePackages = { &quot;ch.rasc.caching.spring&quot; })
@EnableCaching
public class Config {
  @Bean
  public CacheManager cacheManager() {
    return new ConcurrentMapCacheManager(&quot;calculator&quot;);
  }
}</pre><p></p>
<p>Als Parameter für den Konstruktor von <a href="http://www.rasc.ch/spring/org/springframework/cache/concurrent/ConcurrentMapCacheManager.html">ConcurrentMapCacheManager</a> werden die Namen der Caches mitgegeben. Es können dann nur diese verwendet werden. Wenn die Klasse mit dem Default Konstruktor ohne Parameter instanziiert wird werden die Caches bei Bedarf erzeugt. Es empfiehlt sich die Cache Namen vorab zu definieren, da Schreibfehler zu Exceptions führen und Fehler so schneller gefunden werden.</p>
<p>Alternativ kann die Config Klasse das Interface <a href="http://www.rasc.ch/spring/org/springframework/cache/annotation/CachingConfigurer.html">CachingConfigurer</a> implementieren.</p>
<p></p><pre class="crayon-plain-tag">@Configuration
@ComponentScan(basePackages = { &quot;ch.rasc.caching.spring&quot; })
@EnableCaching
public class Config implements CachingConfigurer {
  @Bean
  @Override
  public CacheManager cacheManager() {
    return new ConcurrentMapCacheManager(&quot;calculator&quot;, &quot;anotherCache&quot;);
  }

  @Override
  public KeyGenerator keyGenerator() {
    return new DefaultKeyGenerator();
  }
}</pre><p></p>
<p>Caches sind im Grunde nichts anderes als Key-/Value-Stores. Als Wert wird der Rückgabewert der Methode verwendet. Es macht also nur Sinn Methoden cachbar zu machen die etwas zurückgeben. Der Key wird aus den Parametern der Methode gebildet. Die Klasse <a href="http://www.rasc.ch/spring/org/springframework/cache/interceptor/DefaultKeyGenerator.html">DefaultKeyGenerator</a> wird von Spring immer dann verwendet wenn kein anderer <a href="http://www.rasc.ch/spring/org/springframework/cache/interceptor/KeyGenerator.html">KeyGenerator</a> spezifiziert wurde.</p>
<p>Nun erzeugen wir ein Service Bean mit einer Methode die cachbar gemacht werden soll.</p>
<p></p><pre class="crayon-plain-tag">@Service
public class Calculator {
  @Cacheable(&quot;calculator&quot;)
  public BigInteger factorial(long n) {
    //...
  }
}</pre><p></p>
<p>Der Annotation @Cacheable muss der Name des Caches mitgegeben werden. Dies entspricht dem Namen den man beim Instanziieren des CacheManagers verwendet hat. Wenn der Cache nicht existiert wird eine Exception geworfen (ausser man verwendet die dynamische Variante des ConcurrentMapCacheManager). Es ist möglich mehrere Caches anzugeben <pre class="crayon-plain-tag">@Cacheable(value={&quot;calculator&quot;, &quot;anotherCache&quot;})</pre>. Der Rückgabewert wird dann in allen spezifizierten Caches eingetragen.</p>
<p>Per Default werden immer alle Methodenparameter für die Key Generierung verwendet. Man kann dieses Verhalten mit dem Argument <em>key</em> anpassen.</p>
<p>Im folgenden Beispiel wird nur der erste Parameter (n) als Key verwendet. Als Wert für das Argument <em>key</em> muss eine SpEL Expression angegeben werden. Den Namen des Parameters kann nur dann verwendet werden wenn der Code mit Debug Informationen kompiliert wurde. Alternativ kann deshalb der Parameter mit a<em>#</em> oder p<em>#</em> (<em>#</em>=Position des Parameters) spezifiziert werden.</p>
<p>Die folgenden drei Beispiele sind alle gleichwertig:</p>
<p></p><pre class="crayon-plain-tag">@Cacheable(value=&quot;calculator&quot;, key=&quot;#n&quot;)
public BigInteger factorial(long n, String user) {
  //...
}
@Cacheable(value=&quot;calculator&quot;, key=&quot;#p0&quot;)
public BigInteger factorial(long n, String user) {
  //...
}
@Cacheable(value=&quot;calculator&quot;, key=&quot;#a0&quot;)
public BigInteger factorial(long n, String user) {
  //...
}</pre><p></p>
<p>Es ist möglich das Caching nur dann zu benutzen wenn eine bestimmte Bedingung eintritt. Dazu wird mit dem Argument <em>condition</em> eine SpEL Expression angegeben die entweder true oder false zurückgibt. Nur wenn diese Bedingung eintritt (true) wird das Caching benutzt. Im folgenden Beispiel nur dann wenn der Parameter n einen Wert grösser 10 hat.</p>
<p></p><pre class="crayon-plain-tag">@Cacheable(value=&quot;calculator&quot;, condition=&quot;#n &gt; 10&quot;)
public BigInteger factorial(long n) {
  //...
}</pre><p></p>
<p><strong>Cache Einträge löschen</strong></p>
<p>Um Cache Einträge wieder zu löschen wird die Annotation <a href="http://www.rasc.ch/spring/org/springframework/cache/annotation/CacheEvict.html">@CacheEvict</a> verwendet. Ein Anwendungsfall ist ein Cache für eine Datenbank. Die Abfragemethoden werden mit @Cacheable und die Modify Methoden mit @CacheEvict annotiert, so dass im Cache keine veralteten Werte eingetragen sind.</p>
<p>Beim Aufruf der folgenden Methode wird der Eintrag mit dem Key n im Cache gelöscht. Wenn das nächste Mal eine @Cacheable Methode mit diesem Cache und gleichem Parameter n aufgerufen wird, wird diese wieder ausgeführt. Der Rückgabewert einer @CacheEvict Methode wird für das Cache Handling ignoriert und kann void sein.</p>
<p></p><pre class="crayon-plain-tag">@CacheEvict(value=&quot;calculator&quot;)
public void clearCache(long n) {
}</pre><p></p>
<p>Es ist möglich, gleich wie bei @Cacheable, den Parameter zu spezifizieren der als Key verwendet werden soll.</p><pre class="crayon-plain-tag">@CacheEvict(value = &quot;calculator&quot;, key = &quot;#n&quot;)
public void clearCache(long n, String user) {
  //nothing here
}</pre><p></p>
<p>Anstatt nur einen Eintrag zu löschen können mit dem Argument <em>allEntries=true</em> alle Einträge des Caches gelöscht werden. Gleich wie bei @Cacheable ist es möglich mehrere Caches anzugeben die betroffen sind.</p>
<p></p><pre class="crayon-plain-tag">@CacheEvict(value = { &quot;calculator&quot;, &quot;anotherCache&quot; }, allEntries = true)
public void clearCache() {
  //...
}</pre><p></p>
<p><strong>Proxy/AspectJ Modus</strong></p>
<p>Per Default verwendet Spring Proxies für das Cachemanagement. Diese werden zur Laufzeit erzeugt und es ist keine spezielle Konfiguration notwendig. Proxies haben aber den Nachteil das nur public Methoden mit @Cacheable annotiert werden können. Man kann zwar auch andere Methoden damit annotieren, dies führt beim Aufruf zu keinem Absturz allerdings wird der Rückgabewert nicht gecacht. Zusätzlich haben Proxies den Nachteil, dass wenn die @Cacheable Method von innerhalb der Klasse aufgerufen wird, das Cachehandling nicht angestossen wird (auch bei public Methoden). Die gleichen Einschränkungen existieren auch bei @Transactional Methoden.</p>
<p>Hier ein Beispiel. Wenn die Methode factorial von ausserhalb des Calculators aufgerufen wird, werden die Rückgabewerte gecacht. Wenn wir nun aber die Methode callFromInside() aufrufen, welche wiederum die Methode factorial ausführt, wird das Caching umgangen und die Methode wird immer ausgeführt.</p>
<p></p><pre class="crayon-plain-tag">@Service
public class Calculator {

  public BigInteger callFromInside() {
    return factorial(69);
  }

  @Cacheable(&quot;calculator&quot;)
  public BigInteger factorial(long n) {
    //...
  }
}</pre><p></p>
<p>Wenn man nicht-public Methoden cachbar und/oder Methoden von innerhalb der Klasse aufrufen möchte können anstatt Proxies AspectJ verwendet werden. AspectJ verwebt (weave) den Bytecode des Cachehandlings direkt in die Klasse. Das passiert entweder zur Compile- oder zur Load-Time. Hier das Vorgehen um Compile-Time-Weaving zu aktivieren.</p>
<p>Zum einen müssen wir AspectJ im Spring ApplicationContext einschalten. Entweder via JavaConfig @EnableCaching(mode=AdviceMode.ASPECTJ) oder via XML &lt;cache:annotation-driven mode=&#8221;aspectj&#8221;/&gt;.</p>
<p>Zusätzlich benötigen wir zwei zusätzliche Dependencies für unser Programm.</p>
<p></p><pre class="crayon-plain-tag">&lt;dependency&gt;
			&lt;groupId&gt;org.aspectj&lt;/groupId&gt;
			&lt;artifactId&gt;aspectjrt&lt;/artifactId&gt;
			&lt;version&gt;1.6.12&lt;/version&gt;
		&lt;/dependency&gt;

		&lt;dependency&gt;
			&lt;groupId&gt;org.springframework&lt;/groupId&gt;
			&lt;artifactId&gt;spring-aspects&lt;/artifactId&gt;
			&lt;version&gt;3.1.1.RELEASE&lt;/version&gt;
		&lt;/dependency&gt;</pre><p></p>
<p>Damit Maven den AspectJ Compiler startet integrieren wir das <a href="http://mojo.codehaus.org/aspectj-maven-plugin/">aspectj-maven-plugin</a> Plugin ins pom.xml</p>
<p></p><pre class="crayon-plain-tag">&lt;plugin&gt;
				&lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;
				&lt;artifactId&gt;aspectj-maven-plugin&lt;/artifactId&gt;
				&lt;version&gt;1.4&lt;/version&gt;
				&lt;configuration&gt;
				    &lt;Xlint&gt;warning&lt;/Xlint&gt;
					&lt;complianceLevel&gt;1.7&lt;/complianceLevel&gt;
					&lt;source&gt;1.7&lt;/source&gt;
				    &lt;target&gt;1.7&lt;/target&gt;
					&lt;encoding&gt;UTF-8&lt;/encoding&gt;
					&lt;aspectLibraries&gt;
						&lt;aspectLibrary&gt;
							&lt;groupId&gt;org.springframework&lt;/groupId&gt;
							&lt;artifactId&gt;spring-aspects&lt;/artifactId&gt;							
						&lt;/aspectLibrary&gt;						
					&lt;/aspectLibraries&gt;
				&lt;/configuration&gt;
				&lt;executions&gt;
					&lt;execution&gt;
						&lt;goals&gt;
							&lt;goal&gt;compile&lt;/goal&gt;
							&lt;goal&gt;test-compile&lt;/goal&gt;
						&lt;/goals&gt;
					&lt;/execution&gt;
				&lt;/executions&gt;
			&lt;/plugin&gt;</pre><p></p>
<p>Wenn man mit Eclipse arbeitet müssen die “AspectJ Capability” eingeschaltet werden. Mit dem neuesten Eclipse und m2e Plugin wird dies automatisch eingeschaltet, wenn das aspectj-maven-plugin Plugin im pom.xml eingetragen wird.</p>
<p>Für die Testprogramme hatte ich das Problem dass der AspectJ Compiler folgenden Fehler anzeigte:<br />
<code>[ERROR] can't determine superclass of missing type org.springframework.transaction.interceptor.TransactionAspectSupport</code><br />
Dies hat damit zu tun das spring-aspects.jar neben den Cache- auch noch Transaktionsaspekte (für @Transactional) beinhaltet und AspectJ versucht auch diese zu verweben. Man kann nun entweder die benötigten Libraries hinzufügen (spring-tx) oder man konfiguriert das aspectj-maven-plugin Plugin mit &lt;Xlint&gt;warning&lt;/Xlint&gt;. Damit erhalten wir zwar einige Warnungen aber der Code kann kompiliert werden.</p>
<p>Diese Einstellung wird leider nicht ins AspectJ Tool von Eclipse übernommen, deshalb musste ich dort noch folgende Einstellung vornehmen um den Code auch via Eclipse kompilieren zu können.</p>
<p><a href="http://blog.rasc.ch/wp-content/uploads/2012/04/eclipseaspectj.png"><img src="http://blog.rasc.ch/wp-content/uploads/2012/04/eclipseaspectj.png" alt="" title="eclipseaspectj" width="710" height="260" class="alignnone size-full wp-image-1906" /></a></p>
<p>Falls beim Starten des Javaprogramms folgender Fehler auftaucht<br />
<code>Exception in thread "main" java.lang.VerifyError: Expecting a stackmap frame at branch</code><br />
muss die JVM mit dem Argument <code>-XX:-UseSplitVerifier</code> gestartet werden.</p>
<p>Weitere Informationen findet man in der Spring Dokumentation:<br />
<a href="http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/cache.html">http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/cache.html</a></p>
<p>Source Code:<br />
<a href="https://github.com/ralscha/playground/tree/master/caching/src/main/java/ch/rasc/caching/spring">https://github.com/ralscha/playground/tree/master/caching/src/main/java/ch/rasc/caching/spring</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1904</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pub/Sub mit Hazelcast</title>
		<link>http://blog.rasc.ch/?p=1888</link>
		<comments>http://blog.rasc.ch/?p=1888#comments</comments>
		<pubDate>Sat, 21 Apr 2012 06:00:42 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[hazelcast]]></category>
		<category><![CDATA[pub/sub]]></category>

		<guid isPermaLink="false">http://blog.rasc.ch/?p=1888</guid>
		<description><![CDATA[In den beiden vorangegangen Artikeln (Blogpost vom 19.4. und 20.4.) haben wir einfache Pub/Sub Systeme mit den Spring eigenen Bordmitteln und mit dem Google Guava Eventbus erstellt. Diese Systeme haben die Eigenschaft das sie nur innerhalb einer Virtual Machine eingesetzt werden können. Haben wir zum Beispiel einen Cluster von Virtual Machines die untereinander Events austauschen [...]]]></description>
			<content:encoded><![CDATA[<p>In den beiden vorangegangen Artikeln (Blogpost vom <a href="http://blog.rasc.ch/?p=1838">19.4.</a> und <a href="http://blog.rasc.ch/?p=1853">20.4.</a>) haben wir einfache Pub/Sub Systeme mit den Spring eigenen Bordmitteln und mit dem Google Guava Eventbus erstellt. Diese Systeme haben die Eigenschaft das sie nur innerhalb einer Virtual Machine eingesetzt werden können. </p>
<p>Haben wir zum Beispiel einen Cluster von Virtual Machines die untereinander Events austauschen möchten dann benötigen wir eine andere Lösung. Für dieses Szenario können wir einen <a href="http://www.oracle.com/technetwork/java/index-jsp-142945.html">JMS</a> (Java Message Service) einsetzen auf den alle beteiligten Subscriber und Publisher eine Verbindung aufbauen. </p>
<p>Eine alternative Lösung wird im folgenden beschrieben die <a href="http://www.hazelcast.com/">Hazelcast</a> einsetzt. Diese Lösung bietet nicht die umfangreiche Funktionalität an die ein JMS zur Verfügung stellt, aber für ein einfaches Pub/Sub System zwischen mehreren Virtual Machine kann dieser Ansatz je nach Anforderungen durchaus genügen. Die Hazelcast Lösung hat den Vorteil das wir keinen zentralen Server aufsetzen müssen, da sich die einzelnen Virtual Machines via Multicast finden und kommunizieren. Die einzelnen Knoten müssen sich dazu im gleichen Netz befinden und Multicast muss eingeschaltet sein.</p>
<p>Wie üblich benötigen wir auch hier ein Objekt das als Event verwendet wird. Das Objekt muss <a href="http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html">Serializable</a> sein damit es von einer Virtual Machine zur anderen gesendet werden kann.</p>
<p></p><pre class="crayon-plain-tag">public class ShortMessageEvent implements Serializable {
	private String msg;

	public ShortMessageEvent(String msg) {
		this.msg = msg;
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}
}</pre><p></p>
<p>Der Sender benötigt eine Referenz zu einem <a href="http://www.hazelcast.com/docs/2.0/javadoc/com/hazelcast/core/ITopic.html">ITopic</a> um damit das Event zu versenden. Das ITopic erhält man mit einem Aufruf von <a href="http://www.hazelcast.com/docs/2.0/javadoc/com/hazelcast/core/Hazelcast.html#getTopic(java.lang.String)">Hazelcast.getTopic(..)</a></p>
<p></p><pre class="crayon-plain-tag">public void send(String msg) {
	ITopic&lt;ShortMessageEvent&gt; topic = Hazelcast.getTopic (&quot;my_topic&quot;);
	topic.publish(new ShortMessageEvent(msg));
}</pre><p></p>
<p>Der Subscriber muss das Interface <a href="http://www.hazelcast.com/docs/2.0/javadoc/com/hazelcast/core/MessageListener.html">MessageListener</a> implementieren. Zusätzlich muss er sich beim Hazelcast Topic registrieren. Im folgenden Beispiel ist der Listener ein Spring Managed Bean und die Registrierung erfolgt in einer @PostConstruct Methode. Wichtig ist das der gleiche Topic Name wie beim Publisher verwendet wird. </p>
<p></p><pre class="crayon-plain-tag">public class ShortMessageListener implements MessageListener&lt;ShortMessageEvent&gt; {

	@PostConstruct
	public void register() {
		Hazelcast.&lt;ShortMessageEvent&gt;getTopic(&quot;my_topic&quot;).addMessageListener(this);
	}

	@Override
	public void onMessage(Message&lt;ShortMessageEvent&gt; message) {
		System.out.println(message.getMessageObject().getMsg());
	}
}</pre><p>	</p>
<p>Nun kann der Publisher in einer Virtual Machine (siehe Klasse <a href="https://github.com/ralscha/playground/blob/master/eventbus/src/main/java/ch/rasc/pubsub/hazelcast/Client.java">Client</a>) und der Listener (<a href="https://github.com/ralscha/playground/blob/master/eventbus/src/main/java/ch/rasc/pubsub/hazelcast/Server.java">Server</a>) in einer anderen gestartet werden und man sieht wie die Meldungen versendet werden und der entsprechende Listener aufgerufen wird. Für dieses Beispiel benutzen wir die Default Konfiguration von Hazelcast. Hazelcast kann mit Hilfe der Datei <a href="http://www.hazelcast.com/docs/2.0/manual/single_html/#Config">hazelcast.xml</a>, die sich im Klassenpfad befinden muss, detailiert konfiguriert werden.</p>
<p>Alternativ lassen sich Meldungen via das <a href="http://www.hazelcast.com/docs/2.0/manual/single_html/#JavaClient">Hazelcast Client API</a> versenden. Dies hat den Vorteil das sich das Programm nicht am Cluster anmelden muss was einige Zeit kosten kann, da beim Aufstarten von Hazelcast die anderen Member des Clusters gesucht werden müssen. Dies kann zum Beispiel sinnvoll sein für ein Batchprogramm das regelmässig Meldung absetzen muss und dann wieder beendet wird. Allerdings muss bei dieser API die IP Adressen der einzelnen Clusterknoten angegeben werden. Sinnvollerweise übergibt man mehrere IP Adresse damit die Meldung trotzdem abgesetzt werden kann auch wenn ein Knoten nicht laufen sollte.</p>
<p></p><pre class="crayon-plain-tag">ClientConfig clientConfig = new ClientConfig();
clientConfig.addAddress(&quot;localhost&quot;);

HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig);			
client.getTopic(&quot;my_topic&quot;).publish(new ShortMessageEvent(&quot;message from a simple hazelcast client&quot;));</pre><p></p>
<p>Source Code: <a href="https://github.com/ralscha/playground/tree/master/eventbus/src/main/java/ch/rasc/pubsub/hazelcast">https://github.com/ralscha/playground/tree/master/eventbus/src/main/java/ch/rasc/pubsub/hazelcast</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1888</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pub/Sub mit Spring und dem Google Guava EventBus</title>
		<link>http://blog.rasc.ch/?p=1853</link>
		<comments>http://blog.rasc.ch/?p=1853#comments</comments>
		<pubDate>Fri, 20 Apr 2012 06:00:08 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[guava]]></category>
		<category><![CDATA[pub/sub]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.rasc.ch/?p=1853</guid>
		<description><![CDATA[Im vorherigen Blogpost haben wir gesehen wie man ein einfaches Pub/Sub System mit den Bordmittel von Spring umsetzen kann. Seit Version 10.0 hat die Google Guava Library auch Support um ein einfaches Publish-Subscribe System aufzubauen. Das folgende Beispiel zeigt eine Möglichkeit wie man dies in einer Spring Applikation einsetzen kann. Die Pub/Sub Klassen der Google [...]]]></description>
			<content:encoded><![CDATA[<p>Im vorherigen <a href="http://blog.rasc.ch/?p=1838">Blogpost</a> haben wir gesehen wie man ein einfaches Pub/Sub System mit den Bordmittel von Spring umsetzen kann. </p>
<p>Seit Version 10.0 hat die <a href="http://code.google.com/p/guava-libraries/">Google Guava Library</a> auch Support um ein einfaches Publish-Subscribe System aufzubauen. Das folgende Beispiel zeigt eine Möglichkeit wie man dies in einer Spring Applikation einsetzen kann. Die Pub/Sub Klassen der Google Guava Library haben ein paar kleine Vorteile gegenüber einer reinen Spring Lösung die im folgenden beschrieben werden. </p>
<p>Zentrales Element ist die Klasse <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/eventbus/EventBus.html">EventBus</a>. Dies ist der Vermittler der die Messages von einem Publisher entgegennimmt und an interessierte Subscriber weiter leitet. Der EventBus wird sinnvollerweise als Singleton instanziiert und kann sehr einfach mit Spring verwaltet werden.</p>
<p></p><pre class="crayon-plain-tag">@Configuration
public class SpringConfig {
	@Bean
	public EventBus eventBus() {
		EventBus eventBus = new EventBus();
		return eventBus;
	}
}</pre><p></p>
<p>Eine Applikation kann aber auch mehrere EventBus Instanzen besitzen um damit beispielsweise verschiedene Bereiche/Module voneinander abzugrenzen. </p>
<p>Wie mit der Spring-Lösung benötigen wir auch hier Objekte die als Events vom Publisher zum Subscriber gesendet werden. Im Gegensatz zur reinen Spring-Lösung kann der EventBus von Guava jedes beliebige Objekt als Event verarbeiten. Es muss kein Interface implementiert oder eine Superklasse abgeleitet werden.</p>
<p></p><pre class="crayon-plain-tag">public class MsgEvent {
	private String message;

	public MsgEvent(String message) {
		this.message = message;
	}

	public String getMessage() {
		return message;
	}
}</pre><p></p>
<p>Der Publisher benötigt eine Referenz des EventBus damit er Events versenden kann. Mit Aufruf der post Methode wird das Event Objekt versendet.</p>
<p></p><pre class="crayon-plain-tag">@Service
public class Publisher {

	private EventBus eventBus;

	@Autowired
	public Publisher(EventBus eventBus) {
		this.eventBus = eventBus;
	}

	public void publishMsgEvent(String message) {
		eventBus.post(new MsgEvent(message));
	}
}</pre><p></p>
<p>Der Subscriber ist in diesem Beispiel auch ein gewöhnliches Spring Managed Bean. Es muss kein Interface implementiert werden, aber dafür muss für jedes Event das man verarbeiten möchte eine Methode erstellt werden die mit der Annotation <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/eventbus/Subscribe.html">@Subscribe</a> gekennzeichnet ist. Die Methode muss public sein und als einzigen Parameter das gewünschte Event Objekt besitzen.</p>
<p></p><pre class="crayon-plain-tag">@Service
public class Subscriber {
	@Subscribe
	public void handleMsgEvent(MsgEvent event) {
		System.out.println(&quot;MsgEvent: &quot; + event.getMessage());
	}	
}</pre><p></p>
<p>Ein Subscriber ist nicht auf ein Event beschränkt sondern kann mehrere verschiedene Events verarbeiten in dem für jedes gewünschte Event eine Methode implementiert wird.</p>
<p></p><pre class="crayon-plain-tag">@Service
public class Subscriber {

	@Subscribe
	public void handleMsgEvent(MsgEvent event) {
	...
	}

	@Subscribe
	public void handleSpecialMsgEvent(SpecialMsgEvent event) {
	...
	}

	...
}</pre><p></p>
<p>Als letzten Schritt müssen sich alle Subscriber beim EventBus registrieren. Dies geschieht mit der Methode EventBus.register. Wir könnten die EventBus Instanz in unseren Subscriber injizieren und dann zum Beispiel im Konstruktor oder einer @PostConstruct Methode eventBus.register(this) aufrufen. Bei vielen verschiedenen Subscriber Klassen kann dies umständlich werden oder sogar vergessen werden. </p>
<p>Da in diesem Beispiel die Subscriber als Spring Beans implementiert sind können wir stattdessen einen BeanPostProcessor implementieren der die Registrierung übernimmt. Die Methoden des BeanPostProcessor werden für jedes registrierte Bean des ApplicationContext aufgerufen. In der Methode postProcessAfterInitialization untersucht der Processor ob eine Methode mit der Annotation @Subscribe gekennzeichnet ist. Wenn ja wird das Bean im EventBus registriert.</p>
<p></p><pre class="crayon-plain-tag">@Service
public class EventBusSubscriberRegisterar implements BeanPostProcessor {

	private EventBus eventBus;

	@Autowired
	public EventBusSubscriberRegisterar(EventBus eventBus) {
		this.eventBus = eventBus;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

		for (Method method : bean.getClass().getMethods()) {
			if (method.getAnnotation(Subscribe.class) != null) {
				eventBus.register(bean);
				break;
			}
		}

		return bean;
	}
}</pre><p></p>
<p>Damit ist das Pub/Sub System einsatzbereit und ein Aufruf der Publisher.publishMsgEvent(&#8230;) löst den Aufruf des Listeners aus.</p>
<p><strong>Hierarchische Events</strong></p>
<p>Ein Feature des Guava EventBuses ist das die Event Objekte hierarchisch sind. Eine Subscriber Methode erhält nicht nur die Events des spezifizerten Parametertyps sondern auch von allen Subklassen davon. Nehmen wir als Beispiel die folgenden beiden Event Objekte. </p>
<p></p><pre class="crayon-plain-tag">public class MsgEvent {
...
}

public class SpecialMsgEvent extends MsgEvent {
...
}</pre><p></p>
<p>Ein Subscriber kann Messages vom Typ SpecialMsgEvent verarbeiten indem er folgende Methode implementiert. Diese Methode wird nur dann aufgerufen wenn ein Publisher ein SpecialMsgEvent versendet. </p>
<p></p><pre class="crayon-plain-tag">@Subscribe
public void handleSpecialMsgEvent(SpecialMsgEvent event) {
  ...
}</pre><p></p>
<p>Folgende Methode mit MsgEvent als Parameter wird dagegen immer dann aufgerufen wenn ein MsgEvent oder ein SpecialMsgEvent verschickt wird, da SpecialMsgEvent eine Subklasse von MsgEvent ist.</p>
<p></p><pre class="crayon-plain-tag">@Subscribe
public void handleMsgEvent(MsgEvent event) {
  ...
}</pre><p></p>
<p>Es ist daher möglich eine Methode mit Object als Parameter zu implementieren. Diese Methode wird für jedes versendete Event aufgerufen, da jedes Objekt in Java eine Subklasses von Object ist.</p>
<p></p><pre class="crayon-plain-tag">@Subscribe
public void handleAllEvents(Object event) {
  ...
}</pre><p></p>
<p><strong>DeadEvent</strong></p>
<p>Ein nützliches Feature während der Entwicklung ist das <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/eventbus/DeadEvent.html">DeadEvent</a>. Eine Subscribe Methode mit DeadEvent als Parameter wird immer dann aufgerufen wenn für ein Event keine eigene Subscribe Methode implementiert wurde. </p>
<p></p><pre class="crayon-plain-tag">@Subscribe
public void handleDeadEvents(DeadEvent deadEvent) {
	System.out.print(&quot;Event without a subscriber: &quot;);
	System.out.println(deadEvent.getEvent());
}</pre><p></p>
<p>Damit findet man recht einfach heraus ob unnütze Events versendet werden oder ob eine Subscribe Methode vergessen wurde zu implementieren.</p>
<p><strong>Asynchrones Eventhandling</strong></p>
<p>Gleich wie bei der reinen Spring-Lösung ruft der EventBus die Subscribe Methoden im gleichen Thread auf wie der Aufruf der eventBus.post Methode. Auch hier kann ein Subscriber den Ablauf blockieren indem umfangreiche Berechnungen gestartet werden. Um das zu verhindern benutzt man anstatt EventBus die Klasse <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/eventbus/AsyncEventBus.html">AsyncEventBus</a>. Diese Klasse ruft die Subscribe Methoden in eigenen Threads auf. Dem AsyncEventBus Konstruktor muss ein <a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executor.html">Executor</a> übergeben werden. Im folgenden ein Beispiel mit einem FixedThreadPool Executor mit 10 Threads. Damit ist es dem EventBus möglich 10 Listeners gleichzeitig in unterschiedlichen Threads aufzurufen. </p>
<p></p><pre class="crayon-plain-tag">@Bean
public EventBus eventBus() {
	AsyncEventBus asyncEventBus = new AsyncEventBus(Executors.newFixedThreadPool(10));
	return asyncEventBus;
}</pre><p></p>
<p><strong>Thread-Safe Handlers</strong></p>
<p>Ein weiteres Feature ist die Möglichkeit Event Handler Methoden als Thread-Safe zu kennzeichen.</p>
<p></p><pre class="crayon-plain-tag">@Subscribe
@AllowConcurrentEvents	
public void handleMsgEvent(MsgEvent event) {
	...
}</pre><p></p>
<p>Ist die Methode nur mit @Subscribe gekennzeichnet dann wird sie vom EventBus mit einem synchronized Block umschlossen und kann dadurch nicht gleichzeitig mehrfach ausgeführt werden. Die Annotation <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.2/javadoc/com/google/common/eventbus/AllowConcurrentEvents.html">@AllowConcurrentEvents</a> entfernt diesen synchronized Block und ermöglicht es mehreren Threads die Handler Methode gleichzeitig aufzurufen und auszuführen.</p>
<p>Sourcecode dieser Beispiel: <a href="https://github.com/ralscha/playground/tree/master/eventbus/src/main/java/ch/rasc/pubsub/guava">https://github.com/ralscha/playground/tree/master/eventbus/src/main/java/ch/rasc/pubsub/guava</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1853</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pub/Sub mit Spring</title>
		<link>http://blog.rasc.ch/?p=1838</link>
		<comments>http://blog.rasc.ch/?p=1838#comments</comments>
		<pubDate>Thu, 19 Apr 2012 11:29:22 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[pub/sub]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.rasc.ch/?p=1838</guid>
		<description><![CDATA[Ein weit verbreitetes Programmiermodel ist die Event getriebene Programmierung. Hier gibt es Quellen die Events erstellen und senden (z.B. bei einer Benutzereingabe) und es existieren Empfänger, welche die Events verarbeiten. Ein klassisches Design Pattern ist das Observer Pattern. Das zu überwachende Objekt (Observable) führt eine Liste von Überwachobjekten (Observer), die beim Auftreten eines Ereignisses informiert [...]]]></description>
			<content:encoded><![CDATA[<p>Ein weit verbreitetes Programmiermodel ist die Event getriebene Programmierung. Hier gibt es Quellen die Events erstellen und senden (z.B. bei einer Benutzereingabe) und es existieren Empfänger, welche die Events verarbeiten.</p>
<p>Ein klassisches Design Pattern ist das <a href="http://en.wikipedia.org/wiki/Observer_pattern">Observer Pattern</a>. Das zu überwachende Objekt (Observable) führt eine Liste von Überwachobjekten (Observer), die beim Auftreten eines Ereignisses informiert werden möchten. Das Observable Objekt ist dann zuständig das die Observer aufgerufen werden. </p>
<p>Beim <a href="http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern">Publish-Subscribe Pattern</a> enkuppelt man den Sender (Publisher) und den Empfänger (Subscriber) voneinander. Der Sender sendet die Nachricht nicht direkt an den Empfänger sondern an einen Vermittler. Empfänger bekunden ihr Interesse in dem sie beim Vermittler bestimmte Nachrichten abonnieren. Der Vermittler ist dann zuständig das die Nachrichten zu den interessierten Empfängern gelangt. Empfänger und Sender kennen sich in diesem Pattern nicht mehr. Es kann daher vorkommen das niemand ein bestimmtes Event sendet auf das der Empfänger wartet und umgekehrt kann ein Sender Events absetzen die niemanden interessieren.</p>
<p>Ein klassischer Publish/Subscriber Vermittler im Java Umfeld ist Java Message Service (JMS). Dies ist ein Service der entweder eigenständig oder als Bestandteil eines JEE Servers läuft. Verteilte Systeme melden sich an diesem Server Prozess an und können Nachrichten absetzen oder sich als Subscriber anmelden.</p>
<p>Benötigt man nur ein einfaches Eventsystem innerhalb einer Spring Applikation und einer Virtual Machine, dann kann man dies mit den Bordmitteln umsetzen. </p>
<p>Als erstes erstellen wir das Event, das vom Empfänger zum Sender gesendet wird. Die Klasse muss eine Subklasse von <a href="http://www.rasc.ch/spring/org/springframework/context/ApplicationEvent.html">org.springframework.context.ApplicationEvent</a> sein. </p>
<p></p><pre class="crayon-plain-tag">import org.springframework.context.ApplicationEvent;
public class AppEvent extends ApplicationEvent {
	private String message;

	public AppEvent(Object source, String message) {
		super(source);
		this.message = message;
	}

	public String getMessage() {
		return message;
	}
}</pre><p></p>
<p>Der Publisher ist ein Spring Managed Bean und benötigt eine Referenz des <a href="http://www.rasc.ch/spring/org/springframework/context/ApplicationEventPublisher.html">ApplicationEventPublisher</a>. Mit Hilfe dieser Klasse werden die Events versendet. In diesem Beispiel wird der Publisher via Konstruktor injiziert. In Spring implementiert der ApplicationContext das ApplicationEventPublisher Interface. Die Instanz die in diesem Beispiel injiziert wird ist also ein <a href="http://www.rasc.ch/spring/org/springframework/context/annotation/AnnotationConfigApplicationContext.html">AnnotationConfigApplicationContext</a>.</p>
<p></p><pre class="crayon-plain-tag">import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

@Service
public class EventPublisher {
	private ApplicationEventPublisher publisher;

	@Autowired
	public EventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}

	public void publishEvent(String message) {
		publisher.publishEvent(new AppEvent(this, message));
	}
}</pre><p></p>
<p>Mit der publishEvent Method können Events versendet werden. Als Parameter wird das Event übergeben (Zeile 15). </p>
<p>Der Listener ist auch ein Spring Managed Bean und muss das Interface <a href="http://www.rasc.ch/spring/org/springframework/context/ApplicationListener.html">ApplicationListener</a><AppEvent> implementieren. Dazu muss die Methode onApplicationEvent(AppEvent event) ausprogrammiert werden.</p>
<p></p><pre class="crayon-plain-tag">import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Service;

@Service
public class EventListener implements ApplicationListener&lt;AppEvent&gt; {
	@Override
	public void onApplicationEvent(AppEvent event) {
		System.out.println(new Date() + &quot;: &quot; + event.getMessage());
	}
}</pre><p></p>
<p>Der Listener muss nicht speziell registriert werden. Es genügt wenn er ein Spring Managed Bean ist. Die Registrierung erfolgt automatisch beim Aufstarten des ApplicationContext.</p>
<p>Wir können nun mit einem Testprogramm die Spring Umgebung starten und das Event versenden und der Listener wird aufgerufen.</p>
<p></p><pre class="crayon-plain-tag">public static void main(String[] args) {
	final AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(&quot;ch.rasc.pubsub.spring&quot;);
	ctx.getBean(EventPublisher.class).publishEvent(&quot;hello world&quot;);
}</pre><p></p>
<p>Ein mögliches Problem ist das per Default alle Listener im gleichen Thread wie der Aufruf der publishEvent Methode des Publisher aufgerufen werden. Dies birgt die Gefahr dass ein Listener den ganzen Ablauf blockieren kann indem er eine umfangreiche Berechnung in der onApplicationEvent Methode startet. Man kann dies Verhindern indem die Listeners in eigenen Threads aufgerufen werden. Dazu muss der <a href="http://www.rasc.ch/spring/org/springframework/context/event/SimpleApplicationEventMulticaster.html">SimpleApplicationEventMulticaster</a>, der zuständig für das Ausführen der Listener Methoden ist, mit einem <a href="http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executor.html">Executor</a> konfiguriert werden. Hier ein Beispiel mit Java Config und einem Executor mit einem Thread Pool von 10 Threads. </p>
<p></p><pre class="crayon-plain-tag">@Bean
public ApplicationEventMulticaster applicationEventMulticaster() {
	SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
	multicaster.setTaskExecutor(Executors.newFixedThreadPool(10));
	return multicaster;
}</pre><p></p>
<p>Sourcecode der Beispiele: <a href="https://github.com/ralscha/playground/tree/master/eventbus/src/main/java/ch/rasc/pubsub/spring">https://github.com/ralscha/playground/tree/master/eventbus/src/main/java/ch/rasc/pubsub/spring</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1838</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache POI 3.8: Weniger RAM</title>
		<link>http://blog.rasc.ch/?p=1817</link>
		<comments>http://blog.rasc.ch/?p=1817#comments</comments>
		<pubDate>Mon, 02 Apr 2012 12:57:24 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[poi]]></category>

		<guid isPermaLink="false">http://blog.rasc.ch/?p=1817</guid>
		<description><![CDATA[Am 28. März 2012 ist Apache POI 3.8 erschienen. Änderungen und Neuerungen findet man in diesem Announcement Post. Eine interessante Neuerung ist die Klasse SXSSFWorkbook. Dies ist eine Streaming Variante der bestehenden XSSFWorkbook Klasse um Excel im Office Open XML Workbook (.xlsx) Format zu erstellen. Das Problem ist das wenn sehr grosse Excel generiert werden [...]]]></description>
			<content:encoded><![CDATA[<p>Am 28. März 2012 ist <a href="http://poi.apache.org/">Apache POI</a> 3.8 erschienen. Änderungen und Neuerungen findet man in diesem <a href="http://mail-archives.apache.org/mod_mbox/www-announce/201203.mbox/%3CCAAwi-j-CcSJN5AnFcLSPmV-TP0Zoh+psn5ie0pZo1Mz7BQgXJg@mail.gmail.com%3E">Announcement Post</a>. </p>
<p>Eine interessante Neuerung ist die Klasse <a href="http://poi.apache.org/apidocs/org/apache/poi/xssf/streaming/SXSSFWorkbook.html">SXSSFWorkbook</a>. Dies ist eine Streaming Variante der bestehenden <a href="http://poi.apache.org/apidocs/org/apache/poi/xssf/usermodel/XSSFWorkbook.html">XSSFWorkbook</a> Klasse um Excel im  <a href="http://en.wikipedia.org/wiki/Office_Open_XML">Office Open XML Workbook</a> (.xlsx) Format zu erstellen. </p>
<p>Das Problem ist das wenn sehr grosse Excel generiert werden benötigt das XSSFWorkbook sehr viel RAM, da das ganze Workbook im Speicher abgebildet werden muss. Mit SXSSFWorkbook werden immer nur eine konfigurierte Anzahl Rows im Speicher abgelegt und die übrigen Rows in temporäre Dateien zwischengespeichert. </p>
<p>Im folgenden ein Beispiel das ein Excel mit 10&#8217;000 Rows zu je 10 Spalten erzeugt. Mit XSSF liegt der Speicherverbrauch bei ca. 122 MB. </p>
<p></p><pre class="crayon-plain-tag">Workbook wb = new XSSFWorkbook();
Sheet sh = wb.createSheet();
for (int rownum = 0; rownum &amp;lt; 10000; rownum++) {
	Row row = sh.createRow(rownum);
	for (int cellnum = 0; cellnum &amp;lt; 10; cellnum++) {
		Cell cell = row.createCell(cellnum);
		String address = new CellReference(cell).formatAsString();
		cell.setCellValue(address);
	}

}		
Runtime rt = Runtime.getRuntime();
rt.gc();
System.out.println(&quot;Used memory: &quot; + ((rt.totalMemory()-rt.freeMemory())/1024));
File f = new File(&quot;xssf.xlsx&quot;);
FileOutputStream out = new FileOutputStream(f);
wb.write(out);
out.close();</pre><p></p>
<p>Um SXSSF zu verwenden muss nur die erste Zeile geändert werden. Der Speicherverbrauch mit SXSSFWorkbook liegt bei ca. 4 MB</p>
<p></p><pre class="crayon-plain-tag">Workbook wb = new SXSSFWorkbook(100)</pre><p></p>
<p>Dem Constructor übergibt man die Grösse des &#8220;Row-Window&#8221;. Wenn nichts übergeben wird ist der Defaultwert 100 Rows. SXSSF hält in diesem Beispiel immer 100 Rows im Speicher. Sobald die 101. Row erstellt wird, wird die erste Row &#8220;geflusht&#8221; und kann nicht mehr angesprochen werden. Sobald die 102. Zeile erstellt wird, ist auch die 2 Row nicht mehr ansprechbar usw. Das &#8220;Window&#8221; bewegt sich also ständig mit und hält die letzten 100 Rows im Speicher. </p>
<p>POI schreibt die &#8220;geflushten&#8221; Rows in temporäre Dateien. Diese Dateien können unter Umständen sehr gross werden. POI ermöglicht deshalb diese Dateien zu komprimieren. Dazu muss das <a href="http://poi.apache.org/apidocs/org/apache/poi/xssf/streaming/SXSSFWorkbook.html#setCompressTempFiles(boolean)">compressTempFiles</a> Flag auf true gesetzt werden:</p>
<p></p><pre class="crayon-plain-tag">((SXSSFWorkbook)wb).setCompressTempFiles(true);</pre><p></p>
<p>Da mit SXSSF nicht mehr alle Rows im Speicher vorhanden sind gibt es einige Einschränkungen. Löschen von Sheets/Rows/Cells, Rows verschieben und Clonen von Sheets ist nicht möglich. Diese <a href="http://poi.apache.org/spreadsheet/index.html">Tabelle</a> listet die Unterschiede und Möglichkeiten der verschiedenen POI Excel Apis auf.</p>
<p>Weitere Infos zu SXSSF findet man auch im <a href="http://poi.apache.org/spreadsheet/how-to.html#sxssf">Apache POI HOWTO</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1817</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Datum/Zeit Libraries in Javascript</title>
		<link>http://blog.rasc.ch/?p=1800</link>
		<comments>http://blog.rasc.ch/?p=1800#comments</comments>
		<pubDate>Wed, 14 Mar 2012 11:30:13 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[moment.js]]></category>
		<category><![CDATA[sugar]]></category>
		<category><![CDATA[xdate]]></category>

		<guid isPermaLink="false">http://blog.rasc.ch/?p=1800</guid>
		<description><![CDATA[Um in Javascript mit Daten und Zeiten zu arbeiten gibt es das Date Objekt. Ein Aufruf des Konstruktors ohne Argumente liefert ein Objekt mit dem aktuellen Datum und der aktuellen Zeit zurück. [crayon-4fb9571716d8c/] Ein spezifisches Datum lässt sich mit der Übergabe von Argumenten erstellen. Date kann Strings im Format RFC2822 verarbeiten. Neuere Browser unterstützen auch [...]]]></description>
			<content:encoded><![CDATA[<p>Um in Javascript mit Daten und Zeiten zu arbeiten gibt es das <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date">Date</a> Objekt.</p>
<p>Ein Aufruf des Konstruktors ohne Argumente liefert ein Objekt mit dem aktuellen Datum und der aktuellen Zeit zurück.</p><pre class="crayon-plain-tag">var now = new Date();
var now = Date.now(); //In neueren Browsern</pre><p></p>
<p>Ein spezifisches Datum lässt sich mit der Übergabe von Argumenten erstellen. Date kann Strings im Format <a href="http://tools.ietf.org/html/rfc2822#page-14">RFC2822</a> verarbeiten. Neuere Browser unterstützen auch einen <a href="http://www.w3.org/TR/NOTE-datetime">Teil</a> des <a href="http://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a> Standards. Oder man übergibt die Anzahl Millisekunden seit Mitternacht 1.1.1970 UTC. Als dritte Möglichkeit übergibt man Jahr, Monat, Tag und optional Stunden, Minuten, Sekunden, Millisekunden.</p>
<p></p><pre class="crayon-plain-tag">new Date(1331121652499); //7. M&auml;rz 2012 13:00:52 GMT+1
new Date(&quot;2012-03-07T07:04:12&quot;); //7. M&auml;rz 2012 08:04:12 GMT+1
new Date(2012, 2, 7); //7. M&auml;rz 2012
new Date(2012, 2, 7, 13, 0, 0, 0); //7. M&auml;rz 2012 13:00:00</pre><p></p>
<p>Beim Monat muss darauf geachtet werden das dieser 0 basiert ist (0 = Januar, 11 = Dezember). Nicht vergessen sollte man <em>new</em> anzugeben. Ohne <em>new</em> erhält man anstatt einem Date einen String zurück, der das aktuelle Datum und Zeit beinhaltet.</p>
<p></p><pre class="crayon-plain-tag">Date()    //&quot;Sun Mar 11 2012 11:48:27 GMT+0100 (W. Europe Standard Time)&quot;</pre><p></p>
<p>Das Date Objekt liefert Funktionen mit um Teile des Datums und der Zeit zu lesen und zu verändern. Zum Beispiel liest folgender Code das aktuelle Jahr.</p>
<p></p><pre class="crayon-plain-tag">var now = new Date();
var year = now.getFullYear(); //2012</pre><p></p>
<p>Mit <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/setFullYear">setFullYear(year)</a> wird das Datum auf ein bestimmtes Jahr gesetzt.</p>
<p></p><pre class="crayon-plain-tag">var twoYearsAgo = new Date();
twoYearsAgo.setFullYear(2010);</pre><p></p>
<p>Eine Auflistung der Date Funktionen findet man auf dem <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date">Mozilla Developer Network</a>.</p>
<p>Mit den get/set Funktionen lassen sich auch einfache Berechnungen durchführen. Folgender Code erstellt ein Date Objekt das 3 Tage in der Zukunft liegt.</p>
<p></p><pre class="crayon-plain-tag">var d = new Date();
d.setDate(d.getDate()+3);</pre><p></p>
<p>Differenzen lassen sich mit der Funktion <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/getTime">getTime</a> berechnen. Diese Funktion liefert die Anzahl Millisekunden seit dem 1.1.1970 zurück.</p><pre class="crayon-plain-tag">var d1 = new Date(2012, 0, 1);
var d2 = new Date(2012, 11, 31);
var diffInMillis = d2.getTime()-d1.getTime()</pre><p></p>
<p>Ein Schwachpunkt des nativen Date Objektes ist Parsen und Formatieren von Datum und Zeit. Date kennt zwar die <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/parse">parse</a> Funktion aber der String muss entweder als RFC2822 oder ISO 8601 (Subset) übergeben werden. Auch beim Konvertieren in einen String kennt Date einige Funktionen (z.B. <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/toISOString">toISOString</a>, <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/toLocaleString">toLocaleString</a>). Aber wenn man sein eigenes Datumsformat ausgeben will muss dies programmiert werden. </p>
<p>Da Berechnungen und Parsen/Formatieren vom nativen Date Objekt nicht genügend unterstützt werden, gibt es einige Libraries die hier in die Lücke springen und die Behandlung von Datum und Zeit versuchen zu vereinfachen.</p>
<p>Wir schauen uns im folgenden die Libraries <a href="http://arshaw.com/xdate/">XDate</a>, <a href="http://momentjs.com/">Moment.js</a> und <a href="http://sugarjs.com/">Sugar</a> genauer an. </p>
<h5><a href="http://arshaw.com/xdate/">XDate</a></h5>
<p>XDate ist komprimiert (gzip) 2.9 kB gross und hat keine Abhängigkeit zu anderen Libraries. Das zentrale Objekt in XDate ist <a href="http://arshaw.com/xdate/#Constructors">XDate</a>. Ein aktuelles Datum mit aktueller Zeit lässt sich, wie das Date Objekt, mit new erstellen.</p>
<p></p><pre class="crayon-plain-tag">var now = new XDate();</pre><p></p>
<p>XDate unterstützt alle Konstruktor Aufrufe die vom Date bekannt sind. Zusätzlich kann ein Date Objekt als Argument dem Konstruktor übergeben werden.</p><pre class="crayon-plain-tag">var date = new Date(2010, 0, 1);
var xdate = new XDate(date);</pre><p></p>
<p>Umgekehrt lässt sich mit toDate aus dem XDate das Date Objekt extrahieren.</p><pre class="crayon-plain-tag">var mydate = xdate().toDate();</pre><p></p>
<p>XDate kennt die vom Date Objekt bekannten get/set Funktionen. Interessant sind die zusätzlichen Funktionen mit denen sich Berechnungen durchführen lassen. Folgendes Beispiel berechnet die Differenz in Tagen bis zu Weihnachen.</p><pre class="crayon-plain-tag">var now = new XDate()
var xmas = new XDate();
xmas.setDate(25);
xmas.setMonth(11);
var diffInDays = now.diffDays(xmas);</pre><p></p>
<p>Für jede Einheit (Year, Month, Week, …) gibt es eine entsprechende diff<em>Einheit</em> Funktion (diffYears, diffMonths, diffWeeks)</p>
<p>Einheiten addieren und subtrahieren lassen sich mit der entsprechenden add<em>Einheit</em> Funktion</p><pre class="crayon-plain-tag">var now = new XDate()
now.addDays(3);

var now = new XDate()
now.addDays(-3);</pre><p></p>
<p>Beim Parsen unterstützt XDate nur Strings im Format <a href="http://en.wikipedia.org/wiki/ISO_8601">ISO8601</a> und <a href="http://tools.ietf.org/html/rfc3339">IETF</a>.</p><pre class="crayon-plain-tag">new XDate(&quot;2011-09-05&quot;);
new XDate(&quot;2011-09-05T12:30:00Z&quot;);</pre><p></p>
<p>Beim Formattieren bietet XDate mit den Funktionen toString  und toUTCString mehr Möglichkeiten als Date. Mann kann diesen Funktionen einen Formatstring mitgeben der das Outputformat beschreibt.</p>
<p></p><pre class="crayon-plain-tag">var s = new XDate(2012, 6, 3).toString(&quot;dd.MM.yyyy&quot;); //03.07.2012
var s = new XDate(2012, 6, 3).toString(&quot;d. MMMM yyyy&quot;); //3. July 2012
var s = new XDate(2012, 6, 3).toString(&quot;d. MMM yyyy&quot;);</pre><p>Eine Beschreibung der unterstützten Tokens findet man hier: <a href="http://arshaw.com/xdate/#Formatting">http://arshaw.com/xdate/#Formatting</a></p>
<p>Localization wird auch unterstützt. Allerdings müssen die benötigten Strings für Monatsname und Wochentagname selber angegeben werden. Hier ein Beispiel für Französisch: <a href="https://gist.github.com/1221376">https://gist.github.com/1221376</a></p>
<h5><a href="http://momentjs.com/">Moment.js</a></h5>
<p>Diese Library ist minified und komprimiert 3.3 kB gross und hat, wie XDate, keine Abhängigkeit zu anderen Libraries. Moment.js liefert verschiedene Sprachen mit die allerdings nicht im Core Javascript enthalten sind sondern bei Bedarf zusätzlich geladen werden müssen.</p>
<p>Das zentrale Objekt in Moment.js ist moment. Folgender Code erzeugt ein Objekt mit dem aktuellen Datum und Zeit.</p><pre class="crayon-plain-tag">var now = moment();</pre><p></p>
<p>Der Funktion moment können auch ein bestehendes Date Objekt oder die Anzahl Millisekunden übergeben werden um damit ein bestimmtes Datum zu erzeugen.</p><pre class="crayon-plain-tag">var d = moment(new Date(2020, 3, 7));
var d = moment(1318781876406);</pre><p></p>
<p>Eine weitere Möglichkeit ist ein Array mit Parametern zu übergeben. Die Reihenfolge der Zahlen im Array entspricht dem Konstruktor Aufruf beim Date Objekt. Wenn Bestandteile wegelassen werden wird immer der kleinste Wert angenommen.</p><pre class="crayon-plain-tag">var d = moment([2012]); // 1 Januar 2012

var d = moment([2012, 2]); // 1 M&auml;rz 2012

var d = moment([2012, 6, 10]); // 10 Juli 2012</pre><p></p>
<p>Mehr Möglichkeiten als Date und XDate bietet Moment.js beim Parsen von Strings. Hier kann ein Formatstring mitgegeben werden der angibt in welchem Format der String aufgebaut ist.</p><pre class="crayon-plain-tag">var d= moment(&quot;25.12.2012&quot;, &quot;DD.MM.YYYY&quot;);</pre><p></p>
<p>Die Beschreibung der unterstützen Tokens findet man in der Dokumentation: <a href="http://momentjs.com/docs/#/parsing/date">http://momentjs.com/docs/#/parsing/date</a></p>
<p>Formatieren lässt sich ein Datum mit der <a href="http://momentjs.com/docs/#/display/format">format</a> Funktion. Diese Funktion unterstützt die gleichen Tokens wie das Parsen.</p><pre class="crayon-plain-tag">d.format(&quot;YYYY-MM-DD&quot;); //2012-12-25</pre><p></p>
<p>Eine Möglichkeit um die Differenz zwischen zwei Daten auszugeben bietet <a href="http://momentjs.com/docs/#/display/from">from</a> an. Damit lassen sich Strings wie &#8220;a day ago&#8221; oder &#8220;in 5 days&#8221; erzeugen.</p><pre class="crayon-plain-tag">var a = moment([2012, 3, 9]);
var b = moment([2012, 3, 20]);

a.from(b); //&quot;11 days ago&quot;
b.from(a); //&quot;in 11 days&quot;
b.from([2012, 3, 21]);  //&quot;a day ago&quot;     

var a = moment([2012, 0, 1, 13, 0, 0]);
var b = moment([2012, 0, 1, 13, 5, 0]);
a.from(b); //&quot;5 minutes ago&quot;
b.from(a); //&quot;in 5 minutes&quot;</pre><p></p>
<p>Moment.js liefert auch Funktionen mit  um einzelne Bestandteile eines Datums zu lesen und zu ändern. Im Gegensatz zu Date haben diese Funktionen kein set/get Prefix.</p><pre class="crayon-plain-tag">var day = moment(&quot;25.12.2012&quot;, &quot;DD.MM.YYYY&quot;);
day.date(); // 25

day.date(26);
day.format(&quot;DD.MM.YYYY&quot;); //26.12.2012</pre><p></p>
<p>Diese Funktionen lassen sich auch miteinander verketten.</p><pre class="crayon-plain-tag">moment().date(23).hours(0).minutes(0).seconds(0).milliseconds(0);</pre><p></p>
<p>Um die Zeit auf 00:00:00.000 zu setzen gibt es die Funktion <a href="http://momentjs.com/docs/#/manipulation/sod">sod</a> (start of day) und <a href="http://momentjs.com/docs/#/manipulation/eod">eod</a> (end of day) um die Zeit auf 23:59:59.999 zu setzen.</p>
<p>Zusätzlich kann mit <a href="http://momentjs.com/docs/#/manipulation/day">day</a> der Wochentag gesetzt werden. Dabei ist 0 = Sonntag und 6 = Samstag. Mit der Subtraktion oder Addition von 7 lässt sich der Wochentag von letzter oder nächster Woche setzen.</p><pre class="crayon-plain-tag">var d = moment(&quot;07.03.2012&quot;, &quot;DD.MM.YYYY&quot;);
d.day(5); //Freitag 09.03.2012

d.day(5 + 7); //Freitag 16.03.2012

d.day(5 + 7 + 7); //Freitag 30.03.2012

var d = moment(&quot;07.03.2012&quot;, &quot;DD.MM.YYYY&quot;);
d.day(5 - 7); //Freitag 02.03.2012</pre><p></p>
<p>Die Funktion <a href="http://momentjs.com/docs/#/display/diff">diff</a> berechnet Differenzen zwischen zwei Daten. Dabei kann spezifiziert werden in welcher Einheit das Ergebnis zurückgegeben werden soll.</p><pre class="crayon-plain-tag">var a = moment([2012, 0, 1]);
var b = moment([2012, 5, 23]);
b.diff(a); //Millisekunden: 15033600000

b.diff(a, 'days'); //Tage: 174

b.diff(a, 'months'); //Monate: 6
b.diff(a, 'months', true); //Monate: 5.7333</pre><p></p>
<p>Additionen und Subtraktionen lassen sich mit <a href="http://momentjs.com/docs/#/manipulation/add">add</a> und <a href="http://momentjs.com/docs/#/manipulation/subtract">subtract</a> durchführen.</p><pre class="crayon-plain-tag">var a = moment([2012, 0, 1]);
a.add('days', 10); //11.01.2012
a.subtract('months', 1); //11.12.2011</pre><p></p>
<p>Eine weitere nützliche Funktion von Moment.js ist <a href="http://momentjs.com/docs/#/display/leapyear">isLeapYear</a> die true oder false zurückliefert.</p><pre class="crayon-plain-tag">moment([2012]).isLeapYear(); //true
moment([2011]).isLeapYear(); //false</pre><p></p>
<h5><a href="http://sugarjs.com/">Sugar</a></h5>
<p>Sugar ist keine reine Datumslibrary sondern erweitert alle nativen Javascript Objekte (Array, String, Number, …) um weitere Funktionen. Die Library ist deshalb einiges grösser (17kB gzipped). Sugar liefert aber eine Version aus (sugar-x.x.x-dates-only.min.js) die nur die Datumsfunktionen beinhaltet.</p>
<p>Im Gegensatz zu XDate und Moment.js gibt es hier kein neues Objekt sondern die zusätzlichen Funktion werden im Prototype des entsprechenden Objektes angefügt und stehen dann überall zur Verfügung.</p>
<p>Um ein Datumsobjekt zu erstellen führt Sugar die Funktion <a href="http://sugarjs.com/api/Date/create">create</a> ein.</p><pre class="crayon-plain-tag">Date.create(2012, 1);  //1. Februar 2012
Date.create(2012, 1, 13); //13. Februar 2012
Date.create(2012, 1, 13, 10, 45); //13. Februar 2012 10:45 Uhr</pre><p></p>
<p>Zusätzlich erlaubt es <a href="http://sugarjs.com/api/Date/create">create</a> auch Daten aus Strings zu parsen.</p><pre class="crayon-plain-tag">Date.create(&quot;2012-02&quot;); //1. Feburar 2012
Date.create(&quot;2012-02-13&quot;); //13. February 2012
Date.create(&quot;02.13.2012&quot;); //13. February 2012
Date.create(&quot;02/13/2012&quot;); //13. February 2012
Date.create(&quot;2012-02-13 10:45:00&quot;); //13. Februar 2012 10:45 Uhr
Date.create(&quot;February 2012&quot;); //1. Februar 2012</pre><p></p>
<p>Sugar kann auch spezielle String wie &#8220;today&#8221; oder &#8220;the 13th of next month&#8221; verarbeiten. Eine Liste von möglichen Werten findet man in der <a href="http://sugarjs.com/dates">Dokumentation</a>.</p><pre class="crayon-plain-tag">Date.create(&quot;today&quot;); //11. M&auml;rz 2012
Date.create(&quot;the 13th of next month&quot;); //13. April 2012
Date.create(&quot;this week friday&quot;); //16. M&auml;rz 2012
Date.create(&quot;last monday&quot;); //5. M&auml;rz 2012
Date.create(&quot;10 minutes ago&quot;);</pre><p></p>
<p>Mit der zusätzlichen Angabe einer Sprache werden auch andere Sprachen und Formate verstanden.</p><pre class="crayon-plain-tag">Date.create(&quot;13.2.2012&quot;, &quot;de&quot;); //13. Februar 2012
Date.create(&quot;heute&quot;, &quot;de&quot;); //11. M&auml;rz 2012
Date.create(&quot;aujourd'hui&quot;, &quot;fr&quot;); //11. M&auml;rz 2012</pre><p></p>
<p>Mit <a href="http://sugarjs.com/api/Date/set">set</a> können beliebige Teile des Datums und der Zeit verändert werden.</p><pre class="crayon-plain-tag">Date.create().set({day: 21}); //21. M&auml;rz 2012
Date.create().set({day: 21, month: 1}); //21. Februar 2012
Date.create().set({day: 21, month: 1, year: 2015}); //21. Februar 2015</pre><p></p>
<p><a href="http://sugarjs.com/api/Date/beginningOfUnit">beginningOfUnit</a> setzt das Datum an den Beginn der entsprechenden Einheit. Mit dem Gegenstück <a href="http://sugarjs.com/api/Date/endOfUnit">endOfUnit</a> setzt man das Datum an das Ende der entsprechenden Einheit.</p><pre class="crayon-plain-tag">Date.create().beginningOfWeek(); //11. M&auml;rz 2012
Date.create().beginningOfMonth(); //1. M&auml;rz 2012
Date.create().beginningOfYear(); //1. Januar 2012
Date.create().endOfYear(); //31. Dezember 2012
Date.create().endOfMonth(); //31. M&auml;rz 2012
Date.create().endOfWeek(); //17. M&auml;rz 2012</pre><p></p>
<p>Für die Datumsarithmetik steht die Funktionen <a href="http://sugarjs.com/api/Date/addUnits">addUnits</a> zur Verfügung. Zusätzlich kann mit <a href="http://sugarjs.com/api/Date/rewind">rewind</a> und <a href="http://sugarjs.com/api/Date/advance">advance</a> das Datum um bestimmte Werte &#8220;vorgespult&#8221; oder &#8220;zurückgespult&#8221; werden.</p><pre class="crayon-plain-tag">Date.create().addDays(3); //14. M&auml;rz 2012
Date.create().addDays(-3); //8. M&auml;rz 2012
Date.create().addMonths(1); //11. April 2012
Date.create().addMonths(-1); //11. Februar 2012

Date.create().advance({days: 3, months: 1}); //14. April 2012
Date.create().rewind({days: 3, months: 1}); //8. Februar 2012</pre><p></p>
<p>Sugar bietet umfangreiche Funktionen an um Daten zu vergleichen. Es ist möglich zwei Daten miteinander zu vergleichen und zu prüfen ob eins davon zeitlich vor dem anderen liegt. <a href="http://sugarjs.com/api/Date/isBetween">isBetween</a> erlaubt es zu prüfen ob ein Datum zwischen zwei Daten liegt. <a href="http://sugarjs.com/api/Date/isFuture">isFuture</a> und <a href="http://sugarjs.com/api/Date/isPast">isPast</a> ermöglichen eine Prüfung ob ein Datum in der Zukunft oder in der Vergangenheit liegt. Mit <a href="http://sugarjs.com/api/Date/is">is</a> kann geprüft werden ob das Datum auf einem bestimmten Tag, Monat, Jahr liegt. <a href="http://sugarjs.com/api/Date/isDay">isWeekend</a> und <a href="http://sugarjs.com/api/Date/isDay">isWeekday</a> prüfen das Datum darauf ob es auf einem Samstag-Sonntag oder Montag-Freitag liegt.</p>
<p></p><pre class="crayon-plain-tag">var a = Date.create(2012, 0); //1. Januar 2012
var b = Date.create(&quot;last day of april&quot;); //30. April 2012
var q = Date.create(&quot;2012-03-13&quot;); //13. M&auml;rz 2012

a.isBefore(q); //true
b.isAfter(q); //true
q.isBetween(a,b); //true
q.isBetween(&quot;January&quot;, &quot;July&quot;); //true
q.isPast(); //false
q.isFuture(); //true
q.isLeapYear(); //true
q.isWeekend(); //false
q.isWeekday(); //true
q.isThisMonth(); //true
q.isToday(); //false
q.is(&quot;2012&quot;); //true
q.isAfter(&quot;April&quot;); //false
q.is(&quot;March&quot;); //true</pre><p></p>
<p>Differenzen zwischen zwei Daten lassen sich mit <a href="http://sugarjs.com/api/Date/unitsSince">unitsSince</a> und <a href="http://sugarjs.com/api/Date/unitsUntil">unitsUntil</a> berechnen.</p><pre class="crayon-plain-tag">var a = Date.create(2012, 7);
var b = Date.create(2012, 8, 23);
   a.daysUntil(b); //53
a.daysSince(b); //-53
a.monthsUntil(b); //2
a.minutesUntil(b); //76320</pre><p></p>
<p>Mit der Funktion <a href="http://sugarjs.com/api/Date/format">format</a> kann ein Datum auf unterschiedlichste Arten in einen String umgewandelt werden. Dazu übergibt man der Funktionen einen String der das Format beschreibt. Die einzelnen Tokens werden mit geschweiften Klammern {..} umschlossen. Zusätzlich existieren Konstanten, wie Date.ISO8601_DATETIME, die ein standardisiertes Format beschreiben und der format Funktion übergeben werden können.</p><pre class="crayon-plain-tag">Date.create().format(); //&quot;March 11, 2012&quot;
Date.create().format('{yyyy}-{MM}-{dd}'); //&quot;2012-03-11&quot;
Date.create().format('{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}'); //&quot;2012-03-11 10:45:33&quot;
Date.create().format('Datum: {dd}. {Month} {yyyy} Zeit: {HH}:{mm}:{ss}', 'de'); //&quot;Datum: 11. M&auml;rz 2012 Zeit: 10:46:44&quot;

Date.create().format(Date.ISO8601_DATETIME); //&quot;2012-03-11T10:47:18.050+01:00&quot;
Date.create().format(Date.RFC1036); //&quot;Sunday, 11-Mar-12 10:47:30 +0100&quot;
Date.create().format(Date.RFC1123, &quot;de&quot;); //&quot;Son, 11 M&auml;r 2012 10:47:43 +0100&quot;</pre><p></p>
<p>Sugar kennt, wie Moment.js, Funktionen um Strings wie &#8220;4 days ago&#8221; und &#8220;10 minutes from now&#8221; zu erzeugen.</p><pre class="crayon-plain-tag">Date.create().addMinutes(-10).relative(); //&quot;10 minutes ago&quot;
Date.create().addMinutes(10).relative(); //&quot;10 minutes from now&quot;
Date.create().addMinutes(-10).relative('de'); //&quot;vor 10 Minuten&quot;
Date.create().addMinutes(10).relative('de'); //&quot;in 10 Minuten&quot;
Date.create(2012, 0).relative(); //&quot;2 months ago&quot;</pre><p></p>
<p>Sugar erweiter nicht nur das Date Objekt, sondern auch das Number Objekt um Datumsfunktionen, wie zum Beispiel <a href="http://sugarjs.com/api/Date/unitBefore">unitBefore</a> und <a href="http://sugarjs.com/api/Date/unitAfter">unitAfter</a>. Oder die <a href="http://sugarjs.com/api/Date/unit">unit</a> Funktionen um eine Einheit in Millisekunden umzurechnen.</p><pre class="crayon-plain-tag">(2).hours(); //7200000
(2).milliseconds(); //2
(2).days(); //172800000
(2).months(); //5259600000
(2).daysBefore(Date.create(2012, 0, 5)); //3. Januar 2012
(2).monthsAfter(Date.create(&quot;September 2012&quot;)); //1. November 2012</pre><p></p>
<h5>Fazit</h5>
<p>Date bietet nur minimale Funktionen um mit Daten und Zeiten zu arbeiten. XDate ist vom Funktionsumfang gesehen die kleinste der drei hier vorgestellten Libraries. Wenn in einem Projekt Datumsformatierungen vorgenommen werden, Datumsarithmetik oder Differenzen berechnet werden müssen ist XDate aber eine gute Wahl, die mit einem Overhead von 2.9 kB nicht gross ins Gewicht fällt. Moment.js kennt ein paar Tricks mehr, wie das Parsen von Daten und die relativen Daten (10 minutes ago), und ist mit 3.3 kB nicht viel grösser als XDate.<br />
Sugar ist dann eine gute Wahl wenn man nicht nur die Date Funktionen sondern auch die Erweiterungen der anderen nativen Objekte (String, Number,Array, Objekt, Function, RegExp) benutzen möchte. Alternativ kann aber auch das Sugar Javscript File eingebunden werden das nur die Datumsfunktionen beinhaltet.</p>
<p>Es braucht aber nicht immer eine zusätzliche Datum/Zeit Library. Oft genügt das native Date Objekt in anderen Fällen können die Datumsberechnungen auf dem Server durchgeführt werden und der Client muss die Resultate dann nur anzeigen. Wichtig ist das man die Grösse der Javascript Files im Auge behält. Dies ist dann wichtig wenn Webapplikationen für mobile Geräte entwickelt werden.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1800</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CSS Sprites mit SmartSprites</title>
		<link>http://blog.rasc.ch/?p=1678</link>
		<comments>http://blog.rasc.ch/?p=1678#comments</comments>
		<pubDate>Tue, 06 Mar 2012 14:07:49 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[sprites]]></category>

		<guid isPermaLink="false">http://blog.ralscha.ch/?p=1678</guid>
		<description><![CDATA[CSS Sprites sind eine Möglichkeit um die Ladezeit einer Webseite zu verkürzen. Wenn ein Browser eine Webseite aufruft, dann lädt er zuerst die HTML Seite herunter, analysiert diese und muss dann für jedes referenzierte Bild einen weiteren Request zum Server senden. Ein CSS Sprite ist eine Sammlung von vielen Bildern in einem einzigen Bild. Im [...]]]></description>
			<content:encoded><![CDATA[<p>CSS Sprites sind eine Möglichkeit um die Ladezeit einer Webseite zu verkürzen. Wenn ein Browser eine Webseite aufruft, dann lädt er zuerst die HTML Seite herunter, analysiert diese und muss dann für jedes referenzierte Bild einen weiteren Request zum Server senden.<br />
Ein CSS Sprite ist eine Sammlung von vielen Bildern in einem einzigen Bild. Im CSS wird mit Hilfe des Attributes <em>background-position</em> die Position angegeben in der sich das gewünsche Image im grossen Bild befindet. Der Browser muss, anstatt vieler kleiner Bilder, nur dieses grosse Bild herunterladen. CSS Sprites reduzieren also die Anzahl Requests und verkürzen dadurch die Ladezeit einer Webseite.</p>
<p>Das folgende Beispiel zeigt wie in einer bestehenden Applikation die Icons durch CSS Sprites, mit Hilfe von <a href="http://csssprites.org/">SmartSprites</a>, ersetzt wurden.</p>
<p>Die Applikation verwendet viele kleine Icons für Buttons. Im CSS finden wir folgenden Code:</p>
<p></p><pre class="crayon-plain-tag">.icon-add {
	background-image: url(../images/add.png) !important;  
}

.icon-delete {
	background-image: url(../images/eraser.png) !important;
}

.icon-logging {
	background-image: url(../images/data_scroll.png) !important; 
}</pre><p></p>
<p>Um SmartSprites anzuweisen diese vielen kleinen Bilder in ein Bild zusammenzufügen, müssen spezielle Kommentare eingefügt werden. Das abgeänderte CSS File sieht danach folgendermassen aus:</p>
<p></p><pre class="crayon-plain-tag">/** sprite: sprites; sprite-image: url('../images/sprites.png'); sprite-layout: vertical */

.icon-add {
	background-image: url(../images/add.png) !important;  /** sprite-ref: sprites; */
}

.icon-delete {
	background-image: url(../images/eraser.png) !important; /** sprite-ref: sprites; */
}

.icon-logging {
	background-image: url(../images/data_scroll.png) !important; /** sprite-ref: sprites; */
}</pre><p></p>
<p>Der erste Kommentar (/** sprite:&#8230;) gibt den Namen (sprites), den Pfad für das Masterbild (../images/sprites.png) sowie das Layout (vertical) an. Mit dieser Konfiguration wird ein Masterbild mit Namen sprites.png angelegt und die einzelnen Icons werden darin vertikal abgelegt. Anstatt vertikal können die Bilder auch horizontal angeordnet werden.</p>
<p>Bei jedem Bild wird mit /** sprite-ref: sprites; */ konfiguriert in welches Masterbild dieses Icon eingefügt werden soll.<br />
Damit ist es möglich mehrere Masterbilder anzulegen, zum Beispiel eins für alle PNG und eins für alle GIF. </p>
<p>Nun benötigen wir eine Möglichkeit um den SmartSprites Prozessor zu starten. Man kann SmartSprites von der Kommandozeile starten und für Ant Projekte wird ein entsprechender Task mitgeliefert. Für Maven gibt es kein Plugin, aber mit dem <a href="http://maven.apache.org/plugins/maven-antrun-plugin/">maven-antrun-plugin</a> lässt sich SmartSprites trotzdem relativ einfach integrieren. </p>
<p></p><pre class="crayon-plain-tag">&lt;plugin&gt;
	&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
	&lt;artifactId&gt;maven-antrun-plugin&lt;/artifactId&gt;
	&lt;version&gt;1.7&lt;/version&gt;
	&lt;executions&gt;
		&lt;execution&gt;
			&lt;id&gt;generate-resources&lt;/id&gt;
			&lt;phase&gt;generate-resources&lt;/phase&gt;
			&lt;configuration&gt;
				&lt;target&gt;

					&lt;taskdef resource=&quot;smartsprites.xml&quot;&gt;
						&lt;classpath refid=&quot;maven.plugin.classpath&quot; /&gt;
					&lt;/taskdef&gt;

					&lt;smartsprites rootdir=&quot;${basedir}/src/main/webapp/resources/css&quot; 
								  cssfileencoding=&quot;UTF-8&quot; cssfilesuffix=&quot;-sprite&quot;
								  loglevel=&quot;INFO&quot; spritepngdepth=&quot;AUTO&quot; 
								  spritepngie6=&quot;false&quot; /&gt;


				&lt;/target&gt;
			&lt;/configuration&gt;
			&lt;goals&gt;
				&lt;goal&gt;run&lt;/goal&gt;
			&lt;/goals&gt;
		&lt;/execution&gt;
	&lt;/executions&gt;
	&lt;dependencies&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;com.carrotsearch&lt;/groupId&gt;
			&lt;artifactId&gt;smartsprites&lt;/artifactId&gt;
			&lt;version&gt;0.2.8&lt;/version&gt;
		&lt;/dependency&gt;
	&lt;/dependencies&gt;
&lt;/plugin&gt;</pre><p></p>
<p>Gesteuert wird SmartSprites mit dem &lt;smartsprites&gt; Tag. SmartSprites sucht nach Dateien mit der Endung *.css im angegebenen <em>rootdir</em> Verzeichnis und in allen Unterverzeichnissen. Das Programm überschreibt nicht die Original css Datei sondern erstellt eine Datei mit dem gleichen Namen und dem Suffix das unter <em>cssfilesuffix</em> angegeben ist. Wenn die Original Datei app.css heisst wird das verarbeitete File app-sprite.css heissen und im gleichen Verzeichnis wie das Original abgespeichert. Eine genaue Beschreibung aller Optionen findet man auf der <a href="http://csssprites.org/">Homepage des Projektes</a>.</p>
<p>Im Beispiel ist das Plugin der generate-resources Phase angehängt und kann mit dem Aufruf von <code>mvn generate-resources </code> ausgeführt werden. SmartSprites sucht nach den CSS Files, analysiert die Kommentare und erstellt das Masterbild sowie das neue css File.</p>
<p>Nach dem Ausführen des Programms und wenn keine Fehler aufgetreten ist finden wir im gleichen Verzeichnis wie das Original eine *-sprite.css Datei. Das Masterbild befindet sich im konfigurierten Pfad. In diesem Beispiel unter (./src/main/webapp/resources/images/sprites.png). </p>
<p><a href="http://blog.rasc.ch/wp-content/uploads/2012/03/sprite.png"><img src="http://blog.rasc.ch/wp-content/uploads/2012/03/sprite.png" alt="" title="sprite" width="48" height="153" class="alignnone size-full wp-image-1687" /></a></p>
<p>In der *-sprite.css Datei sehen wir die Änderungen die SmartSprites vorgenommen hat. Alle Kommentare wurden entfernt, background-image referenziert neu das Masterbild und background-position gibt die Position des ursprünglichen Bildes innerhalb des Masterbildes an.</p>
<p></p><pre class="crayon-plain-tag">.icon-add {
  background-image: url('../images/sprites.png') !important;
  background-position: left -0px !important;
}

.icon-delete {
  background-image: url('../images/sprites.png') !important;
  background-position: left -16px !important;
}

.icon-logging {
  background-image: url('../images/sprites.png') !important;
  background-position: left -32px !important;
}</pre><p></p>
<p>Zum Schluss müssen die HTML Seiten angepasst werden, damit sie nicht mehr das Original css sondern das *-sprite.css File referenzieren. </p>
<p>Das hier beschriebene Projekt befindet sich auf Github: <a href="https://github.com/ralscha/changelog">Changelog</a><br />
Dort konnten 32 Bilder in ein Bild zusammengefasst werden. </p>
<p>Weitere Links zu CSS Sprites:<br />
<a href="http://www.w3schools.com/css/css_image_sprites.asp">http://www.w3schools.com/css/css_image_sprites.asp</a><br />
<a href="http://www.tutorial9.net/tutorials/web-tutorials/building-faster-websites-with-css-sprites/">http://www.tutorial9.net/tutorials/web-tutorials/building-faster-websites-with-css-sprites/</a><br />
<a href="http://coding.smashingmagazine.com/2009/04/27/the-mystery-of-css-sprites-techniques-tools-and-tutorials/">http://coding.smashingmagazine.com/2009/04/27/the-mystery-of-css-sprites-techniques-tools-and-tutorials/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1678</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Erste Schritte mit der HTML 5 File API</title>
		<link>http://blog.rasc.ch/?p=1515</link>
		<comments>http://blog.rasc.ch/?p=1515#comments</comments>
		<pubDate>Wed, 01 Feb 2012 04:57:48 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[html5]]></category>

		<guid isPermaLink="false">http://blog.ralscha.ch/?p=1515</guid>
		<description><![CDATA[Das File API ist eine Spezifikation die im Rahmen von HTML 5 entwickelt wird. Sie ermöglicht den Zugriff auf Dateien vom Browser aus mit Javascript ohne das man diese zuerst zum Server senden muss. Damit kann man zum Beispiel Texte direkt im Browser anzeigen oder eine Preview eines Bildes anzeigen bevor man den Upload zum [...]]]></description>
			<content:encoded><![CDATA[<p>Das <a href="http://www.w3.org/TR/file-upload/">File API</a> ist eine Spezifikation die im Rahmen von HTML 5 entwickelt wird. Sie ermöglicht den Zugriff auf Dateien vom Browser aus mit Javascript ohne das man diese zuerst zum Server senden muss. Damit kann man zum Beispiel Texte direkt im Browser anzeigen oder eine Preview eines Bildes anzeigen bevor man den Upload zum Server startet. </p>
<p>Um mit einer Datei zu arbeiten benötigt man als erstes eine Referenz auf ein File. Diese bekommt man entweder von einem file input Tag. </p>
<pre>
&lt;input id="file" type="file" name="file" multiple&gt;
</pre>
<p>Im Javascript greift man auf das input Element zu und bekommt mit .files ein Array aller ausgewählten Dateien zurück. Mit der File Referenz kann dann zum Beispiel die Grösse und der Name abgefragt werden.</p>
<p></p><pre class="crayon-plain-tag">var myFiles = document.getElementById('file').files;
for (var i = 0; i &lt; myFiles.length; i++) {  
  console.log(myFiles[i].name);
  console.log(myFiles[i].size);
}</pre><p></p>
<p>Die zweite Möglichkeit an eine Filereferenz zu gelangen ist via Drag and Drop. Eine Beschreibung wie das funktioniert findet man auf der HTML5 Rocks Seite: <a href="http://www.html5rocks.com/en/tutorials/file/dndfiles/">http://www.html5rocks.com/en/tutorials/file/dndfiles/</a></p>
<p>Mit der Filereferenz kann nun der Inhalt der Datei eingelesen werden. Dazu benötigt man das Objekt FileReader. FileReader stellt 4 Methoden für das Einlesen zur Verfügung. readAsBinaryString, readAsText, readAsDataURL und reasAsArrayBuffer.</p>
<p>Wie so vieles in Javascript geschieht auch das Einlesen eines Files asynchron. Das heisst man muss einen Eventlistener registrieren damit das Programm informiert wird sobald das Einlesen beendet ist.</p>
<p>Die onload Callback Function wird aufgerufen sobald das File vollständig eingelesen wurden. Das Event enthält im e.target.result den Inhalt der Datei. Das folgende Beispiel zeigt den Dateiinhalt auf der Webseite an.</p>
<p></p><pre class="crayon-plain-tag">var reader = new FileReader();
  reader.onload = function(e) {					
    var pre = document.createElement('pre');
    pre.innerHTML = e.target.result;
    document.getElementById('out').insertBefore(pre, null);
  }
  reader.readAsText(myFiles[i]);</pre><p></p>
<p>Weitere FileReader Events sind:</p>
<ul>
<li>loadstart: Wenn das Einlesen startet</li>
<li>progress: Während des Einlesens. Mit event.loaded und event.total kann der Fortschritt berechnet werden</li>
<li>abort: Wenn das Einlesen mit der Methode FileReader.abort() abgebrochen wurde</li>
<li>error: Wenn ein Fehler beim Lesen der Datei auftaucht</li>
<li>load: Wenn das Einlesen erfolgreich beendet wurde</li>
<li>loadend: Wenn das Einlesen beendet wurde. Egal ob erfolgreich oder mit einem Fehler</li>
</ul>
<p>Sorucecode auf Github: <a href="https://github.com/ralscha/playground/tree/master/upload">https://github.com/ralscha/playground/tree/master/upload</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1515</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fileupload mit Servlet 3.0 und Spring</title>
		<link>http://blog.rasc.ch/?p=1504</link>
		<comments>http://blog.rasc.ch/?p=1504#comments</comments>
		<pubDate>Tue, 31 Jan 2012 13:17:55 +0000</pubDate>
		<dc:creator>Ralph</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://blog.ralscha.ch/?p=1504</guid>
		<description><![CDATA[Mit Servlet 3.0 wurde die Unterstützung für Multipart Request eingeführt. Damit ist es möglich Upload Funktionalität in eine Webapplikation einzubauen ohne das eine zusätzliche Library benötigt wird (wie z.B. commons-fileupload). Tomcat ab Version 7 und Jetty ab Version 8 haben Unterstützung für Servlet 3.0 eingebaut und können für folgende Tests eingesetzt werden. Auf der Seite [...]]]></description>
			<content:encoded><![CDATA[<p>Mit <a href="http://jcp.org/en/jsr/detail?id=315">Servlet 3.0</a> wurde die Unterstützung für Multipart Request eingeführt. Damit ist es möglich Upload Funktionalität in eine Webapplikation einzubauen ohne das eine zusätzliche Library benötigt wird (wie z.B. <a href="http://commons.apache.org/fileupload/">commons-fileupload</a>).</p>
<p><a href="http://tomcat.apache.org/">Tomcat</a> ab Version 7 und <a href="http://www.eclipse.org/jetty/">Jetty</a> ab Version 8 haben Unterstützung für Servlet 3.0 eingebaut und können für folgende Tests eingesetzt werden. </p>
<p>Auf der Seite des Servers müssen wir nun zuerst die Multipart Verarbeitung einschalten. Dies geschieht entweder im File web.xml indem man in der Servletkonfiguration einen &lt;multipart-config/&gt; Tag hinzufügt. Alternativ können die Servlets mit der Annotation <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/annotation/MultipartConfig.html">MultipartConfig</a> gekennzeichnet werden. Da in Spring MVC ein <a href="http://www.ralscha.ch/spring/org/springframework/web/servlet/DispatcherServlet.html">DispatcherServlet</a> als Frontcontroller eingesetzt wird fügen wir die Konfiguration in der Datei web.xml ein. </p>
<p></p><pre class="crayon-plain-tag">&lt;servlet&gt;
  &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
  &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
  &lt;init-param&gt;
    &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
    &lt;param-value&gt;&lt;/param-value&gt;
  &lt;/init-param&gt;
  &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
  &lt;multipart-config/&gt;
&lt;/servlet&gt;</pre><p></p>
<p>Das Hinzufügen des Tags &lt;multipart-config/&gt; genügt damit dass das Servlet Multipart Requests verarbeiten kann. In Jetty 8.1 ist die Verarbeitung auch ohne diese Zeile eingeschaltet. Für den Tomcat Server dagegen muss der Tag vorhanden sein. </p>
<p>Die Multipart Verarbeitung kann mit folgenden Optionen zusätzlich konfiguriert werden.</p>
<p></p><pre class="crayon-plain-tag">&lt;multipart-config&gt;
    &lt;file-size-threshold&gt;....&lt;/file-size-threshold&gt;
    &lt;location&gt;&lt;..../location&gt;
    &lt;max-file-size&gt;....&lt;/max-file-size&gt;
    &lt;max-request-size&gt;....&lt;/max-request-size&gt;
  &lt;/multipart-config&gt;</pre><p></p>
<ul>
<li><strong>fileSizeThreshold</strong>: Gibt an nach wievielen Bytes die Datei temporär auf Disk gespeichert wird. Damit soll verhindert werden das grosse Dateiuploads den Speicher zum Überlaufen bringen.</li>
<li><strong>location</strong>: ist ein absoluter Pfad der ein Verzeichnis im Filesystem angibt in dem die Dateien temporär zwischengespeichert werden sobald der fileSizeThreshold erreicht wird. </li>
<li><strong>maxFileSize</strong>: gibt an wie gross ein Upload in Bytes sein darf. Wenn der Upload grösser ist wirft der Container eine Exception.</li>
<li><strong>maxRequestSize</strong>: gibt die maximale Grösse in Bytes an die ein kompletter Request haben darf. Dies ist das Total aller Parts in einem Multipart Request. Auch hier wirft der Container eine Exception wenn die Anzahl Bytes überschritten wird.</li>
</ul>
<p>Im form Tag muss wie gewohnt der enctype auf multipart/form-data gesetzt sein. Zusätzlich wird ein file input Tag benötigt. </p>
<p></p><pre class="crayon-plain-tag">&lt;form action=&quot;simpleUpload&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&gt;
  &lt;input id=&quot;file&quot; type=&quot;file&quot; name=&quot;file&gt;
  &lt;button type=&quot;submit&quot;&gt;Upload File(s)&lt;/button&gt;
&lt;/form&gt;</pre><p></p>
<p>In der Controller Klasse wird eine Methode eingefügt, die den Post Request verarbeitet. Die Klasse <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/Part.html">Part</a> wurde mit Servlet 3.0 eingeführt und repräsentiert einen Part des Multipart Requests. </p>
<p></p><pre class="crayon-plain-tag">@Controller
public class UploadController {
   	@RequestMapping(value = &quot;/simpleUpload&quot;, method = RequestMethod.POST)
	public String processUpload(HttpServletRequest request,
                                    @RequestParam(&ldquo;file&rdquo;) Part file)  {
...
}</pre><p></p>
<p>Dies funktioniert ohne weitere Konfiguration mit Spring. In der Spring 3.1 Dokumentation wird erwähnt das ein StandardServletMultipartResolver benötigt wird.</p>
<pre>
&lt;bean id="multipartResolver"
class="org.springframework.web.multipart.support.StandardServletMultipartResolver"&gt;
&lt;/bean&gt;
</pre>
<p>Dieser wird allerdings nur dann benötigt wenn als Parameter anstatt <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/Part.html">Part</a> <a href="http://www.ralscha.ch/spring/org/springframework/web/multipart/MultipartFile.html">MultipartFile</a> verwendet werden soll. Allerdings hat der MultipartResolver in der aktuellen Version 3.1 einen Fehler der den Einsatz verhindert (siehe <a href="http://forum.springsource.org/showthread.php?120810-Servlet-3-0-MultipartForm-parameters-missing&#038;highlight=StandardServletMultipartResolver">Forum Post</a>)</p>
<p><strong>Nachtrag 22.02.2012<br />
Der Fehler im MultipartResolver ist nur bemerkbar in Jetty und Resin. Es funktioniert alles ohne Probleme mit Tomcat und Glassfish. Anstatt Part kann man die Spring Klasse MultipartFile als Parameter verwenden.<br />
Jira-Bug: <a href="https://jira.springsource.org/browse/SPR-9149">https://jira.springsource.org/browse/SPR-9149</a></strong></p>
<p>Ein kleines Problem mit der <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/Part.html">Part</a> Klasse ist das es keine eingebaute Methode gibt die den Filenamen zurückgibt. Folgende Methode löst dieses Problem und liest den Dateinamen aus dem Header.</p>
<p><strong>Nachtrag 22.02.2012<br />
Die Klasse MultipartFile enthält die Method getOriginalFilename() die den Filenamen zurückgibt. </strong></p>
<p></p><pre class="crayon-plain-tag">private String getFileName(Part part) {
  String partHeader = part.getHeader(&quot;content-disposition&quot;);

  for (String cd : partHeader.split(&quot;;&quot;)) {
    if (cd.trim().startsWith(&quot;filename&quot;)) {
      return cd.substring(cd.indexOf('=') + 1).trim().replace(&quot;\&quot;&quot;, &quot;&quot;);
    }
  }
  return null;
}</pre><p></p>
<p>Der Input File Tag erlaubt es auch das Attribute multiple anzugeben.</p>
<pre>
&lt;input id="file" type="file" name="file" multiple&gt;
</pre>
<p>Der User kann nun mehrere Dateien auswählen und übermitteln. In dem Fall funktioniert die Methode mit dem Parameter nicht mehr, da alle Dateien den gleichen Partnamen besitzen. Mit der Methode getParts des HttpServletRequest Objekts kann aber auf eine Collection der Parts eines Multipart Requests zugegriffen werden. </p>
<p>Anstatt </p>
<pre>
public String processUpload(HttpServletRequest request,
@RequestParam(“file”) Part file)   {
...
}
</pre>
<p>kann dieser Code verwendet werden um Zugriff auf die Dateien zu erlangen.</p><pre class="crayon-plain-tag">public String processUpload(HttpServletRequest request)   {
  for (Part part : request.getParts()) {
     String fileName = getFileName(part);
     if (fileName != null) {
        //a file
     }
  }
}</pre><p></p>
<p>Beachten muss man hier das ein Part entweder eine Datei oder einen Parameter enthalten kann. Jeder Form Parameter erhält seinen eigenen Part im Request. Mit der Prüfung auf den Filenamen wird unterschieden ob es sich um einen Parameter- oder um einen Datei-Part handelt. </p>
<p><strong>Nachtrag 22.02.2012<br />
Die Übermittlung mehrerer Files funktioniert ohne Probleme mit Tomcat und Glassfish. Dazu muss nur eine Liste als Parameter angeben werden<br />
@RequestParam(value = &#8220;multipleFiles&#8221;, required = false) List&lt;MultipartFile&gt; files)<br />
Siehe Bug <a href="https://jira.springsource.org/browse/SPR-9149">https://jira.springsource.org/browse/SPR-9149</a></strong></p>
<p>Ein weiteres Problem gibt es in Jetty. Gemäss Servlet 3.0 Spezifikaton muss jeder form-data Part ohne Dateiname als Parameter via request.getParameter verfügbar gemacht werden. Leider funktioniert dies im Jetty nicht. Der Tomcat hat damit keine Probleme und liefert die gewünschten Daten zurück wenn man request.getParamter(&quot;&#8230;&quot;) aufruft.</p>
<p>Eine Spring Controller Method die zum Beispiel so aussieht wird also im aktuellen Jetty nicht funktionieren. Spring wirft eine Exception da die Parameter fehlen.</p><pre class="crayon-plain-tag">@RequestMapping(value = &quot;/upload&quot;, method = RequestMethod.POST)
	public void processUpload(HttpServletRequest request, HttpServletResponse response,
			@RequestParam(&quot;chunkNumber&quot;) Integer chunkNumber,
			@RequestParam(&quot;resumableChunkSize&quot;) Long chunkSize) {
}</pre><p></p>
<p>Als Workaround kann die <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#getPart(java.lang.String)">request.getParts(String name)</a> Methode verwendet werden. Diese gibt den Part mit dem angegeben Namen zurück. Mit <a href="http://docs.oracle.com/javaee/6/api/javax/servlet/http/Part.html#getInputStream()">getInputStream()</a> erhält man Zugriff auf den Inhalt des Parts und kann diesen in einen String umwandeln. Das folgende Beispiel verwendet die <a href="http://docs.guava-libraries.googlecode.com/git-history/v11.0.1/javadoc/com/google/common/io/ByteStreams.html">ByteStreams</a> Klasse aus der <a href="http://code.google.com/p/guava-libraries/">Google Guava Library</a>.</p>
<p></p><pre class="crayon-plain-tag">chunkNumber = Integer.valueOf(getPartString(request, &quot;chunkNumber&quot;));
chunkSize = Long.valueOf(getPartString(request, &quot;resumableChunkSize&quot;));

private String getPartString(HttpServletRequest request, String name) throws IOException, ServletException {
		return new String(ByteStreams.toByteArray(request.getPart(name).getInputStream()));
	}</pre><p></p>
<p>Sourcecode auf Github: <a href="https://github.com/ralscha/playground/tree/master/upload">https://github.com/ralscha/spring-playground/tree/master/upload</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.rasc.ch/?feed=rss2&#038;p=1504</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

