Schlagwort-Archive: Java

Alles trieft, alles klebt, die Affenhitze hat Deutschland fest im Griff, und wochenlang gibt es keinen einzigen Tropfen Regen, der die Qual ein wenig lindern würde. Während ich bei bestimmt 40 Grad unterm Dach vor mich hin transpiriere und es seit letztem Monat kaum terminfreie Tage gab, versuche ich im Umzugsstress meinen Blog nicht komplett zu vernachlässigen, auch wenn ich dafür nur noch zwischen Tür und Angel mal die Möglichkeit habe. Aber es kommen wieder bessere Tage, dafür garantiere ich. Die Gelegenheit ist günstig für einen Füllbeitrag zum Thema „Warum Windows manchmal eben doch großer Mist ist“. Hier habe ich zwei skurrile Dinge gesammelt, die mir beim Arbeiten (oder Zocken) mit Windows sinnlos Probleme bereitet haben.

Fangen wir mit dem größten Übel an: Ein Problem mit Windows Server 2003, das scheinbar schon so manchem die Schuhe beim Gedanken daran auszieht. Ich wollte einen gerade unter Windows laufenden Java-Prozess mit Hilfe des Tools jstack.exe untersuchen. Üblicherweise ist das gar kein Problem, man muss eben nur Process-ID wissen, und die erfährt man mit dem tollen Windows-Befehl tasklist. Soweit alles noch in Ordnung. Als ich dann aber jstack mit besagtem Parameter ausführen wollte, erhielt ich diese völlig nichtssagende weil absurd falsche Fehlermeldung: „Not enough storage is available to process this command.“ (im deutschen Windows „Nicht genügend Server-Speicherplatz verfügbar, um diesen Befehl zu verarbeiten„).

Einwandfrei. Nicht genügend Arbeitsspeicher bzw. Swap-Speicher für die winzige jstack.exe auf einem eigentlich gut ausgestatteten Windows-Server? Nein, ich glaube eher nicht. Aber danke für deine unbrauchbare Hilfe, Windows! Ich fand eine Microsoft-Hilfeseite, die versucht das Problem näher zu erläutern und Problemlösungen zu bieten. Mit Betonung auf „versucht“, weil Microsoft grandios daran scheitert, denn schon die Fehlermeldung an sich ist einfach Quatsch. Auch eine deutsche Hilfeseite führte mit ihren Anweisungen nur komplett in die Irre.

Zum Glück kannte jemand auf Stackoverflow.com die Lösung. Man muss jstack mit Hilfe von „psexec -s jstack.exe pid“ aufrufen, damit es richtig auf dem Zielrechner ausgeführt wird. Das hat also genau gar nichts mit zuwenig Speicherplatz o.ä. zu tun, wie Windows mir weismachen wollte. Wenn man noch nicht einmal die richtige Fehlermeldung angezeigt bekommt, wenn schon ein Fehler auftritt, dann weiß ich nicht, worauf ich mich bei Windows sonst noch verlassen können soll.

Das zweite Problem ist dagegen ein eher kleines, kürzlich entdeckt und gelöst auf einer LAN-Party, also einem gesellschaftlichen Event zum gemeinschaftlichen Zocken netzwerkfähiger Windows-Spiele. Besonders nervtötend ist es, wenn das Windows-Netzwerk an sich fehlerfrei eingerichtet ist, es aber dennoch vereinzelt Spiele gibt, in denen immer derselbe LAN-Teilnehmer (=ich) die Spiele der anderen nicht sehen kann, und umgekehrt. Die Liste in der Lobby ist leer, obwohl alle anderen bereits dem offenen Spiel beigetreten sind. Man sucht sich also einen Wolf, auf der Suche nach dem einen Fehler, der dafür sorgt, dass man in manchen Spielen für alle anderen unsichtbar ist. Die Fehlersuche wird allein dadurch erschwert, dass das Problem nur manche Spiele betrifft, und auch dann noch nicht einmal immer.

lanadapterDas Problem wäre natürlich gar keines, wenn man in solchen Spielen einfach eine Ziel-IP zum Verbinden eingeben könnte, aber so einfach machen es einem die Entwickler nicht. Könnte womöglich manche Spieler überfordern. Des Rätsels Lösung lag dann in der Existenz weiterer LAN-Adapter, die unter Windows installiert waren: darunter der VirtualBox-LAN-Adapter, Tunngle, bei anderen findet man dort etwa Hamachi oder VMware. Alle diese Adapter müssten – auch wenn sie im Moment nicht benutzt werden – explizit deaktiviert werden, weil die Spiele sonst in Versuchung kommen könnten, diese für die Netzwerkverbindung mit den anderen Spielern zu verwenden, anstelle des eigentlich höher priorisierten richtigen LAN-Adapters.

