Social-Networks:
Facebook
Instagram
Tumblr

Blog: Latest Entries (15):


MySQL: DDL und Transactions

Das ist jetzt nicht wirklich eine große Entdeckung und ist eigentlich klar, aber auch wenn in der Beschreibung von MySQL nur steht, dass einige Statements nicht mehr mit einem Rollback zurück genommen werden können, wenn man ein DDL-Statement nach einem start transaction; ausführt, bedeutet es einfach, dass die Transaction danach einfach commited wird und alles danach nicht in einer Transaction läuft.

Wenn man sich als bei größeren Imports oder Datenverarbeitungen eine Tabelle zum Auslagern von Daten erzeugt, sollte man das immer zuerst und außerhalb der Transaction machen. Auch wenn man mit PDO arbeitet, muss man darauf achten.

bbcode-image


Sich extra Tabellen anlegen ist gut für Dinge, die länger laufen und besonders wenn sie länger laufen als die Timeout-Zeit von PHP oder des DB-Treibers. Den gerade MySQL locked alle Rows, die während einer Transaction geschrieben und auch gelesen werden. Wenn nun jemand in so eine Row schreiben möchte, die in einer langen Transaction auch nur gelesen wurde,kann es schnell zu Problemen kommen.
Erst einmal sollte man sowie so Stammdaten und Bewegungsdaten trennen. Damit minimiert sich das Problem schon mal etwas.

Am Ende kann man auch das Isolation-Level ändern, aber das sollte immer das letzte sein, was man versuchen sollte.

Eigenes Lightweight Logging (PHP)

Wenn ich eine Lib oder ein Framework sehe, kommt bei mir immer die Frage auf: "Wie macht man so etwas?" Das gipfelte heute darin, dass ich ein kleines Logging-Framework geschrieben habe. Etwas an
Log4j erinnernd aber erst einmal nur mit Output in eine Datei. Andere Outputs könnte man noch integrieren durch Appender-Types.

bbcode-image


Die LoggerFactory

class XWLoggerFactory{
private static $config=[];
private static $appenderCache=[];

/**
* @return XWLogger
* @param string $clazz
*/
public static function getLogger($clazz){
if(count(self::$config)==0 && file_exists("system/config/log.json")){
self::$config=json_decode(file_get_contents("system/config/log.json"),true);

foreach(self::$config["appenders"] as $appender){
self::$appenderCache[$appender["name"]]=$appender;
}
}

$appenders=[];
$levels=[];

foreach(self::$config["classes"] as $cla){
if(preg_match("/^".$cla["name"]."/i", $clazz)){
foreach($cla["appenders"] as $app){
$appenders[]=self::$appenderCache[$app["name"]];
$levels[]=$app["level"];
}
}
}

return new XWLogger($clazz, $appenders, $levels);
}
}


Der Logger

class XWLogger{
const ALERT="alert";
const CRITICAL="critical";
const ERROR="error";
const WARNING="warning";
const INFO="info";
const NOTICE="notice";
const DEBUG="debug";

private $clazz="";
private $appenders=[];
private $levels=[];

private $values=[
"alert" => 6,
"critical" => 5,
"error" => 4,
"warning" => 3,
"info" => 2,
"notice" => 1,
"debug" => 0,
];

public function __construct($clazz, $appenders, $levels){
$this->clazz=$clazz;
$this->appenders=$appenders;
$this->levels=$levels;
}

/**
*
* @param string $type
* @param string $msg
* @param \Exception $e
*/
public function log($type, $msg, \Exception $e=null){
foreach($this->appenders as $key => $app){
if($this->values[$this->levels[$key]] >= $this->values[strtolower($type)]){
$dateFormat="Y-m-d h:i:s";
if(isset($app["dateformat"])){
$dateFormat=$app["dateformat"];
}
$ip="";
if(isset($app["remoteip"]) && ($app["remoteip"]===true || $app["remoteip"]=="true")){
$ip=" [".$_SERVER["REMOTE_ADDR"]."]";
}
$content = strtoupper($type).$ip." [".date($dateFormat)."]: ".$msg;
if($e!=null && $app["exceptionFullStackTrace"]){
$content.="\n".$e->getTraceAsString();
}
if(!file_exists($app["filename"])){
if(!file_exists(preg_replace("/[a-zA-Z0-9_.]+$/Uis", "", $app["filename"]))){
mkdir(preg_replace("/[a-zA-Z0-9_.]+$/Uis", "", $app["filename"]));
}
}
file_put_contents($app["filename"], $content."\n", FILE_APPEND);
}
}
}
}


