Keeping your configuration and data in Subversion
Auch die Konfiguration des Build-Servers selber sollte man sichern.
Jul 28
Gepostet von knalli in Empfehlungen, Entwicklung, Konfiguration, Technik | Keine Kommentare
Keeping your configuration and data in Subversion
Auch die Konfiguration des Build-Servers selber sollte man sichern.
Jul 6
Gepostet von knalli in Eclipse, Empfehlungen, Entwicklung, Java, Technik, Tutorial | Keine Kommentare
Für diesen Artikel setze ich jetzt einfach mal voraus, dass die Begriffe und Technologien hinter Java, Maven, Repository, Eclipse und Tomcat bekannt und geläufig sind. Und nein, jeweiliger Profi muss man zum Verständnis nicht sein.
An ein firmeneigenes Repository — oder auch: corporate repository — gelten besondere Anforderungen. Diese können bei einem “einfach privat-eigenen” verändert werden, aber man kommt meistens auf folgende Punkte:
Für Punkt zwei spricht auch eine wesentlich einfachere Konfiguration der Clients (Entwicklerprofile), da nur noch ein Repository eingetragen werden muss. Alle “bekannten” Repositories werden zentral gebündelt, damit schwindet natürlich gleichzeitig die “Freiheit” des einzelnen Entwicklers, andere “unbekannte” Repositories zu verwenden. Dies ist jedoch vernachlässigbar, weil: Diese “Freiheit” schränkt im Endeffekt den Buildprozess und auch die Wiederverwendbarkeit ein. Das Hinzufügen von weiteren Repositories in die POM ist aus Gründen der Versionisierung und Nachhaltigkeit auch keine optimale Lösung. Dennoch, alles nur eine Sache der Konfigurations der Clients.
Es gibt eine Reihe von Repository-Managern, die allesamt viel können. Die Wahl auf Nexus fällt hier aus folgenden Gründen:
Eine umfangreiche Online-Dokumentation ist auf der Nexus-Seite zu finden.
Nexus wird unter anderem als WAR ausgeliefert, insofern die Installation in einen Tomcat ein leichtes ist. Beachtenswert ist dabei nur, dass Nexus ein Verzeichnis ~/sonatype-work erstellt. Da sich dort unter Umständen viele Nutzdaten ansammeln, kann ein Verschieben (symbolischer Link?) nicht verkehrt sein. Da sich mit der Laufe der Zeit einiges an Daten ansammeln kann, sollte der Platz nicht zu sparsam vermessen sein.
Nachdem Tomcat bzw. Nexus gestartet ist, kann man sich mit dem Default-Daten admin/admin123 anmelden (analog mit den Daten der anderen beiden Benutzern!).
Nexus kommt bereits mit einer Reihen von vorkonfigurierten, eigenen hosted repositories einher.
Daneben gibt es so genannte proxy repositories, die praktisch gesehen nur aus einem Index bestehen. Wie ein Proxy hängen sie sich zwischen dem Client und dem tatsächlichen Repository und cachen alle Artifakte lokal. Selbst der Index ist mehrere Megabytes groß, das sollte man nicht vernachlässigen. Voreingetragene proxy repositories sind Apache Snapshots, Codehaus Snapshots, Central Maven Repository (Maven1/Maven2-Repository-Konverter sind in Nexus vorhanden a.k.a. virtual repositories).
Die grouped repositories sind auch rein virtuelle Gruppierungen von verschiedenen Repositories. Das Standard Repository “Public” ist in der einfachsten Konfiguration eine Sammlung aller (aktivierten) Repositories auf dem Manager — also sowohl der externen Spiegel, der Third-Parties als auch den eigenen Artifakten.
Die Aktivierung und Verwaltung von (neuen) Repositories ist abhängig der eigenen Bedürfnisse. Meistens sinnvoll ist es jedoch, bei den drei großen Spiegeln (proxy repositories) in dem Konfigurationstab das Indizieren (Download Remote Indexes) zu aktivieren. Je nach Belieben kann man in der Gruppe Administration auch das Aktualisierungsverhalten steuern.
Um ein Deployment zu gewährleisten, muss man nebst Kenntnis der Repository-URL (eben die URL) nur wissen, ob der anonyme Zugriff erlaubt sein soll, oder ob man einen Deployment-Benutzer einrichten und nutzen willst. Falls eine Richtlinie vorschreiben sollte, dass dies nur ein Build-Agent machen darf, ist ein (geheimes) Passwort oder Schlüssel unabdingbar.
Nehmen wir an, der Nexus-Manager ist auf dem Host 192.168.0.10:8080/nexus installiert. In der einfachen Installation und Konfiguration sammeln sich im public repository praktisch alle relevanten Artifakte (sowohl Releases als auch Snapshots).
<settings> <mirrors> <mirror> <id>corporate</id> <name>Corporate Repository</name> <url>http://192.168.0.10:8080/nexus/content/groups/public</url> <mirrorOf>*</mirrorOf> </mirror> </mirrors> </settings>
Der Deployment-User benötigt ggf. Zugangsdaten für das entsprechende Repository.
Ein Client wie m2eclipse sollte danach einen kompletten Rebuild des Index machen.
Jun 3
Gepostet von knalli in Entwicklung, Java, Kurz notiert, Technik | Keine Kommentare
Der dritte Release Candidate von Eclipse 3.6 alias Helios wurde vor wenigen Tagen bereitgestellt – man kann wohl davon ausgehen, das dem baldigen Release Juni/Juli nicht mehr viel im Weg steht.
Damit reiht sich nun ein weiterer Jupitermond in die Reihe der 3.x-Releases ein: besser, umfangreicher, aktueller.
Auf dem ersten Blick sieht Eclipse wie immer aus. Zwar wurde der Welcome-Screen, wie immer, in Punkto Design und Content geändert.. aber ansonsten ist alles wie gehabt.
Zwecks des kleinen Reviews habe ich die 64-Bit-Version (Cocoa) für Mac OS X heruntergeladen; da ich aber auch noch eine Reihe von Plugins benötige, diese dann später nachinstalliert. Prinzipiell hat sich der Updatemanager zumindestens optisch nicht zum Vorgänger geändert. Immerhin: Mit schätzungsweise 50 Einzelplugins ist der Installationsvorgang erstmalig in meiner persönlichen Eclipse-Geschichte problemlos von statten gegangen – sonst hat es immer irgendwo ein bisschen geknallt. Manchmal mit, meist ohne Auswirkungen. Unter anderem war auch ein SVN Connector Plugin dabei.
Es sieht so aus, als wäre in Eclipse kein VCS-Plugin (mehr) enthalten, vielmehr wird dies durch den Connector (ggf. bekannt aus 3.5) bekannt. Nach dem obligatorischen Neustart wird man sofort vom Connector-Wizard begrüßt und kann zwischen verschiedenen HavaHL und SVNKit-Versionen wählen. Ausgewählt, installiert, neugestartet. Fertig. Import, From SVN.. und voilá. Projekt ist drin. Interessant: Neuerdings wird man informiert, dass man gespeicherte Passwörter (SVN-Dialog) mittels Passphrasen absichern kann.
Ich habe mich im Vorfeld noch nicht mit den Änderungen und Neuerungen von Helios auseinandergesetzt, daher stochere ich etwas herum. Augenfällige Änderung: Die Eigenschaftsfenster einer Dateiressource wurden um eine detaillierte Rechte-Verwaltung erweitert.
Aha… Resources können jetzt endlich gefiltert in einem Projekt eingefügt werden. Soll heißen: Man kann nicht nur weitere Resourcen dazu linken sondern auch explizit welche ausschließen. Yes!
Der Produktiveinsatz in den nächsten Wochen wird zeigen, was es sonst noch gibt.
Apr 29
Gepostet von knalli in Empfehlungen, Entwicklung, Java, Technik | Keine Kommentare
Die Java Reflection API ist Bestandteil des JDK und ermöglicht den Zugriff auf Methoden, Felder und Annotationen von Klassen und Objekte, also den Instanzen von Klassen. Mit Ausnahme von Annotationen geschieht der Zugriff immer auf einer Meta-Ebene.
Mit einem einfachen Beispiel ist diese Meta-Ebene erklärt.
class Foo {
private String bar = "private value";
}
Stellen wir uns vor, wir wollen ganz exemplarisch von dem Objekt foo (foo = new Foo())den Inhalt von dem Feld bar erhalten. Auf dem üblichen Weg ist das nicht möglich, da das Feld ein privates ist.
Über den zugehörigen Klassentyp (via getClass()) stellt Java eine Reihe von Methoden aus dem Reflection-Paket zur Verfügung, u.a. auch Field getDeclaredField(String). Ein declared field ist ein Instanzattribut eines Objektes, während ein field (Field getField(String)) statische Felder finden.
Field field = foo.getClass().getDeclaredField('bar');
Die Variable field enthält aber – wie man dem Typ entnehmen kann – aber nicht den Inhalt von bar, sondern ein Field-Objekt. Um an den Inhalt zu kommen, verwendet man die Methode get(Object). Der Parameter bezeichnet den entsprechenden Kontext, also das Objekt foo von weiter oben.
Object value = field.get(foo);
Das bedeutet im Klartext: Auch für eine weitere Instanz der Klasse Foo (etwa foo2) kann dieses Field für dieses Feld verwendet werden. Es beinhaltet nur die Metainformationen, nicht die eigentlichen Inhalte.
Dabei ist jedoch zu beachten, dass der SecurityManager aktiv werden kann; in diesem Falle wird eine Exception bei get(Object) geschmissen, weil das Feld nicht sichtbar ist.
field.setAccessible(true);
schafft dabei Abhilfe.
Im Prinzip funktioniert das Schema bei Methoden genauso – aber bevor ich jetzt einen Radio Eriwan-Witz loslasse…
Im Gegensatz zu den vorherigen Feldern werden Methoden nicht nur über den Namen, sondern auch über die Parametertypen identifiziert (daher können Methoden sich vom Namen her in Java auch “überladen”).
class Bar {
private String name;
String getName() {
return name;
}
String getName(String defaultName) {
return (name == null) ? defaultName : name;
}
}
Die Metainformationen werden entsprechenderweise geladen:
Method method1 = bar.getClass().getDeclaredMethod("getName");
Method method2 = bar.getClass().getDeclaredMethod("getName", String.class);
Selbstverständlich ist bei Kenntnisnahme der Klasse auch folgende Zeile gleichwertend:
Method method1 = Bar.class.getDeclaredMethod("getName");
Methoden haben im Gegensatz zu Feldern keinen “Inhalt”, sondern sind eine Aktivität oder Operation — und zwar auf einem Objekt. Dementsprechend funktioniert das Ausführen mittels der Method Object invoke(Object, Object…args):
Object result1 = method1.invoke(bar); // getName()
Object result2 = method2.invoke(bar, "default name"); // getName("defaultName")
Annotationen sind “Anmerkungen” im Quellcode, und seit Java 5 fester Bestandteil des JDKs. Technisch gesehen sind Annotationen besondere Klassen mit eingeschränkten (Java-) Möglichkeiten, deren Instanz auf einem Meta-Attribut wie Klasse, Feld, Methode oder Methodenparameter “hängen”. Mit anderen Worten bedeutet dass, dass man mittels Reflection tatsächlich eine Instanz einer Annotation erhält — allerdings mittels einem Proxy (aus der Java API).
@Entity
class Account {
@Column(name="id_x")
private Long id;
}
Die Methode getAnnotation(Class) existiert in allen Typen: Class, Field und Method.
Account account = new Account();
Entity annotation1 = Account.class.getAnnotation(Entity.class).annotationType();
Column annotation2 = Account.class.getDeclaredField("id").getAnnotation(Column.class).annotationType();
Assert.assertEquals("id_x", annotation2.name());
Im Regelfall benötigt man keinen Zugriff auf Reflection und sollte es vermeiden. Nichtsdestotrotz gestalten sich Konfigurationen, welche auf Basis von Annotationen, meist als sehr einfach, simpel und vor allem Code-konzentriert. Das JPA-Mapping (etwa mit Hilfe von Hibernate) gestaltet sich via Annotationen wesentlich einfacher, schneller und schlanker als mit XML.
Jeder Zugriff über die Reflection API kostet Zeit. Für Konfigurationen und Pläne ist das meist nebensächlich; die JPA-Konfiguration wird beim Start der Applikation eingelesen, analysiert und gespeichert. Nebenbei profitiert das natürlich von der anfänglichen “Warmup-Phase”.
Besteht jedoch ein Access on Demand, so sollte man sich Gedanken um eine geeignete Cachestruktur machen. Wichtig ist dabei, die Metadaten von den eigentlichen Inhalten zu trennen.
Jeder der oben genannten Reflection-Getter gibt es auch jeweils eine getAll-Variante: Class.getDeclaredFields(),Class.getDeclaredMethods(), Class.getAnnotations(), Field.getAnnotations() und Method.getAnnotations().
Mit einem einfachen Algorithmus kann man die Laufzeit drastisch senken, wenn Objekte des gleichen Typs mittels Reflection untersucht werden.
public class CacheReflectionUtil {
// cache of declared fields of class types
private final Map<Class<?>, Field[]> classDeclaredFields = new HashMap<>();
// Return the declared fields of the given class type.
public Field[] getDeclaredFields(Class<?> type) {
Field[] fields = classDeclaredFields.get(type);
if (fields == null) {
fields = type.getDeclaredFields();
classDeclaredFields.put(type, fields);
ensureAccessibility(fields);
}
return fields;
}
// Ensure that the given fields are accessible.
public void ensureAccessibility(Field[] fields) {
for (Field field : fields) {
// setAccessible will not only set a property but invoke SecurityManager stuff
if (field.isAccessible()) {
field.setAccessible(true);
}
}
}
// Return the declared field of the given class type.
public Field getDeclaredField(Class<?> type, String name) {
for (Field field : getDeclaredFields(type)) {
if (field.getName().equals(name)) {
return field;
}
}
return null;
}
}
Um einen stetigen Speicherverbrauch zu verhindern, empfiehlt sich das Nutzen einer Least-Recently-Used-Struktur. Das Apache-Commons-Paket bietet dies etwa mit der LRUMap an.
Apr 28
Gepostet von knalli in Entwicklung, Java, Kurz notiert, Spring, Technik, Tipps | 1 Kommentar
Bei Spring ist die globale Einheit in der Konfiguration der so genannte ApplicationContext. Dieser Context ist etwa ein Container im Applicationserver (beispielsweise web.xml). Soweit so gut.
Tatsächlich ist der WebApplicationContext eine Spezialisierung des oben genannten ApplicationContext — und zuständig für Webanwendungen. Da ein Servlet die Steuerung im Applicationserver übernimmt, benötigt der Spring-Context ein DispatcherServlet. Damit ist die “Verbindung” User->Server->Spring geschaffen. Soweit so gut.
Konfiguriert man das DispatcherServlet etwa – sinnigerweise – mit dem Namen”dispatcher”, dann sucht Spring standardgemäß nach einer dispatcher-servlet.xml. Diese XML-Konfigurationsdatei kann ähnlich der applicationContext.xml (u.ä.) ganz normale Bean-Konfigurationen enthalten. Interessant ist dabei, dass dabei ein zusätzlicher ServletContext erstellt wird. Das hat zwei Auswirkungen:
Apr 8
Gepostet von knalli in Entwicklung, Technik, Tipps, Web | Keine Kommentare
Für Webapps, also HTML-Seiten, gibt in speziellen Sitationen wie Loginformulare Problemen mit der Autovervollständigung bzw. -korrektur des iPhone OS.
Für input-Tags gibt es neben dem Attribut autocomplete=”off” (unterstützt bspw. durch den Firefox) noch zwei weitere Attribute:
Alle drei Attribute zusammen schalten auf iPhone/iPad/iPad sämtliche Korrekturvorschläge ab.
Jan 25
Gepostet von knalli in Java, Konfiguration, Spring, Technik, Technologie/IT, Tipps | Keine Kommentare
Mit dem Majorrelease 3.0 wurde dem Modul Spring Security eine Menge von neuen Features angeignet. Spring Security ist die Modulkomposition, welches für das Java Framework Spring quasi die gesamte Authentifizierung, Autorisierung, Legitimierung jedwegiger Art ermöglicht.![]()
Leider wurden mit dem Release 2.x auf 3.0 eine Reihe von API-Changes vollzogen. Zugegeben, die waren auch sicher alle sinnvoll, weil Komponenten wie die Authentifizierung weiter geteilt wurden und man somit wesentlich flexibler ist, neue Anforderungen zu ermöglichen (Baukastenprinzip). Aber die Dokumentation ist – gesamtheitlich betrachtet – irgendwie immer noch mies und oft nicht aktualisiert. Oder man findet im Internet einfach nur (alte) Beispiele.