Willkommen zu meinem nächsten Beitrag direkt aus meinem Fundus merkwürdiger Java-Lösungen für nicht ganz so alltägliche Programmierprobleme. Normalerweise würde ich meine kreativen Fehltritte sicher NIE veröffentlichen, aber dieses Mal mache ich noch eine Ausnahme, da ich glaube, es könnte den einen oder anderen auf die richtige Spur bringen, wenn er nicht weiter weiß.

Kürzlich war ich dabei, einen kleinen Indexer für dies und das zu schreiben, der einmal am Tag zu einer bestimmten Tageszeit Datensätze aus einer Datenbank zieht. Wofür genau spielt hier natürlich keine Rolle. Jedenfalls wollte ich dafür einen TimerTask verwenden, und der wird beispielsweise mit einem Delay (Verzögerung in Millisekunden bis zum ersten Start), und einem Intervall (Verzögerung in Millisekunden für alle darauffolgenden Starts) gefüttert. Randbedingung war, dass der Indexer einmal am Tag um dieselbe Uhrzeit läuft. Diese Uhrzeit soll man hinterlegen können. Den TimerTask-Kram habe ich weggelassen, und den eigentlichen Indexer-Code auch, um das Beispiel möglichst auf das Essentielle zu reduzieren.

Mein Problem war nämlich, dass ich auf Anhieb nicht wusste, wie ich herausfinden könnte, wann der nächstmögliche Zeitpunkt für eine festgelegte Uhrzeit ist, also ob beispielsweise 14:30 Uhr noch am selben Tag ist, oder erst am darauffolgenden Tag. Wieviele Millisekunden muss ich als Verzögerung des initialen Starts angeben, damit der Indexer zur nächsten Gelegenheit um eine bestimmte Uhrzeit losläuft?

Nach einer Weile habe ich mir die obige Lösung für mein simples Problem auserdacht. Die Methode timeToNextIndexTask() gibt einen int-Array zurück, der die Zeit in Stunden und Minuten beinhaltet. Das lässt sich ohne Schwierigkeiten in Millisekunden umrechnen.

Aber wie das so ist, fällt einem schon kurze Zeit später auf, wie sinnlos man sich den Kopf darüber zerbrochen hat, und dass diese Lösung zwar funktioniert, aber eigentlich viel zu aufwändig und der Code ziemlich wackelig ist. Meine Frage lässt sich mit zwei GregorianCalendar-Objekten sehr einfach beantworten:

Kurzgesagt, man legt einen GregorianCalender für den aktuellen Zeitpunkt an, und verstellt einfach die Uhrzeit, behält das Datum jedoch bei. Nun muss man lediglich mit Hilfe der Methode after() bzw. before() vergleichen, ob das verstellte Calendar-Objekt in der Vergangenheit oder in der Zukunft liegt. Falls es in der Vergangenheit liegt, muss man einen Tag dazuzählen, und schon hat man seinen gewünschten Zeitpunkt.

javaappletGerade kürzlich dachte ich so bei mir: Warum eigentlich nicht mal wieder einen Java-Artikel schreiben? Die Zeit ist reif dafür. Oracle bringt es mit seiner Intransparenz und seiner faulen Update-Politik offenbar noch fertig, Java komplett in den Ruin zu reiten. In der Öffentlichkeit hatte Java nie einen schlechteren Stand. Dass inzwischen selbst JavaScript ein sehr viel besseres Ansehen als Java genießt, das ist wirklich ein großes Armutszeugnis, das ich Oracle ausstellen muss. Wir erinnern uns an das Jahr 1997: JavaScript war ursprünglich diese nervige Browserspielerei, mit der man den Rechtsklick unterbinden und die Statusleiste im Internet Explorer für blöde Laufschriften missbrauchen konnte.

Java hat bestimmt so einige kleine Problemchen, aber im Moment wird zu Unrecht geschimpft. Das miese Browser-Plugin ist es, das ständig mit neuen Sicherheitslücken negativ in die Schlagzeilen gerät. Dennoch hagelt es jetzt Kommentare in der Art wie: „Java gehört in den Sondermüll und ich kann nur jedem raten, es zu deinstallieren!“. Die Probleme waren kürzlich scheinbar sogar so gravierend, dass das Bundesamt für Sicherheit in der Informationstechnik (BSI) in diesem Drama unbedingt mitspielen wollte und fortan ebenfalls jedem empfiehlt, bloß schnell Java loszuwerden. In meinen Augen allerdings eine ziemlich peinliche Äußerung, die mir beweist, dass der Laden dort auch nur von den üblichen Internetausdruckern geführt wird, die keine Fachkompetenz besitzen. Das ist wie als würde man ständig empfehlen, Windows zu deinstallieren, wenn im Internet Explorer mal wieder eine Sicherheitslücke offengelegt wurde. Das ist mit Kanonen auf Spatzen schießen.