Die Config-Datei (system/config/log.json) for den aoop-PageLoader

{
"appenders":[
{
"name":"default",
"filename":"system/log/aoop.log",
"dateformat":"H-m-y h:i:s",
"remoteip":"true"
}
],
"classes":[
{
"name":"XWFastPostProPageLoader",
"appenders":[
{
"name":"default",
"level":"warning"
}
]
}
]
}


Eine Nutzung mit einer einfachen Warning

XWLoggerFactory::getLogger(self:class)->log(XWLogger::Warning, "a warning!");

PHP Basics

Wer sich mal etwas mit Zend VM, Objekten in PHP beschäftigen möchte oder wissen will wie Funktionen in PHP funktionieren (mit Stack und allem anderen) sollte sich mal diese Artikel ansehen:

http://jpauli.github.io/2015/02/05/zend-vm-executor.html

http://jpauli.github.io/2015/01/22/on-php-function-calls.html

http://jpauli.github.io/2015/03/24/zoom-on-php-objects.html

Mir haben die Artikel einen wirklich tieferen Einblick in PHP ermöglicht und ich verstehe jetzt einiges besser. Gerade auch wenn es um Performance geht.

Neo4j 3.0: Import Verzeichnis ändern

Wer sich mit CSV-Importen in Neo4j 3.0 versucht wird schnell merken, dass die angegebene File-URL sich irgendwie immer auf das Neo4j Verzeichnis bezieht auch wenn man sich auf das Root Verzeichnis bezieht. Der Fehler liegt nicht an der File-URL, sondern an einer Einstellung in Neo4j, wo als default Verzeichnis das eigene import-Verzeichnis gewählt ist und die File-URL sich nur auf Dateien innerhalb dieses Verzeichnisses bezieht.
Man kann einfach in der conf/neo4j.conf das import Verzeichnis von import auf / (Linux) ändern und es verhält sich wieder wie in der 2.x Version.

Intel Xeon Mainboard und Lüfter auf voller Power

Wenn die Lüfter bei einem Intel Mainboard (z.B. einem S5520) nach dem Piepsen beim Start plötzlich extrem aufdrehen und sehr laut werden, liegt es wohl daran, dass noch ein falsches Gehäuse konfiguriert ist.
Das Board hat gewisse Vorgaben, welche Gehäuselüfter in welchem Gehäuse angeschlossen sein müssen. Wenn nun einer dieser Lüfter fehlt (oder auch nur an FAN 2 und nicht an FAN 3 angeschlossen ist...) geht das System von einem Ausfall aus und dreht alle Lüfter auf, um den Ausfall zu kompensieren.

bbcode-image


Bei dem Wechsel des Boards aus einem Intel-Servergehäuse in einen normalen Tower fehlen dann meist das Frontpanel, der Sensor und die Gehäuselüfter oder sind anders verteilt, da weniger Lüfter an der Front angebracht sind.

Um nun die Konfiguration auf ein Gehäuse des Typs "other" zu ändern muss man sich den gesamten BIOS-Stack downloaden und auf einen USB-Stick ins Root-Verzeichniss kopieren.

bbcode-image


Diesen anschließen und über den Bootmanager in die interne EFI-Shell booten. Der Stick wird automatisch erkannt.

bbcode-image


Dann einfach das Script ausführen lassen und allen Schritten folgen. Fehlendes Front-Panel ist egal und wenn gefragt wird, ob und was alles man konfigurieren möchte immer alles neu konfigurieren.
Wenn man durch ist, sollten die Lüfter wieder mit normaler Geschwindigkeit laufen.

