2019-03-23

Zeugenschutzprogramm

Wie nennt man Software zur Steuerung von Automaten, die Kondome herstellen?

2012-04-13

Neulich in der U-Bahn


The dynamic link library MSWSOCK.DLL could not be found in the specified path C:\WINNT\system32 ...
Aha und ich dachte auf den Werbemonitoren in der Berliner U-Bahn läuft noch Windows 95 ;) Wie auch immer. Diese Absturzmeldung gab es nicht das erste mal und spricht nicht gerade für das System und deren Käufer. Aber vielleicht hat die BVG ja garnicht so viel Geld für unnötige Windows-Lizenzen ausgegeben, weshalb das nicht registrierte Windows nun den Dienst einstellt.
Für so eine simple Kiosk-Anwendung braucht man im einfachsten Fall ein absolut abgespecktes Linux und einen von mir aus Java oder Flash oder sonstwas hypertoll Animierfähiges in einem Vollbild-Browser.

Kanban und Kaizen

Folgendes Video zeigt mein Team und beschreibt was Kanban & Kaizen (Signalkarten und Veränderung zum Besseren) für uns gebracht haben:
Kurz (aus meiner Sicht als Entwickler):
Vorteile:
  • Focus. 
  • Messbarkeit. 
  • Kleine Schritte, also kontinuierliche Veränderungen, statt mühsame - oft als künstlich wahrgenommene - Zeremonien.
  • Man muss nichts wirklich neu lernen. Man macht sich nur bewußt was wer wie warum tut.
Nachteile:
  • Keine. Wenn man plötzlich beschließt aufzuhören, hat man trotzdem gewonnen, da man sein Verhalten bereits geändert hat, ohne die Anstrengung zu spüren.

2011-10-15

Dümmster Spam des Tages

Eben fand ich die folgende Mail in den tiefen des Spamordners (natürlich automatisch verklappt):
Guten Tag Bla Fasel (Name von mir geändert ;),

Ihre 150,00 Euro können morgen überwiesen werden.

Folgende Daten werden noch benötigt:

- Vorname
- Nachname

Bitte besuchen Sie meine Internetseite, um das Geld zu erhalten. Weitere Daten werden nicht benötigt.

Klicken Sie hier:
http://<>

Mir freudlichen Grüssen,

Moritz Ahlborg
Anmerkung: Es stand mein Vorname und mein Nachname hinter "Guten Tag". Ausserdem mache ich hier nicht noch mehr Werbung für die Webseite mit Gedächtnisschwund.

Was soll ich denn jetzt davon halten?
Natürlich ist das Spam und selbverständlich klicke ich nicht auf den Link, um dort etwas anzugeben, was der Spammer bereits kennt!
Der Typ soll mir doch einfach all sein Geld überweisen (oder den Koffer mit Bargeld vor die Tür stellen), schliesslich werden ja keine weiteren Angaben benötigt.
Wie bescheuert sind die Leute, die Leute für so bescheuert halten?
Immerhin haben die Spammer inzwischen deutsch gelernt. Aber entweder es wird hier auf Menschen gesetzt, die Ihre Mails nicht lesen und alles klicken, was nicht bei drei auf den Bäumen ist oder dieser Spammer ist eine wildgewordene KI, die (noch) nicht weiß, wie Menschen funktionieren.
Fazit:
So werde ich meine Stupidophobie (Angst vor Dummheit) jedenfalls nicht bekämpfen :p

2011-04-29

Bis zum Hals in Arbeit

Als ich neulich den Ausspruch eines Teamleiters hörte, daß das Team bis zum Hals in Arbeit stecke, mußte ich sofort an das untige Bild denken:

Tja diese kreativen Workaholics ...
Nachtrag: Nach meinem letzten Eintrag war auch ich länger als gewollt in der Firma (Ausnahmen bestätigen die Regel)

2011-04-14

Nabelschau im Software-Team

A: Ich war heute schon um 7:22 im Büro ...
B: Ich war Samstag im Büro ...
C: Ich war Sonntag um 7:00 im Büro und jetzt Du ...
D: NULL Pointer Exception!

Man muß nicht jeden Mist mitmachen und man ist kein toller Hecht, wenn man nicht weiß, wann man aufhören muß.
Nochwas: Afterwork habe ich Freizeit

2010-08-22

Falcon-X RC Modell Hubschrauber / Helikopter

Im Nobelkaufhaus Harrods gibt es ja diverse abgefahrene Dinge, aber das bemerkenswerteste für mich war die Tatsache, daß in der Spielzeug-Abteilung diverse Spielzeuge vorgeführt wurden. Der Hinweis über dem Durchgang, der einen (natürlich auf englisch) auf Ufos in Kopfhöhe warnte, war durchaus ernst gemeint! In Punkto Sicherheitshinweisen wird man übrigens in der ganzen Stadt überhäuft. Die "Look left" / "Look right"-Hinweise an Kreuzungen und "Take all your personal belongings with you"-Hinweise in den Bahnen haben wohl schon so manchem Touristen das Leben und den Schirm gerettet.