Natürlich würde dort NIE jemand empfehlen, Windows zu deinstallieren. Warum eigentlich nicht? Und wenn wir schon bei Sicherheitslücken sind, wieso empfiehlt das BSI nicht ausnahmsweise was Sinnvolles, z.B. solchen fahrlässigen Mist wie WhatsApp zu deinstallieren, wegen der ganzen Sicherheitslücken, wegen dem komplett unverschlüsselten Traffic, und wegen dem fragwürdigen Datenschutz beim Versenden des kompletten Adressbuches? Aber das ist wohl eine andere Geschichte.

Nichtsdestotrotz hat Java dadurch wieder einen spürbaren Imageschaden abbekommen. Witzigerweise wird Java immer nur dann verteidigt, wenn jemand Minecraft erwähnt. DAS ist so ziemlich der ultimative Beweis dafür, dass es Java schlecht geht: Wenn ein mäßiges aber weitverbreitetes Indie-Spiel so ziemlich das Einzige ist, womit man noch zeigen kann, dass Java manchmal auch ein bisschen toll sein kann. Mich als Java-Entwickler stört das natürlich schon ein wenig, weil Java eigentlich sehr vielseitig und extrem nützlich ist, wenn man platformunabhängig entwickeln möchte. Programmieren in Java macht einfach Spaß und Probleme habe ich damit auch keine.

Nun wollte ich eigentlich einen Beitrag über einen winzig kleinen Fehler in Java schreiben, der mir kürzlich aufgefallen ist, aber ich glaube wenn Java im Moment etwas am wenigsten gebrauchen kann, dann sind das noch mehr Nörgler. Stattdessen werde ich mich mit diesem Beitrag einfach öffentlich solidarisch zu Java bekennen. Ich bin gerne Java-Programmierer und ich würde es am liebsten noch eine Weile bleiben. Es gibt nichts zu bereuen.

Ich weiß nicht ob das typisch für mich ist, dass ich das neue Jahr mit einem Rant einleite, aber zeitlich ist es jedenfalls nicht beabsichtigt. Ich wasche meine Hände in Unschuld. Zunächst also ein frohes neues Jahr. Die tollen, freundlichen Beiträge kommen alle noch die Tage. Wieder einmal habe ich die Hoffnung, dass dieser Artikel all jenen hilft, die mit einem ähnlichen Problem konfrontiert werden. Das Programmiererleben ist sicherlich vieles, aber gewiss nicht einfach.

Vergangene Woche war ich in der Situation eine portable Version einer Solaris JVM (Java Virtual Machine) aktualisieren zu dürfen. Die bisherige Version des JDK6 war leider veraltet und brachte regelmäßig Segmentation Faults im Dauerbetrieb zustande. Ein neueres Update (1.6.0 Update 38) sollte hoffentlich stabiler laufen. Mit einer portablen Version ist eine Java-Installation gemeint, die man einfach auf dem Zielsystem in ein Verzeichnis seiner Wahl entpackt und die sofort (und vor allem ohne betriebssystemabhängige Installation) lauffähig ist. Aus diesem Grund wollte ich mir eine solche Version von Oracle herunterladen. Das war aber schon das erste Problem: Oracle ist nämlich ziemlich scheiße.

Oracle bietet (jedenfalls für Java 6) keine portablen JDKs zum Entpacken an – nur Installer. Da ich auf dem Zielsystem aber keine Installationsprogramme ausführen kann/darf/will, ist das selbstverständlich keine Alternative, zumal ich ja wusste, dass Java problemlos portabel ausführbar ist. Eine Installation ist daher gar nicht nötig. Kurzerhand musste ich also kreativ werden und basteln. Ich wollte den doofen Installer umgehen und die Dateien von Hand extrahieren. Das war gar nicht so schwierig wie ich dachte. Mein Werk wollte ich im Vorbeigehen kurz an einer Client-Anwendung testen, als beim Starten der JVM eine wilde Fehlermeldung erschien:

Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object

