#CFCamp 2016 – Ich war da.

Dieses Jahr war ich das erste mal im CFCamp. Ich hab im Vorfeld schon einiges darüber gehört und die Leute sprachen mit Begeisterung darüber.

Also dieses Jahr 2016, war auch ich dort. Am Münchener Flughafen im municon.

Aufstehen in der Nacht -.- ist ja erstmal nichts für mich. Um 04:00 aufstehen, um 05:00 am Hauptbahnhof und von da aus nach Düsseldorf. 7:20 in den Flieger nach München.

Am Flughafen angekommen, mussten wir direkt ins municon, dort begann bereits um 09:00 Uhr die Preside Conference. Diese ging einen Tag lang und alles darüber findet ihr im entsprechenden Blog Eintrag.

Am 20.10 fing das CFCamp um 09:00 Uhr an. Eröffnet wurde das Camp mit der Keynode von Lucee.

Es gab zwei große Räume mit jeweils einem einstündlichen Vortrag. So hatte man den ganzen Tag die Wahl welchen Beitrag man sich anhören möchte. Ich hab mich für die Vorträge entschieden die in den kommenden Tagen hier in meinem Blog veröffentlicht werden.

14711495_1254615277932964_6338856323884856260_o

Sehr interessant fand ich das die Teilnehmer im CFCamp zum größten Teil Wiederholungstäter sind und die ganze Veranstaltung so ein sehr freundschaftlichen flair hat. An den zwei Tagen waren ca 170 Teilnehmer anwesend, darunter hauptsächlich Coldfusion Entwickler.

Am Abend gab es dann noch einen Umtrunk mit CodeWar und viel Spass.

Mein Fazit: Eine interessante Veranstaltung mit guten Inhalten. Neben den Coldfusion Inhalten gab es auch noch interessante Themen rund um die Entwicklung.

Vielleicht könnte man in Zukunft das ganze noch über Youtube und / oder LiveCoding.tv streamen. Oder zumindest die Vorträge im nachhinein als Video Material veröffentlichen.

Das Essen im municon ist übrigens hervorragend, wie ich finde.

Ich hoffe ihr findet die kommenden Beiträge genau so interessant wie Ich.

Die Veranstaltung wurde organisiert von:

bluegras – Internetlösungen
Michael Hnat

Kriegerstr. 49
82110 Germering
Tel. +49 (0)89 81029340

E-Mail: m.hnat@bluegras.de

ColdFusion ORM MySQL Mapping

ORMTYPE SQL MYSQL
big_decimal DECIMAL, MONEY DECIMAL
binary BINARY, VARBINARY TINYBLOB
blob TINYBLOB
Boolean [SMALLINT], BIT BIT
clob LONGTEXT
date DATE DATE
double DOUBLE, MONEY, NUMERIC DOUBLE
character, char CHAR
float REAL, FLOAT FLOAT
integer, int INT INT
long BIGINT BIGINT
serializable TINYBLOB
short SMALLINT SMALLINT
string CHAR, NCHAR, VARCHAR, NVARCHAR VARCHAR
text TEXT, NTEXT LONGTEXT
timestamp DATETIME, SMALLDATETIME, TIMESTAMP DATETIME
true_false CHAR
yes_no CHAR

Continuous Deployment Mit Docker Containern

Ein neues  Projekt steht an und ich bin schon Feuer und Flamme.

Als Dienstleister im Webbereich hat das Unternehmen in dem ich arbeite einige Produkte die stehts weiter entwickelt werden. Dazu kommen einige Customer Applikationen die einige Schnittpunkte zu Produkten haben jedoch mit vielen speziellen Erweiterungen daher kommen.

Ziel des Projektes ist es die bestehenden Produkte in Docker Container auszulagern. Und diese vom Arbeitsplatz über den Entwicklungsserver auf das Staging auszuliefern und diese dann ins Produktionssystem zu spielen. Wärend der Testserver und Staging Server inHouse Lösungen sind wird ein weiterer Meilenstein sein, das Produktionssystem in die Cloud zu legen.