PHP: HashMaps und Objekte, Grundlagen und Implementierung

Gerade in der letzten Zeit mit PHP7 hat sich wieder einiges in der PHP-Welt getan und einiges hat damit einen großen Schritt nach vorne gemacht. Betroffen davon sind z.B. die Bereiche der PHP-Arrays (was im GRunde ja eigentlich HashMaps sind) und der Objekte. Es gibt ein paar wirklich gute und Ausführliche Artikel zu den Themen, die sich mit den Grundlagen beschäftigen. Dies sind keine Grundlagen für Anfänger sondern gehen wirklich in die Tiefe und man sollte beim Lesen auch keine Angst vor etwas C-Code haben.

Besonders der Bereich mit den Packed Hashmaps ist sehr interessant, weil dort erklärt wird, wie man ein fast echtes Array in PHP bekommt, das ohne Translation-Table und die Erzeugung von Hashes auskommt sondern wird einfach 0-n als Index verwendet und dies direkt auf ein entsprechendes C-Array umsetzt. Das spart etwas Speicher, aber auch sehr viel CPU-Zeit und bringt mehr Performance. Bevor man also als Index irgendwelche Ids oder so verwendet sollte man noch mal überlegen, ob man das wirklich benötigt oder ein einfaches und schnelles Array doch von Vorteil wäre.

http://jpauli.github.io/2016/04/08/hashtables.html
http://jpauli.github.io/2016/01/14/php-7-objects.html
http://jpauli.github.io/2015/03/24/zoom-on-php-objects.html


Backups und Blurays

Da sich bei mir im letzten Jahr nebenjobtechnisch viel bewegt hat und ich meine privaten Projekte sehr reduziert habe und mich verstärkt auf wenige einzelne Projekt konzentriere, habe ich die alten Daten oft kopiert, gesichert und nochmal wieder heraus gesucht.
Erst gestern fiel auf, dass bei dem ganzen hin und her eine style.css einer alten Firefox OS App nicht mit kopiert wurde, weil das Build-Script einmal nicht richtig gearbeitet hatte. Also musste ich das original Projekt wieder raus suchen, wo die Datei drin lag.

Ich gehöre sowie so zu den wohl wenigen Personen, die auch privat wirklich viele Sicherungskopien anlegen und dabei nicht einfach auf eine externe Festplatte setzt.
Eine meiner externen Festplatten ist erst vor einer Woche durch Katzenpischi so sehr beschädigt worden, dass wohl die Controller-Platine einen Knacks weg bekommen hat. Wenn ich noch mal eine genau baugleiche Festplatte finde, werde ich nochmal versuchen die Platine auszutauschen und auf die Daten zuzugreifen.

bbcode-image
Die defekte Festplatte


Der Verlust der Festplatte an sich, ist mir sogar relativ egal in dem Fall und es ist eher die Herausforderung als wirklich die Notwendigkeit die Daten doch nochmal zu kopieren.
Denn 99% der Daten von der Festplatte habe ich auf Blurays gesichert.

Blurays haben meiner Meinung nach folgende Vorteile:

* Es sind WORM-Medien, sind nach dem Brennen also unveränderbar
* ...also sicher gegen Trojaner, die einen die Daten verschlüsseln
* ...sicher gegen Trojaner, die einen die Daten löschen
* relativ Wasser fest, wenn eine Bluray mal ins Wasser fällt und mal etwas darin liegen bleibt, macht es nichts
* Stoßfest, kann also auch mal vom Tisch fallen
* keine Mechanik, die bei Nicht-Nutzung sich festsetzen kann
* keine Mechanik die mit der Zeit verschleißen kann