Soso, sehr interessant. Die JVM kann die Klasse java.lang.Object nicht finden. Wenn diese Klasse fehlt, dann fehlt praktisch alles. Ein freundliches Google teilte mir mit, dass es vermutlich mit einer fehlenden Datei rt.jar im Verzeichnis /jre/lib/ zusammenhängt. Tatsächlich, diese Datei gab es dort nicht. Ist Oracle wirklich so bescheuert und liefert ein unvollständiges, nicht lauffähiges JDK aus? Ist das die Strafe dafür, dass ich den Installer übergangen habe?

Ist es. Denn der Installer hat zudem die Aufgabe, die rt.jar aus einer gepackten Datei namens rt.pack auszupacken, und diverse weitere Dateien:

./lib/tools.pack
./jre/lib/charsets.pack
./jre/lib/jsse.pack
./jre/lib/deploy.pack
./jre/lib/javaws.pack
./jre/lib/plugin.pack
./jre/lib/rt.pack
./jre/lib/ext/localedata.pack

Warum das so ist, weiß nur der Teufel. Platzersparnis bringt es gegenüber dem umliegenden Archiv keine. Es ist wahrscheinlich reine Schikane. Manche behaupten auch, das wäre ein Mechanismus, um sicherzustellen, dass niemand den Installer umgeht, da dieser ja zum Akzeptieren der AGB auffordert. Zum Glück gibt es die mitgelieferten Java-Tools pack200 und unpack200. Mit deren Hilfe kann man die JAR-Dateien aus den PACK-Dateien befreien – sogar über verschiedene Betriebssysteme hinweg. Und dann klappt das auch wieder mit der JVM.

Seit diesem Tag hasse ich Oracle wieder ein bisschen mehr, und ich bin ein bisschen weiser geworden. In meinen Augen eine echte Schweinerei. Portable Versionen sind super und hinterlassen weniger Spuren. Wenn man weiß was man tut, und wenn man in der Lage ist, sich selbst um die richtigen Pfadangaben zu kümmern, dann hat ein portables Java viele Vorteile, vor allem wenn man viele homogene Systeme unter seiner Obhut hat.

Quellen:
http://www.cynosurex.com/Forums/DisplayComments.php?file=Java/Finding_rt.jar_in_JRE_5.0_Update_9
http://tntit.blogspot.de/2012/04/linux-jdk-6-installation-hard-way.html
http://turbolinux.org/2011/05/error-occurred-during-initialization-of-vm-javalangnoclassdeffounderror-javalangobject/
http://stackoverflow.com/questions/1619662/where-can-i-get-the-latest-jre-jdk-as-a-zip-file-i-mean-no-exe-installer

Es lebt! Spacola Eclipse ist zwar noch lange nicht fertig, aber ich habe den ersten Meilenstein erreicht: Der erste Gegnertyp fliegt im Spiel herum und man kann schon jede Menge Zeug kaputtballern. Die Gegner können sich zwar noch nicht richtig wehren, aber immerhin nerven sie schon gewaltig. Zur Feier der neuen WIP-Version 0.21 gibt es heute die ersten Preview-Videos, also vollständig bewegte Eindrücke des Spiels. Ich habe endlich eine Desktop-Capture-Software gefunden, die nicht nutzloser Shareware-Müll ist und sogar halbwegs flüssige Bewegungen UND Sound aufnehmen kann.

Das erste Video zeigt das Gameplay des Remakes. Das Intro wird hierzu natürlich abgebrochen. Die schlechte Bildqualität und die ruckelige Grafik bitte ich zu entschuldigen. Das Capture-Programm ist zwar gut, aber leider trotzdem nicht optimal. Der stark verlustbehaftete YouTube-Codec tut dann sein übriges. Das Spiel läuft vollständig flüssig bei (künstlich limitierten) 52 fps und verbraucht nur sehr wenige Ressourcen.

Das zweite Video ist nun naturgemäß nicht so spannend. Es soll im Grunde eigentlich nur zeigen, wie genau ich das Original-Intro in meinem Remake imitiert habe, da ich alles, so weit es mir möglich ist, pixelidentisch halten will. Das Spiel im Demo-Modus würde dann also bisher folgendermaßen aussehen:

Für Späteinsteiger: Spacola Eclipse ist mein kleines Java-Remake (bzw. im Moment eher: Re-Implementation) des Atari ST-Spiels SPACOLA, das 1991 von Dongleware veröffentlicht wurde. Das Ziel ist eine (zunächst) möglichst exakte Nachbildung des Originals für viele moderne Platformen (Windows, Mac OS, Linux, iOS, Android) und in zweiter Instanz die Erweiterung des Spiels um bessere Grafiken, neue Sounds, einen Mehrspielermodus und neue sinnvolle Features.