Das kleinste Problem dürften die in sich geschlossenen Produkte sein, die Herrausvorderung ist das Content Management System. Bis vor kurzen war die Abhängigkeit an die Lokale Produktionsumgebung so tief das ein Auslagern kaum möglich waren. Hier wurden bereits einige Stunden investiert um die Enterprise Version von Abhängigkeiten zu befreien und Cloudfähig zu machen.

Bevor es aber nun los gehen kann müssen zwei Grundlegende Dinge eingeführt werden.

Zum einem die Versionierung.. ja die gibt es nicht so wirklich. Es sind zwar bei einigen Produkten „version“ 2 und 3 vorhanden aber das ist auch nicht mehr als ein Name. es gibt keine Major , Features und Patch Versionen. Dementsprechend auch keine Notes dazu. Zwar Neugikeiten über Änderungen aber alles sehr schwammig.

Zum anderen Unittests. Es gibt zwar einige die für den Entwickler Informationen bereitstellen aber sind nicht wirklich Programmfreundlich gestalltet. Zudem fehlen diese Tests in vielen kritischen Bereich. Ohne diese wird ein automatisches Continouse Deploymend aber ehr ein Ammoklauf.

Weiteres folgt im Laufe der Woche. Einfach dem Block folgen.

Railo & Amazon EC2 Instanzen

Vor einiger Zeit habe ich mich mit der „on the Fly installation“ von Railo auf einer Amazon EC2 instanze beschäftigt. Dabei habe ich viele Ansätze für ein einfaches Setup gefunden, leider entsprach nichts davon meinen Vorstellungen.

Bei meinen Recherchen bemerkte ich, dass man einfach ein shell Script als UserData übergeben kann… endlose Möglichkeiten tun sich da auf.

Dabei bin ich auch über das railo_ec2 shell Script von @Amaroom gestolpert. Da die Version ein etwas altes Railo Paket installiert habe ich das Script kurzerhand geforkt und aktualisiert. Zu finden ist das ganze auf Github.com

Auch wenn sich das Script von selbst erklärt vielleicht ein paar Kommentare:

Der erste Befehl führt ein upgrade aus, so das die aws Linux Version auf dem neusten Stand gebracht wird.

Anschließend wird tomcat7 und git installiert und tomcat in den „autostart“ gepackt.

Nun wird das aktuelle Railo mit Curl gezogen und in den vorbereiteten Ordner verschoben und mit den Tomcat user und der Tomcat Gruppe versehen.

ab Zeile 43 wird ein wenig die Tomcat catalina config geändert. Hier werden der Pfad zu Railo gesetzt sowie mapping und welcome file definiert.

Zum Abschluss wird noch, zu demozwecken, eine index.cfm angelegt und tomcat gestartet.

Ab hier hat man nun frei Hand. Anstelle der index.cfm kann nun mit git clone ein Repositorie gezogen werden und in den webapps/ROOT ordner gelegt werden.
Ein Beispiel wäre:

git clone https://github.com/TiagoReis-Webdevit/demoCMS.git  /usr/share/tomcat7/webapps/ROOT

chown -R tomcat.tomcat /usr/share/tomcat7/webapps/ROOT/

um das TiagoReis demoCMS zu installieren.

Um sich den Ärger mit nicht gesetzten Passwörtern im Web-Admin zu ersparen kann eine entsprechend vorkonfigurierte railo-web.xml.cfm in den Ordner /usr/share/tomcat7/webapps/ROOT/WEB-INF/railo/ geladen werden.

Alternative und von mir bevorzugt kann auch eine server.xml, in der Serverpasswort und defaul web admin Passwort bereits gesetzt sind, in das Verzeichnis /usr/share/tomcat7/railo4/railo-server/context/ kopiert werden.
Vor dem ersten Aufruf des Railo Admins existiert dieser Ordner nicht und muss entsprechen mit mkdir angelegt werden.

