Evaluate structured code in JasperReports
13. Januar 2012
JasperReports is a library which can be used to fill reports from Java applications or just create simple PDFs. It allows you to not only use static output strings but also Groovy expressions. Sadly, this is restricted to simple expressions that result in a value and don’t generate multiple class files at compile time.
For example, you could use the following expression to print different values depending if your document has more or less than 10 pages:
$V{PAGE_COUNT} < 10 ? "foo" : "bar"
But when you have to loop over values you’ll face a problem as you have no possibility to define own methods. Even the usage of closures (Groovy) or anonymous inner classes (Java) is prohibited as Jasper expects every expression to result in one single class file.
Of course you could extend the class path or use Scriptlets for this, but this requires you to ship the compiled class together with the report library.
Using the power of groovy there is a way to work around this: compile your expression at runtime! The following code will calculate the faculty of the number of pages:
new GroovyClassLoader().parseClass('''
def static fac(x) {
def res = 1;
1.upto(x) {
res *= it
}
return res
}
''').fac($V{PAGE_COUNT})
The first line creates a new instance of the GroovyClassLoader, parses the code given in the following multiline string expression and executes the method “fac(x)” defined statically before.
To prove the power of this method the following code will embed a recursive listing of your home directory in your report:
new GroovyClassLoader().parseClass('''
def static list(path, prefix) {
String result = ""
path.listFiles().each() {
result += prefix + it.name + "\\n"
result += list(it, prefix + " ")
}
return result
}
''').list(new File(System.getProperty("user.home")), "")
Remember that you have to double-escape backslashes as the first escape will be handles by the Jasper compiler.
Another possibility (and the reason why I researched at this topic) is that this method allows you to generate images at runtime and use the full power of the JFreeChart library used by Jasper itself.
JTextPane with background color
1. Dezember 2011
JTextPane and his ancestors JEditorPane and JTextComponent won’t respect the color defined with setBackground(Color) since they display a “styled document” and expect the background color to be defined in the content. You’ll always see a white background.
To change the background color (without modifying the content) you have to define attributes for the document:
JTextPane textPane = new JTextPane();
textPane.setContentType("text/html"); // or any other styled content type
textPane.setText("White text on a red background");
textPane.setForeground(Color.white); // Works as expected
textPane.setBackground(Color.red); // Obsolete, no affect
// Define a default background color attribute
Color backgroundColor = Color.red;
SimpleAttributeSet background = new SimpleAttributeSet();
StyleConstants.setBackground(background, backgroundColor);
textPane.getStyledDocument().setParagraphAttributes(0,
textPane.getDocument().getLength(), background, false);
// And remove default (white) margin
textPane.setBorder(BorderFactory.createEmptyBorder());
// Alternative: Leave a 2px border but draw it in the same color
textPane.setBorder(BorderFactory.createLineBorder(backgroundColor, 2));
BTRFS im RAID-1-Modus im praktischen Einsatz
14. November 2011
Soeben habe ich die neuen 2TB-Festplatten in den Media-PC eingebaut und mich dazu entschieden, dieses mal dem neuen Linux-Dateisystem btrfs eine Chance zu geben. Im Gegensatz zum klassischen ext beherscht dieses nämlich von Haus aus RAID-Funktionalitäten (Level 0, 1 und 10) sowie Snapshots. Das RAID im Level 1 schützt vor physikalischen Fehlern, die Snapshots – sofern man sie regelmäßig anlegt – vor logischen, wie einem versehentlichen ‘rm -rf’.
Die Frage ist, wie stabil btrfs inzwischen geworden ist. Da es beinahe das Standardsystem unter Fedora 16 geworden wäre ist meine persönliche Einschätzung: Stabil genug für mich. Der Grund, warum FC16 doch noch ext4 verwendet, ist das fehlende bzw. nicht rechtzeitig fertig gewordene fsck. Mit den git-Quellen jedoch kein Problem, dort findet sich inzwischen ein ‘btrfsck’. Sowieso würde ich für den Einsatz einen aktuellen Kernel (3.x) und die aktuellen Tools aus dem Git-Repository verwenden, siehe https://btrfs.wiki.kernel.org/.
Zuerst müssen die Partitionen im RAID-1-Modus formatiert werden:
$ sudo mkfs.btrfs -L mediafiles -d raid1 -m raid1 /dev/sdd1 /dev/sde1
Im Gegensatz zu einem klassischen mkfs gibt man hier also zwei (bzw. mehr) Devices an. Mit den Parametern -d (–data) und -m (–metadata) wird der jeweilige Speichermodus festgelegt. Standardmäßig spiegelt btrfs bei mehr als einer Partition die Metadaten (raid1) und teilt die Daten auf beide Devices auf (raid0).
Damit btrfs alle zusammengehörigen Partitionen automatisch finden kann, erhalten sie die selbe UUID und unterschiedliche Sub-UUIDs:
$ sudo blkid /dev/sdd1 /dev/sde1 /dev/sdd1: LABEL="mediafiles" UUID="243efbc4-5f72-4352-9160-d693b3ed41b5" UUID_SUB="0a5b948d-9761-4c94-8f85-c9548f1149f2" TYPE="btrfs" /dev/sde1: LABEL="mediafiles" UUID="243efbc4-5f72-4352-9160-d693b3ed41b5" UUID_SUB="66fbc6c1-8295-476a-bdfe-72536f0b50ed" TYPE="btrfs"
Dementsprechend reicht es beim Mounten auch aus, entweder eines der beiden Devices oder die UUID anzugeben. Die folgenden drei Befehle sind also identisch zueinander:
$ mount /dev/sdd1 /mnt $ mount /dev/sde1 /mnt $ mount UUID=243efbc4-5f72-4352-9160-d693b3ed41b5 /mnt
Der Befehl ‘btrfs filesystem show’ zeigt alle erkannten Dateisysteme an:
$ sudo btrfs filesystem show
Label: 'mediafiles' uuid: 243efbc4-5f72-4352-9160-d693b3ed41b5
Total devices 2 FS bytes used 809.82GB
devid 1 size 1.82TB used 817.03GB path /dev/sdd1
devid 2 size 1.82TB used 817.01GB path /dev/sde1
Btrfs v0.19-102-g2482539
Es gibt jedoch eine kleine Stolperfalle. Soll das RAID-1-btrfs beim Booten automatisch eingehängt werden, so *müssen* alle Devices in der /etc/fstab eingetragen werden. Ansonsten meckert das System, da es nicht alle dazugehörigen Devices selbst finden kann, selbst wenn die UUID verwendet wird:
UUID=19aa7588-9694-4440-ae33-e5b8dc4030fa /media/mediafiles btrfs device=/dev/sdd1,device=/dev/sde1 0 0
Gefährlich ist dies vor allem bei Headless-Systemen, da im laufenden Betrieb die automatische Erkennung der Devices durchaus funktioniert und ein Eintrag ohne die ‘device=’-Optionen daher beim Testen durchaus funktionieren würde.
Nicht ganz einfach ist übrigens die Größe bzw. der freie Speicher des RAID-1-Dateisystems zu ermitteln:
$ df -h /media/mediafiles Dateisystem Größe Benut Verf Ben% Eingehängt auf /dev/sdd1 3,7T 1,6T 2,1T 44% /media/mediafiles
‘df’ zählt hier also einfach den gesamten und belegten Speicher aller Einzelpartitionen zusammen. Der Grund hierfür liegt, soweit ich das im Wiki verstanden habe, in einem Berechtigungsproblem: Um das Dateisystem als RAID-1 zu erkennen und die Größe damit korrekt anzugeben müsste df direkt darauf zugreifen, was ihm aber zumindest als normaler User nicht erlaubt ist. btrfs bringt daher sein eigenes ‘df’ mit:
$ sudo btrfs fi df /media/mediafiles Data, RAID1: total=815.00GB, used=808.73GB Data: total=8.00MB, used=0.00 System, RAID1: total=8.00MB, used=120.00KB System: total=4.00MB, used=0.00 Metadata, RAID1: total=2.00GB, used=1.09GB Metadata: total=8.00MB, used=0.00
Das Tool btrfs wird auch verwendet, um weitere Devices zum Raid hinzuzufügen, zu entfernen, Snapshots anzulegen oder das FS zu defragmentieren. Hiermit habe ich bisher aber noch nicht experimentiert, ggf. wird’s einen Nachtrag geben. Erstmal werde ich nun das Verhalten im MythTV-Betrieb beobachten und vor allem auf die – subjektive – Performance im Vergleich zu ext4 achten.
Links:
Java: Model-View-Controller without memory leaks
7. Oktober 2011
When doing MVC programming in Java, there is a problem that most people don’t know about. I’ve ignored it myself much too long. The problem is that when you bind a model class to an UI component you will get a giant memory leak.
What happens?
Well, imagine a model class supporting listening for property changes. A simple example might look like this (I extend from PropertyChangeSupport here so that I don’t have to delegate all the methods, normally you wouldn’t do so, of course):
public class Model extends PropertyChangeSupport {
private String name;
public Model(String name) {
super(new Object()); // Only an example! Don't do this in RL!
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
firePropertyChange("name", this.name, this.name = name);
}
}
Next, imagine a view for this model class. It has an input field that is binded in both direction with the model (very simplified example here, I normally don’t code this way
):
public class ModelView extends JPanel {
public ModelView(final Model model) {
super(new BorderLayout());
add(new JLabel("Name: "), BorderLayout.WEST);
final JTextField textfield = new JTextField(model.getName());
add(textfield, BorderLayout.CENTER);
// Bind textfield => model (harmless)
textfield.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
model.setName(textfield.getText());
}
});
// Bind model => textfield (introduces memory leak)
model.addPropertyChangeListener("name", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
textfield.setText(model.getName());
}
});
}
}
From now on we have a memory leak, because the JPanel, the JLabel and the JTextField (and all other referenced) objects will never be removed by the garbage collector as long as the model exists (which might be until the applications end of life). The reason is that the anonymous inner PropertyChangeListener instance has (and must have!) an implicit reference to the JPanel. And even if you replace it by a static class it does have to know the textfield which is a child object of the panel and has a reference back to it. So even if nobody else references the panel the garbage collector sees:
Model => PropertyChangeListener => JPanel
There is a little known class called WeakReference (and his brother WeakHashMap). It contains an object, but the object could still be removed by the garbage collector as long as there is no other (non-weak) reference to it.
A naive idea is to just encapsulate the PropertyChangeListener within a WeakReference object:
public class WeakListener implements PropertyChangeListener {
private final WeakReference<PropertyChangeListener> listener;
public WeakListener(PropertyChangeListener listener) {
this.listener = new WeakReference<PropertyChangeListener>(listener);
}
public void propertyChange(PropertyChangeEvent e) {
PropertyChangeListener l = this.listener.get();
if (l != null) {
l.propertyChange(e);
}
}
}
Code in ModelView constructor:
// Bind model => textfield (with little memory leak)
model.addPropertyChangeListener("name", new WeakListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
textfield.setText(model.getName());
}
}));
The idea is that you still have this simple and small WeakListener object within your model’s listener list, but the really big part (the original listener, the panel, label, textfield, etc) could be free’d. Sadly, this will not work, because as soon as you gave the anonymous PropertyChangeListener to WeakListener’s constructor nobody else does reference to it, so the garbage collector will remove the object immediately.
The trick is to create a single reference to it which belongs the parent object:
public class ModelView extends JPanel {
private PropertyChangeListener modelTextfieldListener;
public ModelView(final Model model) {
super(new BorderLayout());
add(new JLabel("Name: "), BorderLayout.WEST);
final JTextField textfield = new JTextField(model.getName());
add(textfield, BorderLayout.CENTER);
// Bind textfield => model (harmless)
textfield.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
model.setName(textfield.getText());
}
});
// Bind model => textfield (with little memory leak)
model.addPropertyChangeListener("name", new WeakListener(modelTextfieldListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
textfield.setText(model.getName());
}
}));
}
}
That’s it. To make this easier I’ve created a little support class WeakListenerSupport that’s very helpful if you have to deal with multiple input-property-bindings. Also it tries to remove (”unlink”) itself from the model if the listener doesn’t exist any longer. It even allows to unlink all weak listeners from a single object.
With this class the above example would look like:
public class ModelView extends JPanel {
private final WeakListenerSupport wls = new WeakListenerSupport();
public ModelView(final Model model) {
super(new BorderLayout());
add(new JLabel("Name: "), BorderLayout.WEST);
final JTextField textfield = new JTextField(model.getName());
add(textfield, BorderLayout.CENTER);
// Bind textfield => model (harmless)
textfield.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
model.setName(textfield.getText());
}
});
// Bind model => textfield (without memory leak)
model.addPropertyChangeListener("name", wls.propertyChange(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
textfield.setText(model.getName());
}
}, model));
}
}
A generic meta packaging format for linux distributions?
30. August 2011
I’m doing some end-user support for Linux desktops (family and friends). From a chat with my mother and observation of our trainee I’ve noticed that what’s normal users making the most head pains are the different packaging formats. For example, when you want to download Google Chrome Linux users are confronted with four different options:
- 32-Bit-DEB
- 64-Bit-DEB
- 32-Bit-RPM
- 64-Bit-RPM
Sometimes there are even different .deb’s or .rpm’s for multiple systems (Debian/Ubuntu, Fedora/OpenSuSE/Mandriva, …). And of course there are package managers that have a fundamentally different design philosophy (emerge or ABS).
Even if the requested package could be found in the distributions package repository the very first step for new linux users is: Google the vendors homepage and click “download”. As I don’t think there will ever be a “one and only” package manager for all distributions maybe we should start thinking about some kind of “meta-package-format” (MPF) that’s a simple text file which contains parsable information about plattform specific packages. Some kind of computer readable download page. I think of it as an INI file with various sections and conditions that have to match. The first section that matches all conditions takes it.
A short example how this might look like:
[Ubuntu 11.04/64] vendor=Ubuntu version=11.04 arch=x86_64 package=http://www.example.org/dist/myprogram-x.y.z-ubuntu-x86_64.deb [Ubuntu 11.04/32] vendor=Ubuntu version=11.04 arch=i386|i586|i686 package=http://www.example.org/dist/myprogram-x.y.z-ubuntu-i386.deb [Generic deb/64] format=deb arch=x86_64 package=http://www.example.org/dist/myprogram-x.y.z-x86_64.deb [Generic deb/32] format=deb arch=i386|i586|i686 package=http://www.example.org/dist/myprogram-x.y.z-i386.deb [Fedora] # Can be found in regular repository vendor=Fedora package=myprogramm [Generic rpm/64] format=rpm arch=x86_64 package=http://www.example.org/dist/myprogram-x.y.z-x86_64.rpm [Generic rpm/32] format=rpm arch=i386|i586|i686 package=http://www.example.org/dist/myprogram-x.y.z-i386.rpm [Gentoo] format=ebuild package=http://www.example.org/dist/myprogram-x.y.z.ebuild [Windows/32] vendor=Microsoft os=Windows arch=i386 package=http://www.example.org/dist/myprogram-x.y.z-i386.exe [Windows/64] vendor=Microsoft os=Windows arch=x86_64 package=http://www.example.org/dist/myprogram-x.y.z-x86_64.exe [OS-X] vendor=Apple os=OS X package=http://www.example.org/dist/myprogram-x.y.z.dmg [Fallback] package=http://www.example.org/dist/myprogram-x.y.z.tar.gz
Now all that you have to do is to provide this MFP file for download. The MFP manager will evaluate the conditions, download the sufficient package format and give it to the system dependent package manager.
What do you think about this? Am I reinventing the wheel? Is it just a 15th standard? Or is this the idea that helps end users to get in touch with the various linux distributions out there?
Edit: Inserted examples for other OS
WLAN mit Lenovo U160 unter Linux
15. August 2011
Wie bekannt und auch hier im Blog schon beschrieben funktioniert der Broadcom-WLAN-Chip im Lenvo Ideapad U160 unter Linux nicht. Die Karte wird wahlweise durch Softblock oder die Hardblock behindert.
Durch einen Bugreport-Eintrag von Ross Patterson habe ich die Lösung gefunden, auch wenn es bei mir eine andere Reihenfolge brauchte als bei ihm.
Das Problem ist wohl der acer_wmi-Treiber, der die Steuerung der WLAN-Karte stört, aber offenbar irgendetwas initialisiert, wodurch es nach dem Laden und Entladen des Moduls funktioniert.
Da ich gerade nicht viel Zeit habe hier die Kurzfassung für Fedora 15:
1. Die Pakete “broadcom-wl” und “kmod-wl” installieren.
2. Eine neue Datei unter /etc/modprobe.d/acer_wmi mit folgendem Inhalt anlegen:
blacklist acer_wmi
blacklist brcm80211
install wl /sbin/modprobe --ignore-install wl; /sbin/rfkill unblock all; /sbin/modprobe acer_wmi; /sbin/rmmod acer_wmi; /sbin/rfkill unblock all
Seit dieser Änderung funktioniert es für mich zuverlässig. Es muss tatsächlich zweimal “/sbin/rfkill unblock all” drin stehen, mit nur einem Aufruf klappt es nicht.
Wer seinen WLAN-Chip gegen eine Intel-Karte ausgetauscht hat, der kriegt sie mit der selben Änderung zum Laufen, ersetzt jedoch “wl” durch “iwlagn”.
Die CDU will abschalten. 8 Kraftwerke bleiben vom Netz, und zwischen 2020 und 2022 die anderen 9.
W.T.F.?
Unsere Kanzlerin hat vor, in gerade mal zwei Jahren fast 13 GW an Leistung um Netz zu nehmen. Das heißt doch, dass es nur zwei Möglichkeiten gibt:
1. (falls der Vorang der Erneuerbaren bei der Einspeisung und die Subventionen bleiben)
Wir bauen innerhalb der nächsten Jahre die Stromnetze und die Erneuerbaren massiv aus, nur um dann bis 2020 eine deutliche Überkapazität zu haben. Bleibt der Vorrang der Erneuerbaren bei der Einspeisung, so werden die KKW-Betreiber ihren Strom ins Ausland verkaufen oder aus rein wirtschaftlichen Gründen herunterfahren müssen. Alternativ werden Kohlekraftwerke vorübergehend stillgelegt.
2. (der Vorang entfällt und/oder die Subventionen werden massiv gekürzt)
Innerhalb der nächsten 10 Jahre wird es kaum Investitionen in Solaranlagen, Windparks oder das Stromnetz geben, denn der Bedarf ist ja akut nicht vorhanden und niemand will auf einer Anlage sitzen bleiben, deren Kosten er vorerst nicht reinbekommt, evtl. sogar niemals. Auch der Zwang zum Ausbau des Stromnetzes ist nicht gegeben, erst Recht kann es nicht in der Praxis getestet werden. 2019 wird man feststellen, dass sich die Situation gegenüber 2011 kaum verändert hat und man – wohl oder übel – die KKW laufen lassen muss.
So, welche dieser Varianten ist die Wahrscheinlichere?
Atomausstieg ja, so schnell wie möglich, aber nicht so.
Ich verweise auch nochmal auf meine politische Prophezeiung für 2011
“Gefällt mir”-Button mit Opera blockieren
20. Mai 2011
Viele haben vernünftigerweise gar keinen Facebook-Account, aber die, die sich doch angemeldet haben, werden nach dem Login für Facebook furchtbar transparent – dank des “Gefällt mir” / “Like”-Buttons. Dieser stammt im normalfall direkt vom Facebook-Server und beinhaltet auch die URL der aufgerufenen Seite:
<iframe
src="http://www.facebook.com/plugins/like.php?
href=http://www.blogs.uni-osnabrueck.de/rotapken/&[...]"
scrolling="no"
frameborder="0"
style="border:none; overflow:hidden; width:450px; height:35px;"
allowTransparency="true"></iframe>
Dieser Dienst, der viele wohl so gut kennt wie niemand sonst, erhält auf diese Weise also auch noch ein fast flächendeckendes Bewegungsprofil im normalen Netz – Nachtrag: selbst wenn man den Button nicht anklickt!. Vorratsdatenspeicherung ist nichts dagegen
. Wer kein Interesse an Facebook hat, kann das einfach durch einen Eintrag in die hosts-Datei des Systems blockieren:
127.0.0.101 facebook.com www.facebook.com
Leider wird dadurch Facebook generell unbenutzbar. Wer dort also doch in und wieder mal reinschauen möchte, der kommt um eine Alternative nicht herum. Opera bietet hierzu von Haus aus die Datei urlfilter.ini an. Den genauen Pfad der Datei bekommt man durch den Aufruf der Seite “opera:config#urlfilter” (Wordpress macht den Link leider kaputt) heraus, auf Unix-Systemen ist es $HOME/.opera/urlfilter.ini. Dort kann man sehr fein gesteuert die erlaubten und verbotenen Seiten festlegen:
Opera Preferences version 2.1 ; Do not edit this file while Opera is running ; This file is stored in UTF-8 encoding [prefs] prioritize excludelist=1 [include] * [exclude] *://*.facebook.com/plugins/like.php* *://*.facebook.com/plugins/likebox.php* *://*.facebook.com/plugins/*
Die Änderungen werden nach einem Neustart von Opera wirksam, der Gefällt-Mir-Button sollte dann von allen Seiten verschwunden sein. Wenn man auch gleich den ein oder anderen Werbedienst blockieren möchte, kombiniert man dies einfach mit bestehenden Filterlisten, etwa von urlfilter.de.
Nachtrag: Da es offenbar auch noch weitere Facebook-Anwendungen gibt, die in die eigene Seite eingebettet werden können (z.B. Kommentare) habe ich eine dritte exclude-Zeile hinzugefügt, die alle “plugins” blockiert. Der normale Facebook-Betrieb scheint diese nicht zu nutzen.
How to auto-hotplug usb devices to libvirt VMs
11. April 2011
libvirt/kvm allows you to expose any usb device attached to your physical maschine to the guests. Just edit the domain’s XML definition and add the following <hostdev> to the <devices> area:
<domain type='kvm'>
...
<devices>
....
<hostdev mode='subsystem' type='usb'>
<source>
<vendor id='0x03f0'/>
<product id='0x4217'/>
</source>
</hostdev>
</devices>
</domain>
Vendor id and product id can be determined with ‘lsusb’:
$ lsusb ... Bus 002 Device 018: ID 03f0:4217 Hewlett-Packard EWS CM1015 ...
Sadly this only works if the device is attached and enabled when the VM is started. The connection will be lost whenever the device is disabled or removed. But you can re-attach it at runtime. Just put the hostdev-definition into it’s own file:
hostdev-03f0:4217.xml
<hostdev mode='subsystem' type='usb'>
<source>
<vendor id='0x03f0'/>
<product id='0x4217'/>
</source>
</hostdev>
And execute the following command when the device is available again:
virsh attach-device GUEST /path/to/hostdev-03f0:4217.xml
You can use udev to automatically run this command whenever the device is attached:
/etc/udev/rules.d/90-libvirt-usb.rules
ACTION=="add", \
SUBSYSTEM=="usb", \
SYSFS{idVendor}=="03f0", \
SYSFS{idProduct}=="4217", \
RUN+="/usr/bin/virsh attach-device GUEST /path/to/hostdev-03f0:4217.xml"
ACTION=="remove", \
SUBSYSTEM=="usb", \
SYSFS{idVendor}=="03f0", \
SYSFS{idProduct}=="4217", \
RUN+="/usr/bin/virsh detach-device GUEST /path/to/hostdev-03f0:4217.xml"
Today I wrote a patch to Flexbackup 1.2.1 which allows you to define exclude expressions on a per-directory-base (like svn:ignore, cvs_ignore or tar’s –exclude-from). Apply this patch and add the following line to your flexbackup.conf:
$exclude_expr_filename = '.flexbackup_exclude';
This activates an additional routine in the file_list_cmd() method. As soon as the ‘find’ command has enought parameters to iterate through all directory it is used to retrieve a list of ‘.flexbackup_exclude’ files. Each file is read line by line and a regular expression will build and appended to the directory’s name, e.g:
$ cat dummy/.flexbackup_exclude .*\.tmp$ a_very_big_file\.iso
Will result in the expression:
dummy\/((.*\.tmp$)|(a_very_big_file\.iso))
All files matching this expression will be ignored. This is done by piping find’s output through xargs and perl:
find . [conditions...] -print0 | xargs -0 perl -e 'foreach (@ARGV) { print "$_" if ! /dummy\/((.*\.tmp$)|(a_very_big_file\.iso))/ and 1'
If more than one .flexbackup_exclude-file is found more conditions are prepended to the ‘and 1′-dummy-condition. Because every condition is tested (and ignored if compilation failed) it should not be possible to break the backup using these files.
Download: http://dau-sicher.de/stuff/flexbackup-exclude-expressions.patch
PS: Perl sucks