Ich durfte mir in meinem London-Kurzurlaub einen lang gehegten Wunsch erfüllen: Einen Modell-Hubschrauber! Hier gibt es einen Erfahrungsbericht, der ganz gut beschreibt, was sich jetzt in meinem Wohnzimmer bewegt.

Der Heli fliegt wirklich beeindruckend konstant, solange kein Windchen weht. Ein schnell aus dem Weg flitzendes Kind bringt den Piloten allerdings schon ganz schön in Bedrängnis. Ein offenes Fenster ist ein absolutes No-Go. Nach weniger als 5 Flugphasen (zu gefühlten 5 Minuten) kann man bereits die ersten Ziellandungen wagen. Ein Flug durch den Flur ins Nebenzimmer und zurück war bisher mein schwierigstes, gelungenes Manöver.
+ Aufladen via USB am PC dauert ca 20 Minuten (ginge aber auch über die Fernbedienung, dann zu Lasten der dortigen Akkus/Batterien).
+ Sehr stabiler Flug (dank Gyroskop)
+ Für Einsteiger geeignet
+ hoher Spaßfaktor
+ geringer Preis (ca 25-30 Euro)*
+ gute Verarbeitung (verschraubtes Alugehäuse)
- kurze Flugzeit
- sehr Windempfindlich (reines Indoor-Vergnügen)

*) Natürlich kostet es im Londoner Kaufhaus deutlich mehr, aber die dortige Flugshow dirket zwischen den staunenden Kunden hindurch ist in jedem Falle sehenswert.

2010-05-20