Natürlich gibt es beim Preis Unterschiede und bei normalen Blurays kann man nur 25GB pro Rohling brennen. 50x 25GB gibt es aber schon für etwas über 23 Euro. Das sind dann 1,25TB für 25 Euro. Das ist im Vergleich zu Festplatten nicht so teuer wie immer behauptet wird.
Auch die schlechten Erfahrungen mit den ersten DVD-Rohlingen klingen immer wieder mit. Brennen und 2 Wochen später nicht mehr lesbar. So was kenne ich auch. Aber bei Blurays hatte ich bis jetzt solche Probleme nicht. Die ließen sich bis jetzt immer ohne Probleme und ohne dass eine Stelle der Disc mehrmals gelesen werden musste, wieder auslesen. Trotzdem muss man auch wie bei DVDs auf einige achten:

* Trocken lagern
* Bei gleichmäßiger Temperatur (~20°) lagern
* vor direkter Sonneneinstrahlung schützen
* keine Cover drauf kleben oder mit komischen Stiften beschriften
* die Unterseite ist geschützter als die Oberseite.. also nicht falsch herum hinlegen! Ein Kratzer auf der Oberseite ist
viel schlimmer als auf der Unterseite!
* Gute Rohlinge kaufen
* Einen guten Brenner verwenden (hier nicht sparen)

Ich benutze zum Lagern eine Licht dichte Schublade und die Blurays und DVDs lagern in ihren Spindeln, die zum Teil mit Sprühlack abgedunkelt sind. Nicht mit Schwarz sondern mit heller oder reflektierender Farbe, damit sie sich bei Sonneneinstrahlung nicht aufheizen. Außerdem sind die Spindeln auch wirklich gut
abgedichtet, dass man sich um Feuchtigkeit und Staub wenig Gedanken machen muss.

Aber auch hier gelten die allgemeinen Regeln, wie für alle Backups:

* Redundante Datenspeicherung, lieber etwas mehrmals brennen als nur einmal (ein Datenträger kann immer kaputt gehen)
* Räumlich möglichst vom Rechner getrennt lagern (am besten sogar in einer anderen Stadt... oder wenigstens Haus)
* Immer mal wieder die Backups kontrollieren (Nachdem Schreiben auf das Medium sowie so noch mal einen Datenvergleich laufen lassen)
* Sicher aufbewahren (ein Safe wäre natürlich besser als eine Schublade.. falls man so etwas zu hause hat, dann auch verwenden)
* Immer alles sichern... das was man für unwichtig hält wird das sein, was man nachher braucht wenn es weg ist
* Inhalte alter Datenträger auf neue Kopieren

Gerade der letzte Punkt ist wichtig. Ich habe vor paar Monaten viele CDs auf Bluray kopiert. Von über 50 CDs ging gerade mal eine nicht und dort konnte auch nur eine Datei nicht mehr gelesen werden. Es war natürlich eine Datei, die ich dann doch gerne gehabt hätte, aber vermutlich hab ich das Foto auch noch mal zusätzlich auf einer DVD und zur Not müsste ich das Foto neu scannen (ein Vorteil der alten analogen Fotografie.. wenn sie nicht so extrem teuer wäre).

Da wir in einer Welt leben, wo die Daten mehr wert sind als die Hardware auf der sie gespeichert sind und gerade mit der aktuellen Flut an Schädlingen, die einem die Datenverschlüsseln wollen, sollte der Fokus bei der Datensicherung, wieder vermehrt auf optische WORM-Medien gelenkt werden, weil diese auch für den normalen Benutzer viel leichter richtig zu handhaben sind, als Festplatten, USB-Sticks oder Bänder.

GIF vs WebM

GIF ist so fest mit der Web-Kultur der 90er Jahre verbunden wie kaum eine andere Technologie. Die alten Homepages waren voll von blinkenden Sternen, glitzernden Herzen und komischen "Under Construction"-Schildern. Während man gerade erst MPEG-Videos entdeckte, die man dann downloaden konnte, sich aber nicht wirklich in HTML-Seiten integrieren ließen, brachten GIF-Animationen Bewegung in Seiten und ließen alles nicht ganz so statisch wirken.
Auch heute sind GIF-Animationen weit verbreitet und eine eigene kleine Kunstform. Während früher kleine gezeichnete Animationen den größten Teil davon ausmachten sind es heute oft kurze Szenen aus Videos und Filmen aller Art.

