Kommentare in IPTables

Ich habe bei einer Maschine IPTables für IPv6 konfiguriert und dabei festgestellt, dass die Rules sehr schnell unübersichtlich werden, gerade wenn man verschiedene Netze in IPTables freischaltet. Bei der Suche nach der besten Dokumentationsmöglichkeit bin ich im Racker Hacker Blog auf den Hinweis gestoßen, dass IPTables Modul “comment” gibt, das einen Kommentar direkt beim erstellen einer Rule setzt. Dieser Kommentar ist dann auch bei iptables -L sichtbar:

Rule erstellen:

ip6tables -I INPUT --src 2001:1620:f77::/48 -i eth0 -j ACCEPT -m comment --comment "Supertux home sixxs net"

Ausgabe ip6tables -n -L

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all      ::/0                 ::/0                state RELATED,ESTABLISHED
ACCEPT     all      ::/0                 ::/0
ACCEPT     icmpv6    ::/0                 ::/0                /* required for ipv6 to work! */
ACCEPT     all      2001:1620:f77::/48   ::/0                state NEW /* Supertux home sixxs net */
ACCEPT     all      20a1:4f8:162:4ff5::/64  ::/0                state NEW /* hetzner vm net */
ACCEPT     all      2001:6f8:900:7ea::2/128  ::/0                state NEW /* notebook sixxs tunnel */
ACCEPT     all      2001:4dd0:ff00:108d::2/128  ::/0                state NEW /* Olymp sixxs tunnel */
ACCEPT     all      2a01:4f8:161:3fff:200::2/128  ::/0                state NEW /* remote coding4coffee */
REJECT     all      ::/0                 ::/0                reject-with icmp6-port-unreachable

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
REJECT     all      ::/0                 ::/0                reject-with icmp6-port-unreachable

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Die Kommentare bleiben nach einem “service ip6tables save” auf einem Centos/RHEL natürlich bestehen. Ein besserer Weg um seine Firewall-Rules zu dokumentieren ist mir bisher noch nicht begegnet.

Synchronized Sets mit Scala

Ein Snippet zum Frühstück:

Bei mir hat sich gerade die Notwendigkeit ergeben, in Scala mit einem mutable HashSet in einem Multithreading-Context zu arbeiten.

Um dieses Threadsafe zu machen kann man das HashSet mit dem Trait SynchronizedSet instanzieren:

val mutableThreadsafeSet = new HashSet[Long] with SynchronizedSet[Long]

Ich liebe diese Sprache <3

Mit Spring den Classpath durchsuchen