Im Namespace von Spring Security existiert das Tagelement http, mit welchem man kurze, knappe und verständliche Konfigurationen anlegen kann. Der Vorteil liegt klar auf der Hand: Man muss nicht alle Beans, Listener und Provider anlegen, denn das geschieht automatisch. Tja, wären da nicht ein paar Einschränkungen in der Funktionsvielfalt.
Just wurde das Minor-Release 3.0.1 veröffentlicht, und nur wenige Tage später zu erfahren, dass Remember Me kaputt sei. Egal, fahren wir erstmal weiter mit 3.0.0.
Laut Dokumentation ist es am einfachsten, wenn man die Direktive remember-me (Security Namespace) innerhalb der http-Direktive (Security Namespace) verwendet. Ohne irgendeine Angabe wird ein stinknormales, Cookie basiertes Tokenverfahren ohne (echten) privaten Schlüssel verwendet. Reicht für den ersten Einsatz erstmal auf, soll ja erstmal funktionieren.
Fehlermöglichkeit 1a: Man loggt sich ein, und es passiert nichts (kein “RememberMe”-Cookie).
Lösung: Wenn man einen eigenen Auth-Filter einsetzt, muss man diesem auch den RememberMe-Service “setten”. Außerdem muss der SecurityChainFilter (web.xml!) auch auf die login-Seite verweisen. Es dürfen auch keine Filter bei der Konfigurierung von intercepted Urls (speziell hier: login, logout) gemacht werden.
Fehlermöglichkeit 1b: Es passiert noch immer nichts?
Lösung: Vielleicht wurde vergessen, einen Parameternamen für den Request zu setzen. Der Standardname ist ein typischer Springname, der natürlich unschön ist. Und den kann man nicht über die RememberMe-Direktive setzen, also muss man eh einen eigenen Service definieren. Bäm. Referenzierung geht dann zwar noch, aber für mehr ist die RememberMe-Direktive dann nicht mehr zu gebrauchen.
Fehlermöglichkeit 2a: Man besucht die Seite ohne Login, aber mit Cookie – und die Loginseite kommt (Log sagt kein gültiger Auth).
Lösung: Man kann der Log trauen, wenn sie zwar beim Einloggen nun einen Token ablegt (kann man zum Beispiel sehr einfach mit diesem Firefox-Addon inkl. Editor(!) verifizieren), dieses aber beim erneuten Besuchen der Seite (bzw. ohne JSPSESSION-Cookie) nicht verwendet bzw. wird nicht erkannt. Schlussendlich half u.a. das Umbenennen der Userservices-Bean in “userService”. Außerdem sollte die Loginseite keinen Filter/Access haben (s.o.) Lieber 2x prüfen!
Fehlermöglichkeit 2b: Es erscheint eine Ausnahme, dass der Key falsch sei.
Lösung: Dazu muss man wissen: Sobald man eine individualisierte RememberMe-Konfiguration nutzt, wird auch der Key nicht mehr vernünftig auf alle Komponenten (Provider, Filter, Manager) gesetzt. Beim Anlegen wird also der eigene Key verwendet, beim Auslesen der Standardkey. Yes! (s.o.)
Fehlermöglichkeit 3: Man besucht die Seite ohne Login, aber mit Cookie – aber wie in 2 nur die Loginseite.
Lösung: Im Logger/Debugger kann man nun feststellen, dass zwar das Cookie gefunden wurde, das Token gefunden und validiert wurde aber dann keine Rechte existieren – aha? Wahrscheinlich fehlt im Provider noch ein zusätzliches Setting der Komponenten. Am besten von RememberMe Service/Filter/Provider jeweils alle möglichen Properties durchgehen. Jaja, wie gesagt..
Fehlermöglichkeit 4: Das Ausloggen (beispielsweise logout.html) hat nach Aktivierung von Rememberme plötzlich keine Auswirkungen mehr.
Lösung: Zwar wird die Seite gefunden, aber es wird kein “Logout” gemacht. Auch hier sollte man prüfen, ob ein SecurityChainFilter (web.xml) auch für die logout-Seite greift.
Fehlermöglichkeit 5: Das Besuchen der Seite wirft einen Fehler (ggf. “mit weißer Seite”), dass keine neue Session erstellt werden kann.
Lösung: Richtig, nach einem Request ist ja dann auch zu spät. Das Attribut create-session in der Direktive http sollte daher auf “ifRequeried” gestellt sein.
Natürlich kann man sich das Problem mit den SecurityChains vom Hals schaffen, indem man stupide ein /* filtert. Das hat jedoch zur Auswirkung, das Spring Security auch jeden verdammten Request anguckt; bei zusätzlichen (statischen) Inhalten wie Javascript, Stylesheets, Bildern, Flash u.ä. ist das ein Overhead, der unnötig ist.
Dez 30
Gepostet von knalli in Empfehlungen, Technik, Technologie/IT, Tipps, Web | Keine Kommentare
Als Ergänzung zu meinem XForms-Vortrag in der FH, hier ein paar nette Details zu den Neuerungen von HTML5/Forms. Jaja, was für eine Überaschung. Okay, nach dem Tod von XHTML2 (und demnach die Integration von XForms in XHTML) auch wieder nicht…
Ganz allgemein scheint Dive Into HTML5 aber auch empfehlenswert zu sein, wenn auch noch in Arbeit. Nett gemacht.
Dez 2
Gepostet von knalli in Aktuelles, Allgemeines, Technik, Technologie/IT, Tipps | 2 Kommentare
Im Zuge eins kommenden Artikels/Howto über Webapp Deployment/Build suche ich noch bestehende Lösungen, gerne auch Scripts a la Ant. Auf letzterem basiert auch meine bisherige Vorgehensweise..
Update: Inkl. dem Buildprozess.
Google hat also nebst so Allerweltssachen wie Mails, Cloud, Docs und Search also auch
Und die Leute haben da noch Angst vor der Datenkrake – da bahnt sich doch ein ganz anderes – liebes? – Monster an.
Und Hinweise, Links? Google! Ha!
Du befindest dich momentan auf der Archivseite der Kategorie Technik.
Arclite Theme von digitalnature | powered by WordPress
Page optimized by WP Minify WordPress Plugin