Doch GIF ist nicht wirklich das beste Format für Animationen. Mit dem Video-Tag aus HTML5, bei dem man ohne Probleme die Controllers ausblenden kann, einen Autostart festlegt und eine Loop festlegt, kann man nun auch moderne Video-Formate verwenden. Die Vorteile sind schnell genannt:

- mehr Farben
- höhere Framerate
- moderne Kompression und damit kleine Dateien
- höhere Auflösungen

Natürlich gibt es auch viele Vorteile:

- kompatibel bis in die "Steinzeit"
- keine zusätzlichen Codecs, weil fast alle Webbrowser sie nativ unterstützen
- viele Programme zum erzeugen von GIFs
- laufen selbst auf einem alten Win95 Rechner mit Pentium 90
- einfach zu erzeugen

Das größte Problem sind nicht mal die 256 Farben, da es ja nicht so ist dass man nur insgesamt 256 Farben zur Verfügung hat, sondern nur 256 verschiedene Farben aus der Palette der 24-Bit Farben wählen kann. Man hat also eine Tabelle mit Index mit maximal 256 Einträgen in der ja Eintrag eine 24-Bit Farbe (True-Color) hinterlegt ist. Das hat den Vorteil, dass der Eintrag "5" natürlich weniger Speicher verbraucht als "[255,255,255]", aber führt natürlich dazu, dass man die Anzahl der Farben eines Frames eine MP4 Videos auf 256 Farben reduzieren muss. Das geschieht mit der Quantization. Das an sich funktioniert sehr gut und 256 Farben sehen besser aus, als man denkt, solange alle verwendeten Farben nahe bei einander liegen in er 24-Bit Palette. Nur wenn man einen großen Bereich der 24-Bit Palette abbilden will, wirken die Farben fleckig und unpassend.

Früher liefen die Animationen auf auf einen 486er und man brauchte nur ein Modem. Das hatte seine Gründe. Einmal waren sehr wenig Farben in den Bildern (max. 8-10) und man hatte maximal 12 Bilder (das war schon eine aufwendige Animation) und hohe Delay-Werte welche Frameraten von 2-3 Frames pro Sekunde zur Folge hatten. Ich habe gelernt, dass man mit 6 fps man schon gute Animationen erzeugen kann, wenn man ein Video als Ausgangsmaterial hat, aber man dann schon schnell in den Megabyte-Bereich kommt bei der Datei. Weniger Farben ist meistens keine Option.

Eine Alternative zu GIF ist WebM, wo man nicht 10MB für die Animation hat sondern ~900KB und dabei noch mehr Farben hat. Leider funktioniert WebM nicht im IE, sondern nur im Firefox und Chrome/Blink-Browsern. Es können schon viele Programme WebM erzeugen, aber man kann nicht einfach ein paar Layer in GIMP anlegen und das als WebM-Video speichern. Als GIF-Animation könnte man es speichern.

Trotzdem würde ich WebM heute immer vorziehen, wenn ich eine Animation einbauen müsste. Erzeugen im Webbrowser geht im Chrome oder Vivaldi aufgrund der nativen WebP-Unterstüzung sehr schnell, was ich mit MP4toGIF.com gut zeigen kann. Firefox ist da sehr viel langsamer, weil noch eine extra WebP-Codierung in JavaScript erfolgen muss.

Um GIF wieder etwas konkurrenzfähiger in MP4toGIF.com zu haben werde ich mich daran machen einen alten Trick einzubauen. Der nicht gerade neue Trick besteht darin nicht jedes Frame der Animation voll zuspeichern, sondern immer nur die Unterschiede zum vorher gehenden Frame zu speichern und den Rest des Frames mit der Transparenz-Farbe aufzufüllen. Damit reduziert man die Farbanzahl und die Speichergröße des Frames. Früher wo das Bild aus großen Farbflächen bestand ging das sehr gut. Jetzt muss sich zeigen, ob bei einem Videobild wirklich noch genug Bildbereiche statisch bleiben um einen ähnlichen positiven Effekt zu erhalten.