Dort können auch Datenbanken und Mail Server installiert werden. Natürlich bietet sich hier auch die Nutzung der aws Dienste an. Ein awsWrapper ist hier zu finden, der ist etwas verbugt aber anpassbar. Ansonsten schreibe ich grad einen Wrapper der hier zu finden ist.

Und schon können x Passwort gesicherte Railo Instanzen mit einem Git Projekt gestartet werden. Um ein Update der Application auf die Server zu spielen braucht man nur noch alles ins git zu pushen und die neue Instanzen des alten Servers starten, nicht vergessen die alten zu terminieren. Mit einer AutoScalling Group benötigt man nur noch die terminierung der Instanzen.

Schnittstelle zertifiziert

Nach gut 4 Wochen Arbeit wurde nun die Schnittstelle zum Webportal HRS offiziell zertifiziert und wird nun unter den Channel Managern gelistet.

Besonders freut mich, das dies direkt im ersten Anlauf geklappt hat und auf ein „Recall“ verzichtet wird.

Größte Hürde in diesem Interface war nicht die unbedingt die Splittung der verschiedenen Raten, Kategorien und Aufpreis beziehungsweise Abschlag auf Standard Raten. Die eigentliche Schnittstellen Funktionalität ist im Grunde Übersichtlich jedoch teilweise mit verwirrender Logik versehen.

Die Rückführung der Reservierungen war jedoch in meinem Fall die größte Herausforderung. Die Informationen der Reservierungen, gebuchte Raten und Auf-/Abschläge werden gesplittet gelistet und müssen erst wieder zusammengefügt werden um diese dann mit dem im System gemappten werten zu verbinden.

Dies beruht darauf das zum Beispiel Raten Typen auch erst zur Laufzeit der Daten Auslieferung dynamisch gewählt werden diese aber natürlich in den Reservierungen zurück geliefert werden.

Sicherlich sind noch ein paar Dinge Verbesserungswürdig aber „Done is better than perfekt“

Mantis SOAP API Teil 1 Issue Get and Add

Zur Zeit entwickel ich einen WebService der zwischen Mantis und Zendesk Tickets und Kommentare synchronisiert.
Klingt etwas spektakulär, ist im Grunde aber eine Simple Sache wenn nicht immer alles nicht funktionieren würde.

Die Mantis SOAP Api:

Wenn es nach mir ginge würde da eine REST Api hinterstecken aber gut es geht aber nicht nach mir.

Mir ist aufgefallen das es keine wirklich schöne Dokumentation der Mantis Api geht.
Die Nerds unter Euch denken wahrscheinlich: „docu? … wtf … steht alles in der wsdl“ aber das lesen der wsdl ist auch nicht jedermanns Sache.

Da ich ein fauler Programmierer bin, hab ich mir natürlich nicht die Arbeit gemacht, die Komponenten, Verknüpfungen und den Restlichen Firlefanz selbst zu schreiben.
Hierfür hab ich meiner  Request Komponente einfach eine Methode gegeben die aus dem ganzen WSDL Kram die Klassen und Modele erstellt und sich selbst der Komponente erweitert.

Wunder Bärchen.

Grob sähe dass dann so aus.