Für eine Plugin-Engine musste ich heute den Classpath nach Klassen durchsuchen, die von einer abstrakten Plugin-Klasse erben. Von den gefundenen Klassen sollte aber keine Instanz erzeugt werden, eine Erweiterung des <context:component-scan> kam daher nicht in Frage. Die Lösung für das Problem ist die Klasse ClassPathScanningCandidateComponentProvider:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class PluginRegistry {

    @SuppressWarnings("unchecked")
    public static Set<Class<? extends AbstractPlugin>> getAvailablePlugins() {

        ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(false);
        componentProvider.addIncludeFilter(new AssignableTypeFilter(AbstractPlugin.class));

        Collection beanDefinitions = componentProvider.findCandidateComponents("my.plugins.package");

        Set<Class<? extends AbstractPlugin>> set = new HashSet<Class<? extends AbstractPlugin>>();

        for(BeanDefinition beanDefinition : beanDefinitions){
            try {
                set.add((Class<? extends AbstractPlugin>) Class.forName(beanDefinition.getBeanClassName()));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        return set;
    }

}

Diese Lösung benötigt keinen Spring-Context. Oliver Gierke hat mir den entscheidenen Hinweis auf den ClassPathScanningCandidateComponentProvider gegeben, vielen Dank!

Thread.isInterrupted() gibt immer false zurück

Ich bin beim Implementieren von Lasttests über einen sehr fiesen Java-Bug im Multithreadingbereich gestoßen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Thread t = new Thread(new Runnable(){

    @Override
    public void run() {
        while(Thread.currentThread().isInterrupted()){
            System.out.println("running into take");
            try {
                System.out.println("received: " + blockingQueue.take());
            } catch (InterruptedException e) {
                System.out.println("caught interrupted exception.");
            }
        }
    }

});

t.start();

blockingQueue.add("foo");

t.interrupt();

Bei diesem Code hätte ich erwartet, dass das t.interrupt() dafür sorgt, dass ein blockendes blockingQueue.take() in den catch-Block springt und danach der Thread terminiert, da Thread.currentThread().isInterrupted() true zurückgibt. Bei mir springt, bei installiertem Java 1.6 32 / 64 Bit, der Thread nach dem catch sofort wieder zurück zu blockingQueue.take() - weil Thread.currentThread.isInterrupted() immer false zurückgibt.

Über Stackoverflow bin ich auf folgenden JVM-Bug gestoßen:

http://bugs.sun.com/view_bug.do?bug_id=6772683

Um einen Thread sicher über ein Thread.interrupt() zu beenden und dabei den Bug zu umgehen verwendet man am besten eine Shutdown-Flag:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Thread t = new Thread(new Runnable(){

    private boolean shutdown = false;

    @Override
    public void run() {
        while(!shutdown){
            System.out.println("running into take");
            try {
                System.out.println("received: " + blockingQueue.take());
            } catch (InterruptedException e) {
                System.out.println("caught interrupted exception.");
                shutdown = true;
            }
        }
    }

});

t.start();

blockingQueue.add("foo");

t.interrupt();

Damit wird der Thread sauber beendet. Warum der Bug im aktuellen JDK 1.6 immer noch nicht behoben ist, ist mir ein Rätsel. Wie es mit Java 7 / Windows aussieht konnte ich noch nicht testen.

TinyMCE Mixin in Tapestry 5 - Version 2

In der ersten Version des TinyMCE-Mixins wurde der der Javascript-Code der zum laden benötigt wird noch über den MarkupWriter in der @BeginRender-Methode in den Code geschrieben. Tapestry 5 stellt für das Ausführen von Javascript-Code in einer Component den “JavaScriptSupport” (injectbares Interface) zur verfügung. Über diesen Javascript-Support kann man JS-Code in die Seite schreiben der dann an der richtigen Stelle geladen wird. Man braucht so keine <script>-Tags mehr und Tapestry stellt sicher, dass das Javascript an der richtigen Stelle aufgerufen wird.

In der ersten Version wurde auch der gesamte Init-Javascript-Code (Mehrzeiler) in den Markup-Writer geschrieben. Es bietet sich an, diesen Code noch mal durch eine einfache Funktion zu ersetzen, die man in einer externen Javascript-Datei definiert die dann von Tapestry geladen (und komprimiert etc.) werden kann.

JS-Datei:

1
2
3
4
5
6
7
function enableMCEAsMixin(element){
    tinyMCE.init({
        mode : "exact",
        theme_advanced_resizing : true,
        elements: element
    });
}

TinyMCE-Mixin:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package de.metacoder.blog.mixins;

import org.apache.tapestry5.annotations.BeginRender;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.InjectContainer;
import org.apache.tapestry5.corelib.components.TextArea;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;

@Import(library = {
        "context:scripts/tiny_mce/tiny_mce.js",
        "context:scripts/tiny_mce/tiny_mce_mixin_init.js"
        })
public class TinyMCE {

    @InjectContainer
    private TextArea textArea;

    @Environmental
    private JavaScriptSupport javaScriptSupport;

    @BeginRender
    public void enableTinyMCE() {
        javaScriptSupport.addScript("enableMCEAsMixin('%s');", textArea.getClientId());
    }
}