Ich werde berichten...

Passwort Hash-Algorithmus wechseln

Viele System hashen ihre Passwörter immer noch einfach mit MD5. MD5 ist seit längerer Zeit nicht mehr wirklich sicher und ohne Salt sollte man heute sowie so nicht mehr arbeiten. Eines der großen Probleme von MD5 ist, dass es sehr schnell ist. Wenn man Checksums für Dateien erstellen möchte ist es ideal, aber gerade bei Brute-force Angriffen ist ein langsamer Hash-Algorithmus von Vorteil, weil er die Zeit und damit den Aufwand extrem in die Höhe treibt. Salts tun das selbe für Wörterbuch Attacken und Rainbow-Tables.

Wenn man nun auf etwas sicheres Wechseln möchte ist es gar nicht so schwer. Man muss nicht die Passwörter der Benutzer vorliegen haben. Denn bei jedem Login liegt das Passwort für kurze Zeit in der Login-Methode sowie so als Klartext vor. Hier ist also der beste Punkt, um die Änderungen vorzunehmen. Es gibt nur eines dabei zu beachten.

Am Besten fügt man der User Entity ein Version-Flag hinzu, dass man verwendet um festzuhalten welche Hash-Variante gerade verwendet wird. 0 wäre dann einfaches MD5. Es sollte Integer sein, weil boolean einfach zu wenig ist und es mit der Zeit mehr als zwei Möglichkeiten für das Passwort geben wird... ich muss nochmal umbauen.
Wenn der Benutzer sich also einloggt und das Flag auf 0 steht, bedeutet es, dass man den Passwort-Eintrag in der Datenbank aktualisieren muss. Der Login muss dann eben alle möglichen Kombinationen aus Version Flag und Hash-Methode unterstützen. Flag und Hash-Methode immer zusammen, um alles noch sicher zu halten.. ob es ohne wirklich unsicher wäre, müsste man noch mal durch denken, aber verkehr es abzugleichen ist es sicher nicht.

Nun haben wir schon mal unseren neuen Hash, der gesetzt wird, sobald sich der Benutzer das nächste mal einloggt. Jetzt fehlt der Hash und dazu ist nicht viel zu sagen.

bbcode-image


NUR niemals den Benutzernamen als Salt verwenden! Denn das würde bedeuten, dass man bei einer Änderung des Benutzernamen auch immer den Passwort-Hash neu setzen müsste und wenn der Admin den Namen des Benutzers ändert, hat er das einfach nicht. Das Salt kann ein Zufallscode sein und mit in der Entity gespeichert werden, würde der Name ja auch und es geht ja nur darum das Berechnen der Hashes aufwendiger zu machen und nicht Security through obscurity zu betreiben. Hier muss ich auch noch mal nacharbeiten :-)

PHP7.0 installieren unter Linux (Ubuntu)

Ich habe mich dabei an http://tecadmin.net/install-php-7-on-ubuntu/ orientiert.

Unter Ubuntu < 16.04 PHP 7.0 zu installieren ist gar nicht schwer, wenn man erst einmal weiß, wie es geht. Man muss sich ein zusätzliches PPA einrichten und sonst nicht viel machen.


sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install -y php7.0


Damit ist PHP 7.0 an sich schon installiert. Das kann man sehen wenn die Version überprüft (immer die zuletzt installierte Version wird hier verwendet)


php -v


Wenn man nun eine Liste an Modulen haben will bekommt man diese so:


sudo apt-cache search php7-*


Wichtig ist, dass XDebug weiterhin unter php-xdebug zu finden ist und deswegen hier nicht in der Liste auftaucht. Also alles aus der Liste installieren was man braucht.


sudo apt-get install php7.0-mysql php7.0-json php7.0-xml php-xdebug


Nun muss PHP7.0 nur noch aktiviert werden. Ich gehe mal davon aus das momentan eine PHP5-Version aktiv ist.


sudo service apache2 stop
sudo a2dismod php5
sudo a2enmod php7.0
sudo service apache2 start