function parseXml(xml)
{
httpService = new http();
httpService.setMethod('GET');
httpService.setTimeOut(10);
httpService.setUrl( 'http://www.mantisbt.org/bugs/api/soap/mantisconnect.php?wsdl');
result = httpService.send().getPrefix();
xmlfile = xmlparse(result.filecontent); //Parses the XML

//dump(var="#xmlfile.XmlRoot#",label="dump",format="html",abort=true);
strComponent = 'component {';
if(structKeyExists(xmlfile.XmlRoot, "XmlChildren"))
{
for(node in xmlfile.XmlRoot.XmlChildren)
{
switch(node.xmlName){
//dump(var="#node#",label="dump",format="html",abort=false);
case 'message':
if(structKeyExists(node, "XmlAttributes"))
{
strComponent &= chr(13) & chr(10) &'public function ' & node.XmlAttributes.name;
strComponent &= '(';
paramArray = [];
for(strParam in node.XmlChildren)
{
if(structKeyExists(strParam, "XmlAttributes") && strParam.XmlAttributes.name !='return')
ArrayAppend(paramArray, strParam.XmlAttributes.name);
}
if(arrayLen(paramArray))
strComponent &= arraytolist(paramArray);
strComponent &= ')'& chr(13) & chr(10) &'{'&chr(10)&chr(13);
for(strParam in node.XmlChildren)
{
if(structKeyExists(strParam, "XmlAttributes") && strParam.XmlAttributes.name !='return')
strComponent &= chr(9)&'param name="' & strParam.XmlAttributes.name & '" type="' & Mid(strParam.XmlAttributes.type,5,len(strParam.XmlAttributes.type)-3) & '";'&chr(10)&chr(13);
}
}
strComponent &= '}'&chr(10)&chr(13);

break;
case 'types':
for(comps in node.XmlChildren[1].XmlChildren)
{
if(structKeyExists(comps, "XmlAttributes"))
{
if(comps.xmlName == 'xsd:complexType')
{
newComp ='component ' & comps.XmlAttributes.name &chr(10)&chr(13)& ' {'&chr(10)&chr(13);
for(strParam in comps.XmlChildren)
{
for(strP in strParam.XmlChildren)
{
if(structKeyExists(strP, "XmlAttributes"))
if(structKeyExists(strP.XmlAttributes, "name"))
newComp &= chr(9)&'property name="' & strP.XmlAttributes.name & '" type="' & Mid(strP.XmlAttributes.type,5,len(strP.XmlAttributes.type)-3) & '";'&chr(10)&chr(13);
}
}
newComp &= "function toXML()
{
data = getMetaData(this);
xml = '';
for (prop in data.properties)
{
xml &= '<'&prop.name&'>';
switch(prop.type)
{
case 'string':
if(structKeyExists(this, prop.name))
xml &=this[prop.name];
break;
case 'dateTime':
if(structKeyExists(this, prop.name))
xml &=this[prop.name];
break;
case 'boolean':
if(structKeyExists(this, prop.name))
xml &=this[prop.name];
break;
case 'integer':
if(structKeyExists(this, prop.name))
xml &=this[prop.name];
break;
default:
if(refind('Array',prop.name))
{
if(structKeyExists(this, prop.name))
xml &= arrayToList(this[prop.name]);
}
else
{
Comp = createObject(prop.type);
Comp.toXml();
}
break;
}
xml &='';
}
return xml;
}";
newComp &= '}';
FileWrite(comps.XmlAttributes.name&'.cfc',newComp);
}
}
}
break;
}
}
}
strComponent &= '}'&chr(10)&chr(13);
FileWrite('mantis.cfc',strComponent);
//dump(var="#strComponent#",label="dump",format="html",abort=true);
}

MEMO (an mich): Ich brauch hier im Blog mal einen ordentlichen Code Parser -.-

Gut dann hab ich alles was ich benötige zur Hand und kann die Model dem Manger geben.

Die wichtigsten Methoden möchte ich hier einmal aufführen:

Diese Methode holt sich den Eintrag der übergebenden ID

public function issue_get(issue_id)
{
param name="issue_id" type="number";

return '<mc_issue_get>'
& '<username>'
& this.username
& '</username>'
& '<password>'
& this.password
& '</password>'
& '<issue_id>'
& issue_id
& '</issue_id>'
& '</mc_issue_get>';
}