Stilblüten und Codeleichen

  • Aus der Rubrik "Neulich im Quelltext":
  • PROCEDURE displayData(parameter1, parameter2)
    BEGIN
    IF parameter1 is not null OR 1=1 THEN --just for testing
    ...a huge block of code to display the data...
    END IF;
    END;
    Kein ELSE-Teil und seit langer Zeit unverändert im Repository

  • Querdenker der Woche:
  • -- zu ratendes Objekt
    v_objectId := getCustomerObject();
    Es ging übrigens ums Rating (also: Beurteilung der Bonität) nicht ums Raten (im Sinne von Rätselraten)

  • Querschläger der Woche:
  • v_objectId := nimmIrgendeinObjektAusDerListe(liste);
    Wie jetzt irgendein!?
    Das Erste/Letzte würde zumindest verhersagbare Ergebnisse liefern.
    So weiß man zwar, daß man eine Objekt-ID bekommt, aber es könnte auch bei unveränderter Liste jedesmal eine andere sein.

  • Daily Business:
  • BEGIN
    WHILE fehlerVorhanden() LOOP
    behebeFehler();
    EXIT WHEN schnauzeVoll();
    END LOOP;
    END;

    2010-02-23

    Datenverbindungs-Fluchtsymbol

    Mein Zeichen der Woche: Datenverbindungs-Fluchtsymbol

    ASCII-Code: 16
    Kurz: DLE
    Name: Data Link Escape
    Deutsch: Datenverbindungs-Fluchtsymbol
    Bedeutung: Steuerzeichen, das anzeigt, dass eine festgelegte Anzahl an nachfolgenden Zeichen eine andere Bedeutung – z. B. Steuerinformationen – haben. Ähnlich dem Escape (ASCII 27)

    Wenn man also mal wieder nur japanische Kasperzeichen auf dem Bildschirm sieht, dann weiß man: Die Daten sind mal wieder geflüchtet und haben nur Datenverbindungs-Fluchtsymbole hinterlassen.
    Auf so eine abenteuerliche Übersetzung muß man erstmal kommen!

    Etwas historischer Hintergrund findet sich hier:

    16 – DLE – Data link escape
    It is sometimes necessary in an ongoing data communication to send control characters. There are situations where those control characters might be understood as part of the normal data stream. The DLE has been defined in the ASCII standard for these situations. If this character is detected in a datastream, the receiving party knows, that one or more of the following characters must be interpreted in a different way than the other characters in the stream. The exact interpretation of the following characters is not part of the ASCII definition, just the availability to break out of a communication stream with the data link escape. In the Hayes communication protocol for modems, the data link escape has been defined as silence+++silence. In my opinion it would have been a better idea if the Hayes protocol had used the DLE instead, as it does not need to embedded by communication silence, and it would fit within an existing standard. However, the developers of Hayes decided otherwise and now the +++ sequence is used far more often then the original DLE.


    Obiges "to break out of" deutet sehr gut an wie "escape" hier zu lesen ist: "ausbrechen" oder "aussteigen".
    Datenverbindungs-Ausbruchssymbol oder Datenverbindungs-Ausstiegssymbol wären aber auch keine besseren Varianten.

    Kleiner Ausblick auf ein weiteres schönes, aber aus meiner Sicht komplett unsinniges, Zeichen: ẞ - Lateinischer Großbuchstabe Eszett

    2009-12-22

    Fluchomat

    Neulich hörte ich aus der Ecke unseres Testers so merkwürdige Flüche ...
    Ja, ja, so ein Fluchomat ist schon eine tolle Sache.
    Tip: Koordinate [4,3] ist mein Favorit

    Nachtrag: Zum Schluß hörte ich dann aber doch noch den unten rechts ;)

    2009-11-22

    Lüsterleise PCs

    Wenn der PC leise flüsternd
    Unter dem Schreibtisch hockt
    Der Spieler durch sein Fleise lüsternd
    Die Nacht durchzockt

    Wenn der Spieler lüsternd leiser
    Unter den Schreibtisch kriecht
    Der PC vom Flüstern heiser
    Die Nacht im Standby siecht

    Dann nennt man das Lüster Leise
    Oder heise?


    Schöner Freud'scher Verschreiber (gesehen am 2009-11-22 auf www.heise.de).

    2009-10-22

    Ausdruck ohne Wert

    Das folgende ist meine Messagebox des Monats:

    Woher Access wohl weiß, daß meine Eingabe einfach wertlos ist?
    Ob das ein Versuch ist, Datenmüll vorzubeugen?
    Darf ich keine Ausdrücke wie Affenarbeit, Hohldreher oder Plinse eingeben?

    2009-06-16

    EJB-Konfiguration auf glassfish manipulieren ohne Reboot mittels MBeans

    Hintergrund: Nachdem ein EJB (Web-)Service auf dem Application Server (glassfish) deployed wurde, soll die Konfiguration geändert werden ohne den Service neu zu deployen oder gar den Server neu starten zu müssen.

    Daher scheidet ein config.xml im jar-File des Service aus. Ebenso wie die irreführend als dynamisch benannten Server-Properties (hier ist vor dem Wirksamwerden immer ein kompletter Serverneustart nötig)

    Lösung: Custom MBeans

    Und so kann es gehen (schöner geht immer):
    * Ein Interface ConfigMBean
    * Eine abstrakte Klasse Config
    * Zwei Implementationen Development und Production
    * Einen ConfigReader (der nur mit Config hantiert)
    * Ein EJB namens DemoBusiness (der via ConfigReader auf ein MBean zugreift)

    Als Schmankerl cached der ConfigReader und alle ConfigMBean Implementierungen [Development und Production] besitzen eine hardverdrahtete DefaultConfig. Somit funktioniert dieser auch, wenn gerade kein MBean registriert/deployed ist.

    Der ConfigReader registriert sich beim Config(MBean), um über Änderungen von Attributen benachrichtigt zu werden. Der Einfachheit halber wird dann immer die gesamte Config (Cache) ungültig und beim nächsten getConfig erneuert.

    Zusätzlich registriert sich der ConfigReader noch beim Application Server direkt als Listener für unregister-Nachrichten, damit bei unregister/undeploy ebenfalls die Config ungültig wird.

    Wichtig: Am Ende (der Benutzung) muß man sich als Listener mittels releaseConfigListeners wieder deregistrieren (z.B. in ejbRemove oder einem finally-Block).

    * EJB normal deployen
    * Alle class-Files aus de.isolvedit.config.category nach domain-dir/applications/mbeans kopieren
    * folgendes Kommando (zu beachten: Nur via asadmin oder glassfish-GUI gesetzte Attribute werden gespeichert - bleiben also auch nach einem Serverneustart erhalten)
    asadmin create-mbean --user adminuser --name de.isolvedit.config.category.Development de.isolvedit.config.category.Development --attributes SalesOrganisation=1100:DistributionChannel=10: Category=10:ShipCondition=ST:ChangeUser=unknown:Unit=ST: OrderTypeReturnFlag=ZRE: PositionTypeBuy=?:PositionTypeRent=!
    Anmerkung: attr=value:attr=value ohne Leerzeichen(!)

    So sieht das dann auf dem glassfish aus:


    Hier schonmal die Ausgabe im Logfile:
    [DemoBusiness.doSomething()] : start
    [ConfigReader.connectConfigListener()] : add to notification listeners...
    [ConfigReader.connectConfigListener()] : ...done:
    [ConfigReader.getConfig()] : MBean from server
    [ConfigReader.getConfig()] : MBean name: user:impl-class-name=de.isolvedit.config.category.Development, name=de.isolvedit.config.category.Development, server=server
    [ConfigReader.getConfig()] : unit=ST
    [ConfigReader.getConfig()] : shipCondition=ST
    [ConfigReader.getConfig()] : positionTypeRent=FASEL
    [ConfigReader.getConfig()] : category=10
    [ConfigReader.getConfig()] : distributionChannel=10
    [ConfigReader.getConfig()] : positionTypeBuy=BLA
    [ConfigReader.getConfig()] : orderTypeReturnFlag=ZRE
    [ConfigReader.getConfig()] : changeUser=unknown
    [ConfigReader.getConfig()] : salesOrganisation=1100
    [ConfigReader.handleNotification()] : notification message: config changed sequence: 10



    Config

    package de.isolvedit.config.category;

    public interface ConfigMBean {
    public String getSalesOrganisation();
    public void setSalesOrganisation(String salesOrganisation);
    public String getDistributionChannel();
    public void setDistributionChannel(String distributionChannel);
    public String getCategory();
    public void setCategory(String category);
    public String getShipCondition();
    public void setShipCondition(String shipCondition);
    public String getChangeUser();
    public void setChangeUser(String changeUser);
    public String getUnit();
    public void setUnit(String unit);
    public String getOrderTypeReturnFlag();
    public void setOrderTypeReturnFlag(String orderTypeReturnFlag);
    public String getPositionTypeBuy();
    public void setPositionTypeBuy(String positionTypeBuy);
    public String getPositionTypeRent();
    public void setPositionTypeRent(String positionTypeRent);
    }



    ConfigBean

    package de.isolvedit.config.category;

    import javax.management.AttributeChangeNotification;
    import javax.management.Notification;
    import javax.management.NotificationBroadcasterSupport;

    public abstract class Config extends NotificationBroadcasterSupport implements ConfigMBean {

    public static final String CONFIG_CHANGED = "config changed";

    // to set attributes use asadmin or glassfish-GUI !!
    // the following properties are set to null, if deployed via glassfish!
    // further details: http://docs.sun.com/app/docs/doc/820-4336/gbdzi?a=view

    protected String category;
    protected String changeUser;
    protected String distributionChannel;
    protected String orderTypeReturnFlag;
    protected String positionTypeBuy;
    protected String positionTypeRent;
    protected String salesOrganisation;
    protected String shipCondition;
    protected String unit;

    private long sequenceNumber = 1L;

    // there is no abstract static -> so this is the method to override in subclasses!
    public static Config DefaultConfig() {
    return null;
    };

    public synchronized void configChanged() {
    Notification n = new AttributeChangeNotification(this, sequenceNumber++, System.currentTimeMillis(),
    CONFIG_CHANGED, "*", "String", null, null);
    sendNotification(n);
    }

    public String getSalesOrganisation() {
    return salesOrganisation;
    }
    public void setSalesOrganisation(String salesOrganisation) {
    this.salesOrganisation = salesOrganisation;
    configChanged();
    }
    public String getDistributionChannel() {
    return distributionChannel;
    }
    public void setDistributionChannel(String distributionChannel) {
    this.distributionChannel = distributionChannel;
    configChanged();
    }
    public String getCategory() {
    return category;
    }
    public void setCategory(String category) {
    this.category = category;
    configChanged();
    }
    public String getShipCondition() {
    return shipCondition;
    }
    public void setShipCondition(String shipCondition) {
    this.shipCondition = shipCondition;
    configChanged();
    }
    public String getChangeUser() {
    return changeUser;
    }
    public void setChangeUser(String changeUser) {
    this.changeUser = changeUser;
    configChanged();
    }
    public String getUnit() {
    return unit;
    }
    public void setUnit(String unit) {
    this.unit = unit;
    configChanged();
    }
    public String getOrderTypeReturnFlag() {
    return orderTypeReturnFlag;
    }
    public void setOrderTypeReturnFlag(String orderTypeReturnFlag) {
    this.orderTypeReturnFlag = orderTypeReturnFlag;
    configChanged();
    }
    public String getPositionTypeBuy() {
    return positionTypeBuy;
    }
    public void setPositionTypeBuy(String positionTypeBuy) {
    this.positionTypeBuy = positionTypeBuy;
    configChanged();
    }
    public String getPositionTypeRent() {
    return positionTypeRent;
    }
    public void setPositionTypeRent(String positionTypeRent) {
    this.positionTypeRent = positionTypeRent;
    configChanged();
    }
    }



    Development

    package de.isolvedit.config.category;

    public class Development extends Config {

    public static Development DefaultConfig() {
    Development config = new Development();
    config.setSalesOrganisation("1100");
    config.setDistributionChannel("10");
    config.setCategory("10");
    config.setShipCondition("ST");
    config.setChangeUser("unknown");
    config.setUnit("ST");
    config.setOrderTypeReturnFlag("ZRE");
    config.setPositionTypeBuy("?!?");
    config.setPositionTypeRent("!??");

    return config;
    }
    }



    Production

    package de.isolvedit.config.category;

    public class Production extends Config {

    public static Production DefaultConfig() {
    Production config = new Production();
    config.setSalesOrganisation("1100");
    config.setDistributionChannel("10");
    config.setCategory("10");
    config.setShipCondition("ST");
    config.setChangeUser("uwEE");
    config.setUnit("ST");
    config.setOrderTypeReturnFlag("ZRE");
    config.setPositionTypeBuy("BUY");
    config.setPositionTypeRent("RNT");

    return config;
    }
    }



    ConfigReader

    package de.isolvedit.config;

    import java.util.Map;

    import javax.management.AttributeChangeNotification;
    import javax.management.MBeanServerConnection;
    import javax.management.Notification;
    import javax.management.NotificationListener;
    import javax.management.ObjectName;

    import org.apache.commons.beanutils.BeanUtils;
    import org.apache.log4j.ConsoleAppender;
    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.apache.log4j.PatternLayout;

    import com.sun.appserv.management.base.Util;
    import com.sun.enterprise.admin.server.core.jmx.AppServerMBeanServerFactory;

    import de.isolvedit.config.category.Config;

    public class ConfigReader implements NotificationListener {
    public final static String MBEAN_SERVER_DELEGATE = "JMImplementation:type=MBeanServerDelegate";
    public final static String MBEAN_UNREGISTERED = "JMX.mbean.unregistered";

    /**
    * static log4j-logger
    */
    private static final Logger LOGGER = Logger.getLogger(ConfigReader.class);

    private MBeanServerConnection server = null;
    private Config configCache = null;
    private boolean useCachedConfig = false; // force update
    private boolean connectedToServerAsListener = false;
    private ObjectName configObjectName = null;

    public ConfigReader(Config defaultConfig) {
    this.configCache = defaultConfig;
    this.configObjectName = getObjectName();
    // connect to glassfish
    server = AppServerMBeanServerFactory.getMBeanServerInstance();
    }

    // for testing purposes only!
    public ConfigReader(Config defaultConfig, MBeanServerConnection server) {
    this.configCache = defaultConfig;
    this.configObjectName = getObjectName();
    this.server = server;
    LOGGER.addAppender(new ConsoleAppender(new PatternLayout()));
    LOGGER.setLevel(Level.ALL);
    }

    // react on config changes and mbean unregister events
    // if attributes changed invalidate cached config (force update on next getConfig call)
    // if config mbean is unregistered invalidate listenmode (force reconnect on next getConfig call)
    public synchronized void handleNotification(Notification notification, Object handback) {
    try {
    if (notification instanceof AttributeChangeNotification) {
    LOGGER.info("notification message: " + notification.getMessage() + " sequence: "
    + notification.getSequenceNumber());
    if (Config.CONFIG_CHANGED.equals(notification.getMessage())) {
    useCachedConfig = false; // force update
    }
    } else if (MBEAN_SERVER_DELEGATE.equals(notification.getSource().toString())
    && MBEAN_UNREGISTERED.equals(notification.getType()) && !server.isRegistered(configObjectName)) {
    releaseConfigListener();
    }
    } catch (Exception e) {
    LOGGER.error("caught exception", e);
    }
    }

    // return config
    // try to connect config mbean and register as attribute change and unregister listener
    // try to read from config mbean else use default/cached version
    public Config getConfig(boolean cachedVersion) {
    connectConfigListener();
    if (cachedVersion || useCachedConfig) {
    LOGGER.info("MBean from cache");
    } else {
    LOGGER.info("MBean from server");
    try {
    LOGGER.info("MBean name: " + configObjectName);

    @SuppressWarnings("unchecked")
    Map properties = BeanUtils.describe(configCache);

    for (String property : properties.keySet()) {
    if (!property.equalsIgnoreCase("Class") && !property.equalsIgnoreCase("NotificationInfo")) {
    Object value = server.getAttribute(configObjectName, initCap(property));
    LOGGER.info(property + "=" + value.toString());
    BeanUtils.setProperty(configCache, property, value);
    }
    }

    useCachedConfig = true;

    } catch (Exception e) {
    LOGGER.error("caught exception", e);
    useCachedConfig = false;
    }
    }
    return configCache;
    }

    public boolean connectConfigListener() {
    boolean result = false;
    if (!connectedToServerAsListener) {
    LOGGER.info("add to notification listeners...");
    try {
    server.addNotificationListener(configObjectName, this, null, null);
    server.addNotificationListener(getMBeanServerDelegateObjectName(), this, null, null);
    connectedToServerAsListener = true;
    useCachedConfig = false; // force update
    LOGGER.info("...done: ");
    result = true;
    } catch (Exception e) {
    LOGGER.warn("...failed: " + e.getMessage());
    e.printStackTrace();
    result = false;
    }
    } else {
    result = true;
    }
    return result;
    }

    public boolean releaseConfigListener() {
    boolean result = false;
    if (connectedToServerAsListener) {
    try {
    LOGGER.info("remove from notification listeners...");
    if (server.isRegistered(configObjectName)) {
    server.removeNotificationListener(configObjectName, this);
    }
    server.removeNotificationListener(getMBeanServerDelegateObjectName(), this);
    LOGGER.info("...done");
    result = true;
    } catch (Exception e) {
    LOGGER.error("...fail", e);
    result = false;
    }
    connectedToServerAsListener = false;
    } else {
    result = true;
    }
    return result;
    }

    public static String initCap(String input) {
    if (input == null || input.isEmpty()) {
    return input;
    }
    return input.substring(0, 1).toUpperCase() + input.substring(1);
    }

    public ObjectName getObjectName() {
    try {
    return new ObjectName("user:impl-class-name=" + configCache.getClass().getName() + ",name="
    + configCache.getClass().getName() + ",server=server");
    } catch (Exception e) {
    return null;
    }
    }

    public static ObjectName getMBeanServerDelegateObjectName() {
    return (Util.newObjectName(MBEAN_SERVER_DELEGATE));
    }
    }



    DemoBusiness

    package de.isolvedit.business;

    import de.isolvedit.config.category.Config;
    import de.isolvedit.config.category.ConfigReader;
    import de.isolvedit.config.category.Development;

    @Stateless
    public class DemoBusiness implements DemoBusinessLocal {

    private static final Logger LOGGER = Logger.getLogger(ConfigReader.class);

    private ConfigReader conf = new ConfigReader(Development.DefaultConfig());
    //private ConfigReader conf = new ConfigReader(Production.DefaultConfig());

    public String doSomething(){
    LOGGER.info("start");
    String result = null;
    try {
    try {
    Config config = conf.getConfig(false);
    result = config.getSalesOrganisation();
    } catch (Exception e) {
    LOGGER.error("caught exception", e);
    }
    } finally {
    conf.releaseConfigListener();
    }

    return result;
    }

    }



    Nachtrag: Spannend wäre sicher auch sich direkt als Listener für Attributänderungen beim Application Server zu registrieren ... Kommentare sind willkommen.
    Nachtrag 2: Obiges funktioniert erst ab glassfish 2.1

    2009-04-27

    The Paradox of Choice - Why More Is Less

    Verdammt guter Vortrag (englisch) zum Thema: Warum viele Optionen zu haben oft weniger Wert ist, als weniger Wahlfreiheit.

    Was Freiheit in diesem Zusammenhang bedeutet wird gleich am Anfang aufbereitet.
    Eine der Aussagen: Wenn Menschen zu viele Möglichkeiten haben, wählen sie lieber keine, als ggf. eine schlechte Variante. Und selbst wenn sie eine bessere gewählt haben, als sie dies aus einer kleineren Menge hätten tun können, fühlen sie sich oft schlechter. Und zwar, weil sie dank erhöhter Auswahl Perfektion erwarten, dies aber nicht "beweisbar" ist, solange sie nicht alle Möglichkeiten getestet haben (was unmöglicher wird, je größer die Vielfalt).
    Dauer: ca 1 Stunde



    Link: http://video.google.com/videoplay?docid=6127548813950043200&hl=de

    Kleiner Nachtrag: Software-Entwickler/Architekten sollten sich von diesen allgemeinen IT unbelasteten Erkenntnissen beeinflussen lassen. Weniger ist oft mehr. Wobei die im letzten Teil angesprochene Verwendung von Agenten durchaus hilfreich sein kann (besonders schön das Beispiel mit den griechischen Restaurants).

    Wieso Entscheider eine maximal Fünfpunkt Präsentation (in 48-Punkt Schrift) der abzuwägenden Risiken haben wollen, wird mir jetzt auch klarer ;)

    2008-10-20

    Server in VMware

    Auf meiner Linux-Maschine läuft Debian Etch und Windows ist in einen virtuellen PC via VMware-Player verbannt. Aus mehreren Gründen läuft die virtuelle Netzwerkkarte im NAT-Modus:
    Der virtuelle Rechner braucht keine eigene IP aus dem lokalen Netz, da er ja nach aussen die IP des Wirtes benutzt. Somit ist der "Rechner" auch nicht von aussen zu erreichen.
    Das war bisher auch so gewollt. Nun will man aber manchmal eben doch einige Dienste von aussen ansprechen können (z.B. um per VNC Hilfe zu bekommen oder den lokalen Apache mit einer Entwicklerversion eines Webservice ansprechbar zu machen)
    Dazu muß man entsprechende Einträge in der /etc/vmware/vmnet8/nat/nat.conf vornehmen.
    1. VMware-Player beenden
    2. Unter [incomingtcp] die Portweiterleitungen eintragen
    [incomingtcp]
    # Use these with care - anyone can enter into your VM through these...
    PPP = xx.xx.xx.xx:PPP
    xx.xx.xx.xx ist die private IP-Adresse der virtuellen Maschine
    PPP ist der weiterzuleitende Port (z.B. 5900 für VNC oder 8080 für den erwähnten Apache-Dienst)
    3. den VMware-Service (und damit die virtuellen Interfaces) beenden
    /etc/init.d/vmware stop
    /etc/init.d/vmware start

    4. VMware-Player starten und die Ports werden vom Wirt zum Host weitergereicht

    In meinem Fall ist der Dienst dann natürlich noch nicht aus dem Internet/Intranet erreichbar. Dazu muß auf dem vorgeschalteten Router ebenfalls eine Weiterleitung eingerichtet sein, wobei hier natürlich die IP des Wirts zu verwenden ist.
    Beispiel:
    [Internet]-->[Router]--NAT-->[Wirt]--NAT-->[VMware]
    0.0.0.0:8080-->10.0.0.10:8080-->192.168.0.10:8080
    PS: Das Gateway des vmnet-Interface hat die *.*.*.2 und nicht wie üblich *.*.*.1 - aber das sei nur am Rande bemerkt

    2008-10-02

    VPN-Tunnel mittels VPNC und DD-WRT

    Auf der folgenden Seite aus dem offiziellen Wiki zur Open-Source-Firmware DD-WRT wird beschrieben, wie man auf einem mit DD-WRT v24 (oder höher) gepatchten Router einen VPN-Tunnel einrichten kann: http://www.dd-wrt.com/wiki/index.php/VPNC.
    Der Clou: Mittels Ping auf zwei unterschiedliche Rechner innerhalb des VPNs wird festgestellt, ob die Verbindung noch aktiv ist und im Fehlerfall wird der Tunnel wieder hergestellt.
    Da es ausserdem sinnvoll ist, nicht alles durch den Tunnel zu schicken, sondern nur bestimmte Netze, kann man genau das konfigurieren. Mal abgesehen davon: Die Bandbreite, die durch den Tunnel geht ist auf 200kb/s beschränkt.
    Es hat etwas gedauert das zum Laufen zu bringen, weil die Anleitung nur die Bruchstücke hergibt. Darum nun das komplette Skript.
    Die fett gedruckten Teile sind natürlich anzupassen und die kursiv gedruckten kann man anpassen, z.B. wenn die Verbindung sehr oft wegbricht, das Gateway ein anderes ist, ...
    Das ganze als Startup-Skript über den Administration/Diagnose-Reiter der Web-Oberfläche des Routers einspielen und den Router neu starten.
    mkdir /tmp/etc/vpnc
    rm -f /tmp/etc/vpnc/vpnc-script
    echo '
    #!/bin/sh
    # This is a wrapper for the vpnc-script overriding some variables needed
    # for setting up split-tunneling
    # this effectively disables changes to /etc/resolv.conf
    INTERNAL_IP4_DNS=

    # This sets up split networking regardless of the concentrators specifications.
    # You can add as many routes as you want, but you must set the counter
    # CISCO_SPLIT_INC accordingly. All requests to IP ranges NOT listed
    # in the code below will NOT go though the VPN tunnel.

    CISCO_SPLIT_INC=2
    CISCO_SPLIT_INC_0_ADDR=192.0.0.0 #IP range to go into first tunnel
    CISCO_SPLIT_INC_0_MASK=255.0.0.0 #Subnet Mask for first tunnel
    CISCO_SPLIT_INC_0_MASKLEN=8 #Mask length
    CISCO_SPLIT_INC_0_PROTOCOL=0
    CISCO_SPLIT_INC_0_SPORT=0
    CISCO_SPLIT_INC_0_DPORT=0
    CISCO_SPLIT_INC_1_ADDR=172.0.0.0 #IP range to go into 2nd tunnel
    CISCO_SPLIT_INC_1_MASK=255.0.0.0 #Subnet Mask for 2nd tunnel
    CISCO_SPLIT_INC_1_MASKLEN=8 #Mask length
    CISCO_SPLIT_INC_1_PROTOCOL=0
    CISCO_SPLIT_INC_1_SPORT=0
    CISCO_SPLIT_INC_1_DPORT=0

    # run the original script
    . /etc/vpnc/vpnc-script
    ' >> /tmp/etc/vpnc/vpnc-script
    chmod 700 /tmp/etc/vpnc/vpnc-script
    rm -f /tmp/etc/vpnc/vpnc.sh
    echo '
    #!/bin/sh
    vpn_concentrator="xxx.xxx.xxx.xxx" ##enter ip or hostname of your Ipsec vpn concentrator
    vpn_keepalive_host1="192.168.0.1" ##enter the ip or hostname of a computer that is only reachable if vpn connection is established.
    vpn_keepalive_host2="192.168.1.1" ##enter the ip or hostname of a computer that is only reachable if vpn connection is established.
    vpn_groupname="xxx" ##enter the group name here
    vpn_grouppasswd="xxx" ##enter the group password here
    vpn_username="xxx" ##enter your username here
    vpn_password="xxx" ##enter your password here

    #--do not edit this--
    #Written by Alain R. (alainr [AT] gmx.de) 28.Sep.2007
    vpnc-disconnect
    rm -f /tmp/etc/vpnc/vpn.conf
    echo "
    IPSec gateway $vpn_concentrator
    IPSec ID $vpn_groupname
    IPSec secret $vpn_grouppasswd
    Xauth username $vpn_username
    Xauth password $vpn_password
    Script /tmp/etc/vpnc/vpnc-script
    " >> /tmp/etc/vpnc/vpn.conf

    pingtest1 () {
    ping -q -c1 $param1 >> /dev/null
    if [ "$?" == "0" ]; then
    echo 0 #reachable
    else
    echo 1 #not reachable
    fi
    }

    pingtest2 () {
    ping -q -c2 $param2 >> /dev/null
    if [ "$?" == "0" ]; then
    echo 0 #reachable
    else
    echo 1 #not reachable
    fi
    }

    while [ true ]; do
    param1=$vpn_concentrator;
    if [ "`pingtest1`" == "0" ]; then #Vpn concentrator reachable
    doloop=1;
    while [ $doloop -gt 0 ]; do
    param1=$vpn_keepalive_host1;
    if [ "`pingtest1`" == "0" ]; then
    sleep 300
    else
    param2=$vpn_keepalive_host2;
    if [ "`pingtest2`" == "0" ]; then
    sleep 300
    else
    doloop=0;
    vpnc-disconnect
    vpnc /tmp/etc/vpnc/vpn.conf --dpd-idle 0
    sleep 1
    if [ "`pingtest1`" != "0" ]; then
    sleep 10
    fi
    tundev="`ifconfig |grep tun |cut -b 1-4`"
    iptables -A FORWARD -o $tundev -j ACCEPT
    iptables -A FORWARD -i $tundev -j ACCEPT
    iptables -t nat -A POSTROUTING -o $tundev -j MASQUERADE
    sleep 9
    fi
    fi
    done
    else
    sleep 10;
    fi
    done

    return 0;
    ' >> /tmp/etc/vpnc/vpnc.sh
    chmod 700 /tmp/etc/vpnc/vpnc.sh
    /tmp/etc/vpnc/vpnc.sh&

    Spekulationen um DoS-Schwachstelle im TCP-Protokoll

    Ein möglicher Design-Fehler im TCP-Protokoll soll sich ausnutzen lassen, um beliebige Server im Internet unerreichbar zu machen.
    Das ist beunruhigend, basiert doch meine globalisierte kleine Welt genau darauf, daß mittels dieses Protokolls alles was ich brauche vernetzbar ist (oder zumindest die Lieferanten dieser Dinge ein Netzwerk betreiben können, um mich damit zu versorgen).
    Passend zu diesem Thema ist das untige Video. Daumen hoch!

    PS: Gefunden in den Kommentaren zum gleichnamigen Artikel bei heise.de

    Nachtrag: Hier der Link zum Song-Text (man beachte, daß er sich in der RIPE-Datenbank befindet)

    2008-07-30

    VMware Player: Failed to allocate page for guest RAM!

    Nach erfolgreichem Mounten der externen Festplatte, wollte nun der vmplayer die VM nicht starten. Unter Windows und nach dem Kopieren auf eine lokale Platte hingegen schon. Sollte doch noch eine Option beim ntfsmount fehlen?
    Nein, jedes Programm will ein bißchen anders gestreichelt werden.
    Hier die Fehlermeldung:
    VMware Player unrecoverable error: (vcpu-0)
    Failed to allocate page for guest RAM!
    A log file is available in "/media/ExternePlatte/VM/vmware.log". Please request support and include the contents of the log file.
    To collect data to submit to VMware support, run "vm-support".
    We will respond on the basis of your support entitlement.

    Lösung: In der xxx.vmx-Datei die Option
    mainMem.UseNamedFile="FALSE"
    eintragen und der vmplayer kann die Speicher-Datei anlegen und die VM startet.

    ntfsmount

    Eine externe Festplatte mit einem VMware-Image einer Testumgebung ist eine feine Sache. Allein das kopieren der ca 30GB über das Netzwerk wäre sonst schon ziemlich unschön.
    Nach dem Auspacken und Anschliessen der heiß ersehnten Fracht, wurde die Platte auch sofort von Debian (Etch) erkannt und ein lesender Zugriff war ohne Probleme möglich.
    Aber wie kann man nun auch schreiben? Sonst stünde ja doch eine Kopie an?

    Hilfe naht mit dem Tool ntfsmount im Paket ntfsprogs. Dieses via Synaptic Paketmanager oder
    apt-get install ntfsprogs
    installieren.
    Das Tool benötigt noch FUSE, welches aber normalerweise zum Funktionsumfang ab Kernel 2.6.14 gehört (beim aktuellen Patch-Level von Debian Etch ist das der Fall).
    Ob das Modul vorhanden ist kann man mit
    modprobe -l fuse
    feststellen.
    Temporär kann man das Kernelmodul mit
    modprobe fuse
    starten. Permanent macht man das mit dem Eintrag
    fuse
    als separate Zeile in /etc/modules.
    Nun kann man sich an das mounten der Festplatte machen (gilt für interne genauso).
    Als erstes mal einen Mount-Punkt anlegen:
    mkdir /media/ExternePlatte
    Dann manuell mounten:
    ntfsmount /dev/sdb1 /media/ExternePlatte

    sdb1 ggf. durch den eigenen Plattennamen ersetzen.
    Hinweis: Wenn die Platte autmatisch erkannt wurde, kann man mit
    mount
    alle Platten auflisten und erhält so auch den Device-Namen - hier eben /dev/sdb1
    Mit
    umount /dev/sdb1
    sollte man dann vor erneutem mounten die Platte erstmal wieder trennen


    Die Platte ist jetzt verfügbar aber noch nicht wirklich beschreibbar.
    Warum?
    Obige Schritte sind nur als root durchführbar und man ist ja sinnvollerweise eben nicht als root angemeldet. Die folgenden Optionen dienen der Abhilfe unter der Annahme, daß sich genau ein Benutzer am System angemeldet hat (ansonsten sollte man mit uid,guid und umask feintunen - siehe
    man ntsmount
    )
    Der gesamte Befehl nochmal:
    ntfsmount /dev/sdb1 /media/ExternePlatte -o umask=0,allow_others
    Um das ganze nicht jedesmal wieder eintippen zu müssen, kann der Eintrag in der /etc/fstab hinterlegt werden (separate Zeile, Spalten getrennt durch [Tab])
    /dev/sdb1 /media/ExternePlatte ntfs-fuse umask=0,allow_others 0 0
    Hinweis: In der Original-Dokumentation steht fuse.ntfs - das funktioniert nicht
    Hier gibt es mehr Informationen (auch für andere Linux-Distributionen): http://www.linux-ntfs.org/doku.php?id=ntfsmount