Danach ist der Apache wieder da und läuft mit PHP7.0

Wer ein aktuelles Linux Mint verwendet muss unter Umständen noch das PHP7.0 Apache Modul nach installieren und auch den ganzen Kleinkram.

Flexible Alternative zu Nested-Sets

Nested-Sets sind für normale Baumstrukturen super, aber wenn man etwas flexibler sein möchte und z.B. ein Item in mehreren Kategorien haben möchte oder eine Kategorie auch als Kind-Element von z.B. einer Angebots-Kampanie, ist man schon nicht mehr bei einem Baum sondern bei einem Netz. Nun hier Eltern-Elemente zu finden und zu wissen in welchen Kategorien ein Item sich befindet ist etwas aufwendiger.


CREATE TABLE exp_structure(
ID int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
NAME VARCHAR(255) NOT NULL,
TYPE VARCHAR(255) NOT NULL,
PRIMARY KEY(ID)
);

CREATE TABLE exp_links(
ID_PARENT int(11) UNSIGNED NOT NULL,
ID_CHILD int(11) UNSIGNED NOT NULL,
IS_SHADOW_LINK int(1) DEFAULT 0,
REFCOUNT int(1) DEFAULT 0,
PRIMARY KEY(ID_PARENT, ID_CHILD)
);


Damit man nun schnell herausfinden kann wird, beim Anlegen eines Items in der Struktur wird nicht nur ein Link auf das direkte Parent-Element gesetzt sondern werden auch rekursiv alle weiteren Parent-Element aufgerufen und ein Shadow-Link darauf gesetzt. Dieser Shadow-Link besagt, dass das Item nicht direkt am Parent-Element hängt sondern Subelement zugeordnet ist. In der Oberfläche sind mit Shadow-Links verlinkte Items also nicht anzuzeigen.
Ist ja erst einmal ganz einfach. Wenn ich nun aber z.B. ein Item mit 2 Parent-Elementen habe, muss man wenn man weiter nach oben in die Hierarchie kommt darauf achten, dass man nicht mehrere Shadow-Links setzt. Das ist an sich auch kein großes Problem. Schwierig wird wenn man ein Item entfernt und die Shadow-Links entfernen muss. Bei jedem Shadow-Link müsste man prüfen, ob er durch einen weiteren Pfad noch verwendet wird oder nicht. Dafür gibt die REFCOUNT... ja genau.. wie im Garbage Collector. Wenn man ein Shadow-Link setzten soll, dieser aber schon existiert zählt man Counter hoch. Beim Entfernen zählt man einfach alle Shadow-Links des Pfades runter und entfernt dann alle die auf 0 stehen, weil man dann sicher ist, dass dieser Shadow-Link nicht noch von einem anderen Pfad verwendet wird.
bbcode-image

Host-only Netzwerk mit VirtualBox erstellen

Gerade in Firmennetzwerken kann man nicht immer wie man gerade will eine VM ins Netzwerk hängen. Oft hat man aber Bedarf an einer VM. Gerade wenn man auf Windows entwickelt und am Ende auf Linux deployen soll, ist es immer gut eine Linux-VM zur Hand zu haben, um schnell selbst testen zu können, ob da noch alles läuft.
Auch fertige VMs wie die von Oracle mit einer fertig installierten Datenbank sind wirklich praktisch und können in vielen Situationen helfen.

Um jetzt aber einen eigenen Server in VM zu betreiben, von dem man vom Host aus zugreifen kann, aber kein anderer Rechner im Netzwerk diesen Server sehen kann, kann man in VirtualBox ein Host-only Netzwerk erstellen. Der Host ist Teil des Netzwerks, aber er Rest ist rein virtuell.

Beim einfachen Anlegen einer VM ist immer NAT voreingestellt.

bbcode-image


Zuerst muss man das Host-only Netzwerk erstellen.

bbcode-image


am Besten mit DHCP damit man sich nicht mit den IP-Adressen herum ärgern muss.

bbcode-image