Diese Methode erstellt einen neuen Eintrag.
issue._toString() ist eine von mir überschriebene Methode die mir aus den erstellten Modellen sauberes XML zurückliefert um es einfach an die Api zu schicken.


public function issue_add(issue)
{
param name="issue" type="IssueData";

xmlData = ''
& ''
& this.username
& ''
& ''
& this.password
& ''
& ''
& issue._toString()
& ''
& '';
return xmlData;
}

Coldfusion: Klasse erstelllen

Der erste Versuch einer eigenen Klasse war gestern tatsächlich erfolgreich.

Versuchsweise habe ich eine Film.cfc erstellt.
Definiert wird eine neue Komponente / component wie folgt:

<cfscript>
component
{
// hier Parameter und Funktionen
}
</cfscript>

Parameter definieren:

property type=“string“ name=“MovieTitle“ default=““;

Eine Liste der Möglichen Types:

@Quelle: Adobe ColdFusion

ORM data types

You can use any of the following ORM data types for CFCs:

  • string
  • character
  • char
  • short
  • integer
  • int
  • long
  • big_decimal
  • float
  • double
  • Boolean
  • yes_no
  • true_false
  • text
  • date
  • timestamp
  • binary
  • serializable
  • blob
  • clob

Funktionen definieren:

public function getMovieTitel()
{
return this.MovieTitle;
}

public function setMovieTitel(sMovieTitle)
{
this.MovieTitle = sMovieTitle;
}

Constructor definieren

public function init()
{
this.MovieUid = createUUID();
return this;
}

Die Film.cfc hab ich in meinem Projekt im Unterordner App gespeichert.
Um nun meine neue Klasse verwenden zu können kann ich diese wie folgt initialisieren.

<cfscript>
Movie = new App.Film();
</cfscript>

Nun wird´s coldfusion

Da ich nun einen neuen Job angenommen habe, gibt es direkt ein neues Thema über das ich schreiben kann. Müller goe’s ColdFusion.

In den nächsten Wochen werde ich mich in ColdFusion einarbeiten und mich tiefgehend mit der Materie beschäftigen. Der erste Eindruck: „Warum zur Hölle hab ich mich solange mit PHP rumgeschlagen?“.

Das sagt Wikipedia über Coldfusion:

ColdFusion ist eine für Web-basierte Scriptsprache und Datenbank-Anwendungen konzipierte Middleware des Software-Herstellers Adobe Systems, die grundlegend aus den folgenden drei Teilen besteht:

ColdFusion Application Server (dem ersten Application Server der Welt)

ColdFusion Markup Language (CFML, eine Skriptsprache, die es ermöglicht, serverseitige Applikationen zu programmieren)

geeignete Entwicklungsumgebungen (wie zum Beispiel Eclipse oder Dreamweaver)

ColdFusion steht dabei in direkter Konkurrenz zu vergleichbaren serverseitigen Systemen wie ASP.NET, JSP/Servlet, Ruby on Rails (RoR), ZOPE (Python), Perl und PHP. Im Gegensatz zu Skriptsprachen wie Perl, PHP, Python und Ruby, die Open Source sind, ist die Originalversion von ColdFusion nicht im Quellcode verfügbar.

Quelle: http://de.wikipedia.org/wiki/ColdFusion

Und tatsächlich scheinen einem Tags die arbeit zu vereinfache.
Ein Beispiel worüber ich heute gelesen habe war das <cfquery >SELECT * FROM table</cfquery> Tag. Und ja es übernimmt tatsächlich die Datenbank Angelegenheiten.

Und der erste Eindruck scheint zu bestätigen dass ColdFusion tatsächlich sehr gut geeignet ist schnell Webapplikationen zu erstellen und dabei einfach im Einstieg zu sein.

Mehr dazu wird von mir hier die nächsten Tage folgen.

Hier noch ein Link zur Dokumentation von Adobe.
http://www.adobe.com/support/documentation/en/coldfusion/