Wenn man nun die VM wieder startet sieht man schon dass die IP sich geändert hat

bbcode-image


und man kann die VM von Host aus anpingen

bbcode-image

Java (EE) in Gefahr?

In den letzten Tagen liest man immer mehr, dass sich viele Sorgen um die Zukunft von Java und gerade um Java EE machen. Wie schon vorher bei JavaFX gilt auch hier immer der Vorwurf Oracle würde sich nicht genug einbringen und auf Fragen um die Zukunft nicht weiter äußern. Oracle ist leider nicht Sun und da sie keine Rechte an der API gegenüber Google mit Android geltend machen konnten, scheint wohl das Interesse noch Mals wieder gefallen zu sein.
Die nächsten Jahre wird man sich um Java sicher keine sorgen machen müssen. Java ist immer noch mit die wichtigste Plattform für Enterprise Entwicklungen und die angebotenen Lösungen sind sehr mächtig und nehmen einen vielen wichtigen Bereichen eine Position ein, bei denen man nicht einfach mal schnell eine andere Lösung einführen kann.

bbcode-image


Auch wenn Oracle selbst das Interesse verlieren sollte, gibt es immer noch genug eine große Mitspieler, die Java nicht so einfach sterben lassen würden. IBM, Apache und Red Hat sind die wichtigsten hierbei. So lange diese hinter Java stehen und Eclipse und Jetbrains entsprechende Entwicklungsumgebungen anbieten, werden sich viele sehr zurück halten auf etwas anderes umzusteigen und wo ein Markt ist werden auch Firmen sein, die diesen Markt bedienen. Wenn Oracle nicht mehr Teil dieses Marktes sein will, dann soll es eben so sein. Wichtige Entwicklungen wie Microservices und alternativen zu Node.js kamen am Ende ja auch nicht von Oracle sondern von anderen Anbietern. Oracle ist Besitzer von Java aber die Java-Welt wird meistens von anderen Bestimmt.

Aber ähnliches hat man auch lange über Zend gehört.. aber jetzt ist man bei PHP 7.0 und auch wenn es lange dauerte, zweifelt wohl niemand mehr an der Zukunft von PHP. Genau so wird es bei Java sein, es mag mal Zeiten geben wo es langsam voran geht, aber solange von Außen der Input bleibt wird es weiter gehen und am Ende ging es mit Java immer voran.. wenn auch zu vor schon oft eher langsam.
Im Serverbereich ist Java sehr stark und wird es sicher auch noch viele Jahre bleiben.

Heise.de: http://www.heise.de/newsticker/meldung/Analyse-Gibt-es-einen-Ausweg-aus-dem-Dilemma-um-Java-EE-3255563.html

Neo4j: reduce() zum Rechnen mit Collections

Wenn man noch einzelne Nodes oder Relations hat, kann man eine Summe schnell und einfach mit sum() berechnen. Wenn man aber schon eine Collection vorliegen hat oder komplexere Berechnungen ausführen möchte, hilft hier die
reduce() Funktion.
Die an sich wie eine kleine Schleife arbeitet und einen Ausdruck auf jedes
Element einer Collection ausführt.

Das man eine direkt eine Collection erhält, kann ganz schnell der Fall sein. Gerade wenn man mit variablen Path Längen arbeitet.


MATCH p = (start:entity{id:4})-[:relates_to*1..10]->(end:entity{id:100})
RETURN p


hier erhält man alle Relations bis zu einer Anzahl von 10, die einen Path zwischen start und end bilden.
Will man nun Gewichtungen an den Relations zusammen rechnen, damit nicht nur die Anzahl der Relations als Bewertung genutzt werden kann, kommt reduce() zum Einsatz.

Mit so einem Prinzip kann man auch reale Wege mit Meter-Angaben zwischen Stationen und Wegpunkten und Neo4j abbilden.


MATCH p = (start:entity{id:4})-[rels:relates_to*1..10]->(end:entity{id:100})
RETURN reduce(weight=0, r in rels) | weight + r.weight) AS total_weight

Older posts: