Posts mit dem Label CMS werden angezeigt. Alle Posts anzeigen
Posts mit dem Label CMS werden angezeigt. Alle Posts anzeigen

Samstag, 3. Juni 2017

Hello CoreMedia CMS 9

In any project based on the CoreMedia CMS where sites have to be created from scratch, at one point we ran into the need of the minimal content set for that site. That content area should be unrelated and unconnected to any other data and content in the system - so be really self-contained. It should make clear, which elements and settings are really needed from the wealth of options for that very project or site within the instance of the software.

Too much Content


For really some time now, CoreMedia provides a load of demo-site contents for different scenarios of the usage of their products. It is quite easy to set up a system that really shows something.

From my point of view, taking one of these demo sites and ripping out the unnecessary parts was not helpful, since you might end up - especially for new releases - with too much data that might be needed. At least a feeling of unknown dependencies sometimes remained.

URL found through Google search for "coremedia chef corp"

A small content snippet with as few elements as ever possible still seemed to be missing. And this still holds true for the latest release CoreMedia CMS-9 (and LiveContext 3 as well) as shown from a small personal survey.

Hello World


Again involved in a project based on CoreMedia products, I am now using the latest - and greatest - version of the CMS product - CoreMedia CMS 9, and asked some old friends to help me.

After showing the system and demos one of the first questions: "Ok, nice, where is the minimal Hello World site?".

From that feedback without any prior CoreMedia-related background, I assume that developers expect that part of a software - any software - to be there.

The first step now was, to ask people for their starting point content sets or Hello World sites. The result was then reworked as a CoreMedia CMS 9 Hello World site as depicted below:


It could be imported into the repository and instantly be used as a Hello World site, - and with its static content only as a Hello World site.

Configurable Content


This is a nice missing piece - I think - for CoreMedia CMS 9, but it is not really the last step for a starting point for a project. For every re-use that Hello World content has to be reworked to use the needed
  • Local
  • Path
  • Title
  • URL Segments
and the like. So there still is some work to do. But this kind of work is even more schematic and boring than the setup of the minimally needed elements.
This ended in a rewrite script and a content workspace which I now would like to make available to any interested developer in the CoreMedia-sphere.

Find the resulting code at Bitbucket, GitLab, and Github.
Enjoy. Feedback is welcome.

Sonntag, 29. September 2013

Tangram 0.8 Release - Mehr Dynamik bitte

Es wurde langsam Zeit für ein neues Tag auf dem Tangram Repository. Die Änderungen gegenüber der letzten Version sind doch umfangreich und viele Anwendungen, die Tangram nutzen - und dringend Version 0.8 brauchen, sollten wieder eine Stabile Basis bekommen.
Die aktuelle Fassung auch von den Beispielen gibt es als Code wie immer bei github und die Dependencies bezieht man aus dem amor.

Was gibt's neues?

Version 0.8 beschäftigt sich viel mit Dynamik. Dazu bedurfte es eines Erheblichen Tunings - insbesondere auf der Google App Engine - allgemein für die Nutzung in der Cloud. Aber etwas anderes kommt unter der Überschrift Dynamik ja auch nicht in Frage.
Zu den umfangreicheren Caching Techniken ebenfalls mit Zielgebiet Cloud werde ich hier noch einen separaten Beitrag veröffentlichen.
Mit Version 0.8 ist die Programmierung von Tangram-Anwendungen nun endgültig in die Datenbank gewandert und wird dort mit Apache Velocity und Groovy umgesetzt, wobei einige Schwächen und Fehler bereinigt wurden.
Dabei sind nun neben den bekannten URLs auch Benutzeraktionen auf der Weboberfläche mit (in den sogenannten Shims) Groovy umsetzbar.
Das dynamische Zusammenstellen der Inhalte auf der Site ist nun ausreichend performant, in der API vollständig und ebenfalls mit Groovy handhabbar.
Um das alles benutzbar zu halten wurde der Editor - eigentlich nur ein Stiefkind in Tangram - in wichtigen Details verbessert und in den Abläufen einfacher gestaltet.
Technisch wurde die RDBMS Umsetzung vom Proof of Concept neben der Google App Engine zu der Hauptumsetzung und das System um die Anbindung MongoDB erweitert. Dabei wurde der JDO-Layer von den historischen Altlasten früher Google App Engine Zeiten befreit und auf API-Level 3.0 gehoben.
Natürlich sind alle genutzen Komponenten auf aktuelle Versionen umgestellt und auch das Buildsystem mit Gradle - jetzt in Version 1.8 - konsistent weiterentwickelt.

Neuer Standard-Startpunkt

Wer nun eine neue Web-Idee ausprobieren möchte und kein Geld in die Hand nehmen will, nimmt nicht mehr die Tangram und die Google App Engine und den Google Apps sondern Tangram und Cloudbees - ggf. mit MongoDB als Backend, an dieser Stelle sogar mit integrieten git-SCM und Continous-Integration-Server über Jenkins.
Auch hier gilt: Wenn die Idee fliegt, besteht ein professionelles Angebot für eine kommerzielle Nutzung der Plattform.
Ersatz für die Google Apps, die wir in der Vergangenheit für den Rest des Auftrittes wie Mails, Calender, Dokumentablage etc. genutzt haben, findet man bei zoho.

Freitag, 27. September 2013

CoreMedia Blueprint für Solaris

Evtl. kennt das noch der ein oder andere: Wenn man den ganzen Tag auf einen dieser alten grünen Monochrommonitore geschaut hat, sieht man abends einen rosa Augenhintergrund. - In unserem Projekt hier ist es gerade sehr ähnlich - nur andersherum.
Und so müssen die neuen Dinge von CoreMedia, die richtig Spaß machen und gut zu handhaben sind (natürlich nicht ohne Einarbeitung), auch ein wenig Altlast tragen, denn einige Dinge sollen so bleiben, wie sie seit viele Jahren bewährt laufen.
Z.B. sind die Server immernoch Sparc Maschinen mit Oracle Solaris. Und der der Kunde erwartet, daß das einfach so funktioniert, da es ja auch im Handbuch steht.
Der CoreMedia Blueprint und sein kleiner Bruder verlassen sich aber darauf, daß die damit erstellten Pakete auf einer bestimmten Sorte Linux laufen (eine Frage von LSB, BSD, POSIX usw.). Also haben wir da doch mit einer gewissen Lernkurve Punkte entdeckt, an denen man Änderungen einbauen muß. Die Projektlösung war dabei doch recht speziell, umfangreich - und hatte mehr Klippen zu umschiffen als für eine Blueprint nötig.
Daher wollte ich nun auf Basis des reinen Blueprint Workspaces noch einmal eine saubere, schlanke Neu-Umsetzung durchführen. Bereits bei den Spielereien mit Debian/Ubutunu habe ich gesehen, wie sich einige Skripte doch auf Details verlassen, die nicht einmal unter allen Linux-Distributionen so sind. Bei Solaris war mir aus Jahrzehntelanger Erfahrung klar, daß selbst bei gleicher Shell einige System-Tools sich nicht so verhalten, wie ihre meist erweiterten GNU-Freunde. - Und das ist auch hier wieder relevant.
Der große Skripte-Zoo im CoreMedia Blueprint ist aber gerade ein wichtiger Teil für den Weg vom Entwickler-Rechner in die Produktion. Diese Zusammenstellung wollte ich möglichst minimal anpassen und mit einer Solaris Paketierung zusammenführen.
Schritt eins dabei war natürlich die Herstellung der Pakete selbst. Wegen schlechter Erfahrungen mit entsprechenden Maven-Plugins, die auch seit Jahren nicht mehr gewartet werden und das Alpha-Stadium nicht verlassen haben, kam diesmal der Einsatz der System-Tools auf die Tagesordnung. Solaris-Pakete lassen sich damit auch nur unter Solaris erstellen, sorry.
Dabei integriert mal die Skripte aus dem Workspace oder verpackt. D.h. man holt sich die preinstall.sh und portuninstall.sh als preinstall und postuninstall in das Paket während man die postinstall.sh und preuninstall einfach verpacken kann:
  # postinstall
  if [ -f ${INSTALL_ROOT}/${APPLICATION_NAME}/INSTALL/postinstall.sh ] ; then
    ${INSTALL_ROOT}/${APPLICATION_NAME}/INSTALL/postinstall.sh 1
  fi


Im Gegensatz zu Linux Varianten kennt hier Solaris anscheinend keine Parameter an diese Skripte. Preinstall und Postuninstall sind also schon einmal anzupassen, da vor dem Installieren und nach dem Entfernen ein Wrapper in's Leere greifen würde:
  #!/bin/bash
  set -e
  # $1 == 1 --> initial installation
  # $1 == 2 --> upgrade
  SELECTOR=$1

  # Solaris
  if [ -z $SELECTOR ] ; then
    SELECTOR=1
  fi

  if [ $SELECTOR -eq 1 ] ; then
    ...
  (preinstall.sh)Die Solaris Paketierung stellt man auch gerne wieder generisch als Maven Modul unter packages/ bereit und legt sich hierin Prototypen für die Paketbeschreibung inklusive der Skripte und ein Ant-Script zu Steuerung der Paketierung bereit:
  PKG=${APPLICATION_NAME}
  NAME=${APPLICATION_NAME}
  DESC="CoreMedia 7 Component - ${APPLICATION_NAME}"
  VERSION=${project.version}
  BASEDIR=${INSTALL_ROOT}
  PSTAMP=${timestamp}
  CATEGORY=application
  ARCH=sparc
  CLASSES=none
  VENDOR="CoreMedia AG"
  HOTLINE="+49-40-325587-777"
  EMAIL="support@coremedia.com"
  ISTATES=S s 1 2 3
  RSTATES=S s 1 2 3

  pkginfo

  i pkginfo
  i preinstall=preinstall
  i postinstall=postinstall
  i preremove=preuninstall
  ! postremove=postuninstall
  !include generated-prototype

  prototype

<?xml version="1.0" encoding="UTF-8" ?>
<project>
  <target name="pkg">
    <copy file="${project.build.directory}/${PACKAGE_DIR}/INSTALL/preinstall.sh"
          tofile="${project.build.directory}/solaris-cooked/preinstall" 

          overwrite="true" failonerror="false" />
    <copy file="${project.build.directory}/${PACKAGE_DIR}/INSTALL/postuninstall.sh"
          tofile="${project.build.directory}/solaris-cooked/postuninstall"     

          overwrite="true" failonerror="false" />
    <exec executable="/bin/bash" failonerror="true">
        <arg value="-c" />
        <arg value="pkgproto ${project.build.directory}/${PACKAGE_DIR}=${APPLICATION_NAME}/ > ${project.build.directory}/solaris-cooked/raw-prototype" />
    </exec>
    <exec executable="/bin/bash" failonerror="true">
        <arg value="-c" />
        <arg value="sed -e s/${user.name}/${INSTALL_USER}/g ${project.build.directory}/solaris-cooked/raw-prototype | sed -e s/[a-zA-Z0-9]*$/${INSTALL_GROUP}/g | grep -v dll= | grep -v exe= | grep -v bat= > ${project.build.directory}/solaris-cooked/generated-prototype" />
    </exec>
    <exec executable="/bin/bash" failonerror="true">
      <arg value="-c"/>
      <arg value="mkdir ${project.build.directory}/pkg"/>
    </exec>
    <exec executable="/bin/bash" failonerror="true">
        <arg value="-c" />
        <arg value="pkgmk -f ${project.build.directory}/solaris-cooked/prototype -d ${project.build.directory}/pkg -o -b ./" />
    </exec>
    <exec executable="/bin/bash" failonerror="true">
        <arg value="-c" />
        <arg value="pkgtrans ${project.build.directory}/pkg ../${APPLICATION_NAME}-${project.version}.sparc.pkg ${APPLICATION_NAME}" />
    </exec>

    <exec executable="/bin/bash" failonerror="true">
      <arg value="-c" />
      <arg value="gzip -9 ${project.build.directory}/${APPLICATION_NAME}-${project.version}.sparc.pkg" />

    </exec>
  </target>
</project>

(ANT build-pkg.xml)

Wenn man diese Pakete dann installiert, fällt die Installation recht herb auf die Nase. Unter Solaris funktioniert das automatische Anlege der Benutzer doch etwas anders und hat keine impliziten Randbedingungen wie bei Linux.
   # Add the "@INSTALL_USER@" user
  # This will fail on Solaris
  /usr/sbin/useradd -c "system user to run coremedia services and applications" \

       -s /bin/bash -m -d @INSTALL_ROOT@ -r @INSTALL_USER@ 2> /dev/null || :
  # For Solaris create group manually
  /usr/sbin/groupadd @INSTALL_GROUP@ 2> /dev/null || :
  # So try it again without -r parameter but group (s.a.) instead
  /usr/sbin/useradd -c "system user to run coremedia services and applications" \

       -s /bin/bash -m -d @INSTALL_ROOT@ \
       -g @INSTALL_GROUP@ @INSTALL_USER@ 2> /dev/null || :
(postinstall.sh)
Wenn man jetzt noch das mktemp in reconfigure.sh umformuliert kommt man schon sehr viel weiter. Und nach einer Anpassung der Service-Integration in /etc/init.d ist man sehr nahe am Ziel.
  # Register as service if possible
  if [ -x /sbin/chkconfig ] ; then
    logger -p syslog.info -t coremedia/rpm \

           -s "Enabling the service @APPLICATION_NAME@, ..."
    chkconfig @APPLICATION_NAME@ on
  else
    echo "To start call \"/etc/init.d/@APPLICATION_NAME@ start\""
  fi
  (z.B. postinstall.sh)

Auch hier wieder ist zur (etwas) besseren Lesbarkeit einiges ausgelassen. Die volle GIT-Patch-Sequence gibt's gerne auf Anfrage.

Montag, 23. September 2013

CoreMedia 7 Blueprint als Debian/Ubuntu Pakete

Es ist hier Off-Topic, aber es paßt gut in die Zielrichtung Entscheidungsfreiheit bei der Plattformwahl zu bekommen und dennoch einheitlich die benötigten Features zur Verfügung zu haben.
Dies ist ein Thema, das man eben nicht nur mit Tangran adressieren kann, sondern auch z.B. mit dem CoreMedia CMS.
Mehr durch einen Bedienerfehler inspiriert als mit Zielrichtung versehen, habe ich das CoreMedia 7 Blueprint mit Debian Paketbau versehen. Damit kann man - auch wenn es nicht suppported ist - das CoreMedia 7 System auch z.B. mit einem Ubuntu LTS (es sollte ja auch ein Enterprise Linux sein können, damit man bei Bedarf auch kommerziell Support einkaufen kann) einsetzen.
CoreMedia selbst bietet uns ein fertiges Setup zum Bau von RPM-Paketen für die einzelnen Komponenten, das sogar unter Windows ohne weitere Werkzeuge läuft. Das ist eine Meßlatte, die ich nicht unterschreiten wollte. Also war ich auf der Suche nach einer reinen Java-Lösung und stieß auf diese Liste: Maven plugin for building debian package.
Leider werden CoreMedia Workspaces immernoch mit Maven zu fertigen Lösungen zusammengebaut und zwei der Tools auf der Liste lassen sich nicht einfach integrieren oder benötigen wieder externe Werkzeuge auf der Unix-Kommandozeile.
Einzig jdeb brachte schnell erste Ergebnisse.
Wer das Ganze in sein Projekt eingepaßt haben möchte oder einfach den fertigen Patch gegen dan Blueprint in Version 26 haben möchte, möge sich einfach mal melden. Hier folgt jetzt die lesbare aber damit nicht Code-Zeilen-genaue Version.
Was ist zu tun?
Nachdem man in der root-POM jdeb mit Version (hier 1.0.1) bekannt gemacht hat, wendet man sich einzig dem Bereich packages im Workspace zu, wo alles zunächst ganz einfach aussieht.
Mit einer Konfiguration für alle Pakete
  <plugin>
    <artifactId>jdeb</artifactId>
    <groupId>org.vafer</groupId>
    <configuration>
      <deb>[[buildDir]]/${APPLICATION_NAME}_[[version]]_all.[[extension]]</deb>
      <controlDir>${project.build.directory}/deb</controlDir>
      <dataSet>
        <data>
          <type>template</type>
          <paths>
            <path>${INSTALL_ROOT}/${APPLICATION_NAME}</path>
          </paths>
        </data>                  

        <data>
          <src>${project.build.directory}/${APPLICATION_NAME}</src>
          <type>directory</type>
          <excludes>**/*.bat,**/*.exe,**/*.dll</excludes>
          <mapper>
            <type>perm</type>
            <user>${INSTALL_USER}</user>
            <group>${INSTALL_GROUP}</group>
            <prefix>${INSTALL_ROOT}/${APPLICATION_NAME}</prefix>
          </mapper>
        </data>
      </dataSet>
    </configuration>
  </plugin>

entstehen sehr schnell .deb Dateien, wenn man sich vorher eine Dependency auf ein ZIP erzeugt und im ${project.build.directory}/deb auspacken läßt. In dieser Dependency (hier genannt debian-packaging) braucht man mindestens ein control-File und Filtering, damit man nicht für jedes Paket ein eigenes erstellen muß.
  Package: ${APPLICATION_NAME}
  Version: ${project.version}
  Section: httpd
  Priority: optional
  Architecture: all
  Depends: ${APPLICATION_PREFIX}-tomcat-installation
  Maintainer: Main Tainer <maintainer@example.com>
  Description: CoreMedia 7 - ${APPLICATION_PREFIX} ${project.artifactId}
  Homepage: http://www.coremedia.com/

Bis diese Pakete auch nur fast auf dem Niveau der RPM-Pakete sind, ist allerdings noch ein wenig Feinarbeit notwendig.
Die Installation- und Entfernungs-Skripten, die Dateiberechtigungen und die Unterschiede zwischen dem Bereich tools, services und der tomcat-installation bringen dann noch ein wenig Arbeit, die einige Round-Trips erfordert, bis alles an seiner Stelle steht und richtig zusammenspielt.
Man sieht es schon an den data-Template oben, wo der Basis-Pfad des gesamten Paketes noch einmal explizit erwähnt werden muß. Außerdem haben Debian-Pakete andere Aufruf-Parameter für die Skripten, wo z.B. install statt 1 und upgrade statt 2 übergeben wird. Desweiteren verlassen sich die mitgelieferten Skripten von CoreMedia auch fest auf das Vorhandensein von Werkzeugen, die nun einmal nun auf jedem Linux verfügbar sind. Diese mitgelieferten Skripten werden durch Wrapper in den Pakete aufgerufen - außer natürlich dem Skript preinst (preinstall.sh), das beim Wrapper in's leere greifen würde und daher angepaßt werden mußte - in allen drei Varianten, die im Workspace existieren:
  # $1 == 1 --> initial installation
  # $1 == 2 --> upgrade
  SELECTOR=$1


  # Debian
  if [ "a$SELECTOR" = "ainstall" ] ; then
    SELECTOR=1
  fi
  if [ "a$SELECTOR" = "aupgrade" ] ; then
    SELECTOR=2
  fi

  if [ $SELECTOR -eq 1 ] ; then
    # initial installation

Am Ende der ganzen Prozedur kommt noch ein wenig Fleißarbeit: In jedem aber auch jedem Paket - das ist beim CoreMedia Application Maven Plugin letztlich nicht anders - muß nun der Paketbau als Referenz auf die übergreifenden Konfiguration eingefügt werden.
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <phase>initialize</phase>
        <goals>
          <goal>unpack</goal>
        </goals>
        <configuration>
          <artifactItems>
            <artifactItem>
              <groupId>${project.groupId}</groupId>
              <artifactId>debian-packaging</artifactId>
              <version>${project.version}</version>
              <type>zip</type>
              <outputDirectory>${project.build.directory}/deb</outputDirectory>
            </artifactItem>
          </artifactItems>
        </configuration>
      </execution>
    </executions>
  </plugin>

  ...
  <plugin>
    <artifactId>jdeb</artifactId>
    <groupId>org.vafer</groupId>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>jdeb</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

Auch hier sind natürlich wieder ein paar Schritte ausgelassen, um den Text hier noch einigermaßen lesbar zu halten.

Montag, 8. Juli 2013

Mehr Auswahl für die Plattform - Tangram auf Cloudbees

Wie es aussieht, läuft Tangram sehr einfach auch auf der Infrastruktur von Cloudbees. Im Gegensatz zu der Google App Engine benötigt man bei dieser Variante keine spezielle Anpassung, es müssen nur die vorhandenen Konfigurationsparameter passend eingestellt werden:

1. Anlegen einer neuen Anwendung

Entweder über die Web-Schnittstelle oder die Kommandozeile legt man eine neue Anwendung an.

2. Erstellen einer Datenbank

Unter Cloudbees kann man MySQL Datenbanken anlegen und benutzen.
Eine solche Datenbank könnte man natürlich nun direkt in die Tangram-Anwendung hineinkonfigurieren.  Dann könnte man den folgenden Schritt überspringen und direkt die Anwendung mit Schritt 4 deployen. Server, Port, Schemaname und Benutzername sind ja aus dem GUI bekannt und können einfach in die jdoconfig.xml übernommen werden. Wir gehen hier jedoch über einen Zwischenschritt vor.

3. Verbinden der Datenbank als Datasource

Die Verbindung der Datenbank mit einem Namen, der über JNDI erreichbar ist, kann nur über die Kommandozeile erledigt werden:

examples\rdbms-example>bees app:bind -db <DBNAME> -a <APPID> -as tangramdb

Im Tangram rdbms example lautet die jdoconfig.xml dann

<?xml version="1.0" encoding="utf-8"?>
<jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">

   <persistence-manager-factory name="transactions-optional">
       <property name="javax.jdo.PersistenceManagerFactoryClass"
           value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
       <property name="datanucleus.ConnectionFactoryName" 

                 value="java:comp/env/jdbc/tangramdb" />
       <property name="datanucleus.autoCreateSchema" value="true" />
       <property name="datanucleus.validateTables" value="true" />
       <property name="datanucleus.manageRelationships" value="true" />
       <property name="datanucleus.validateConstraints" value="true" />
   </persistence-manager-factory>

</jdoconfig>


Statt der "normalen" Verbindungsparameter findet sich hier also nur eine Zeile mit dem Eigenschaftsnamen "datanucleus.ConnectionFactotyName". Die anderen Parameter entsprechen den Einstellungen, die im Zusammenhang mit Tangram immer verwendet werden.

4. Deployen

Entweder benutzt man wieder das GUI und deployed das Web-Archiv unter build\libs\rdbms-example.war oder erledigt dies über die Kommandozeile (BEES_HOME muß gesetzt sein und das Cloudbees SDK im Pfad erreichbar):

examples\rdbms-example>bees app:deploy build\libs\rdbms-example.war  
    -a <account>/<appid>

5. Benutzen

Das war's dann auch:

http://<appid>.<account.>.cloudbees.net/s/list?cms.editor.class.name=org.tangram.rdbms.solution.RootTopic

führt einen nun auf nach dem Login an den einfachen Tangram Editor - und es kann losgehen, mit dem Anlagen von Codes und (im Beispiel) Topics und anderen Objekten,

Dienstag, 11. Dezember 2012

On the Fly: URL Formate dynamisch anpassen

Nachdem nun einmal Groovy Codes jederzeit als Klassendefinitionen in das Tangram System eingefügt werden können, bietet es sich an
Mit Groovy kann man in Tangram neben den Ergänzungen der "Bean Schicht" - des Models - durch Shims sehr einfach URL-Formate schreiben und dynamisch jederzeit anpassen.
Dazu wird wieder Code mit MimeType "application/x-grooy" geschrieben. Die Annotation ist diesmal aber "org.tangram.view.link.LinkScheme" oder gleich der Klassenname der zu erstellenden Klasse.
Diese Klasse muß das Interface org.tangram.view.link.LinkScheme implementieren, d.h. Instanzen müssen sowohl URLs interpretieren können als auch aus Objekten URLs generieren können.
Das Tangram-System bietet dabei neben den URLs zur reinen Ansicht der Inhalte sogenannte Action-URLs, mit denen Aktionen - also Controller-Elemente - angesprochen werden sollten. Am Ende so einer Aktion sollte ein Redirekt auf eine reinen Ansichts-URL erfolgen. (Sonst würde bei "Reload" durch den Benutzer die Aktion erneut ausgeführt)

package org.tangram.solution.web.links;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.tangram.Constants;
import org.tangram.content.Content;
import org.tangram.content.BeanFactory;
import org.tangram.controller.DefaultController;
import org.tangram.view.Utils;
import org.tangram.view.TargetDescriptor;
import org.tangram.view.link.Link;
import org.tangram.view.link.LinkScheme;

import org.tangram.solution.web.RootTopic;
import org.tangram.solution.web.Topic;
import org.tangram.solution.web.ImageData;

public class DefaultLinkScheme implements LinkScheme {
 
  private static Log log = LogFactory.getLog(DefaultLinkScheme.class);

  private BeanFactory beanFactory;
 
 
  public void setBeanFactory(BeanFactory factory) {
    beanFactory = factory;
  } // setBeanFactory()
 
 
  public void setDefaultController(DefaultController defaultController) {
    // Automagically set default view
    defaultController.getCustomLinkViews().add(Constants.DEFAULT_VIEW);
  } // setDefaultController ()
 
 
  public Link createLink(HttpServletRequest request, 

                         HttpServletResponse response, Object bean, 
                         String action, String view) {   
      Link result = null;
      if ((action==null)&&(view==null)) {
          if (bean instanceof RootTopic) {
              result = new Link();
              result.setUrl("/");
          } else {
              if ((bean instanceof Topic)||(bean instanceof ImageData)) {
                  String title = "-";
                  String keywords = "-";
                  if (bean instanceof Topic) {
                      try {
                          title = Utils.urlize(((Topic)bean).getTitle());
                          keywords = Utils.urlize(((Topic)bean).getKeywords());
                      } catch (UnsupportedEncodingException uee) {
                          log.error("createLink()", uee);
                      } // try
                  } // if
                  String url = "/"+keywords+"/"+title+

                                    "/"+((Content)bean).getId();
                  result = new Link();
                  result.setUrl(url);
              } // if
          } // if
      } // if
      return result;   
  } // createLink()

 
  private TargetDescriptor rootDescriptor = null;;
 
 
  public TargetDescriptor parseLink(String url, HttpServletResponse response) {
    TargetDescriptor result = null;
    if (url.equals("/")) {
        try {
            if (rootDescriptor==null) {
                List<RootTopic> rs = 

                   beanFactory.listBeans(RootTopic.class, null);
                RootTopic root = null;
                if (rs.size()==1) {
                    root = rs.get(0);
                } else {
                    response.sendError(HttpServletResponse.SC_NOT_FOUND, 

                                "Have "+rs.size()+" RootTopics in data store");
              } // if
                rootDescriptor = new TargetDescriptor(root, null, null);
            } // if
            result = rootDescriptor;
        } catch (Exception e) {
            result = new TargetDescriptor(e, null, null);
        } // try/catch
      } else {
          String id = null;
          Object bean  = null;
          String[] elements = url.split("/");
          for (String element : elements) {
            if (element.indexOf(":") > 0) {
              id = element;
              bean = beanFactory.getBean(element);
            } // if
          } // for
          if (bean != null) {
              result = new TargetDescriptor(bean, null, null);
          } else {
              throw new RuntimeException("no content with id "+id+

                                         " in repository.");
          } // if
      } // if
      return result;
  } // parseLink()
   
} // DefaultLinkScheme

Das Beispiel hier zeigt zum einen das Erzeugen von URLs mit createLink() und das Verarbeiten mit parseLink(). Es ist im Grunde schon gar nicht so simpel sondern erfüllt eine ganze Reihe von Anforderunen:
  • Es sind sprechende URLs umgesetzt, die den Title der Objekte benutzen
  • Die Startseite wird mit / aufgerufen
  • Aktionen laufen auf den DefaultController aus dem System

Montag, 10. Dezember 2012

Nie wieder keinen Shim-mer!

Tangram wie viele Systeme besteht aus zwei Elementen: dem Code, der sowohl das Model als auch das Verhalten (den Controller) beschreibt und der View Schicht mit ihren Templates. Ich nenne das im Moment zwei Element, weil sie mit unterschiedlichen Techniken bedient werden: Code ist bei uns typischerweise in Java geschrieben und die Templates in JSP.
Schnell ist man dabei, Ergänzungen zu den Templates wie CSS und JavaScript im Repository anzulegen, damit man sie schnell und einfach ohne Deployment ändern kann. In Tangram Websites war das nicht dadurch gegeben, daß Deployments ein großer Aufwand sind, sie ware auch für die kleinen Sites und das einfache Deployment mit der Google App Engine, schlicht gelegentlich in dem Moment wo es notwendig war technisch nicht durchführbar.
Wenn man dann die Elemente CSS und JavaScript im Repository hat, will man schnell das Template auch dort haben. Das ist im Tangram mit Apache Velocity umgesetzt und ist schnell zur bevorzugten Technik geworden, sodaß JSP-Templates nur noch für die mitgelieferten Teile wie den Editor eine Rolle spielen, nicht aber für die Webanwendungen selbst.
Beim Schreiben der Templates stößt man dann aber unweigerlich immer wieder an die Limitierung der Implementierungsteile in Java, da diese ja fest im Deployment verankert sind.
Also wurde im Tangram Groovy integriert, daß als dynamische Sprache in die Java Welt integriert ist und somit sehr gut in das Szenario paßt.
Mit Groovy kann man in Tangram sehr einfach Funktionen auf Basis des Models zu den Java-Klassen hinzufügen. Da diese Codes im Repository als kleine Erweiterungen gedacht sind, heißen sie Shims. Diese kleinen Shims können zu jeder Klasse definiert werden, indem man einen Code mit dem MimeType "application/x-grooy" erstellt und als Annotation den Namen der Java-Klasse wählt, zu der dieser Code hinzugefügt werden soll.
Der Code selbst implementiert das Interface Shim oder ViewShim, wobei der Unterschied nur ist, daß ein ViewShim auch mit den Informationen des aktuellen Request versorgt wird und damit in den Bereich fällt, in dem Tangram nicht mehr cachen kann.

package org.tangram.solution.web.shims;

import javax.servlet.http.HttpServletRequest;

import org.tangram.logic.AbstractShim;
import org.tangram.gae.solution.Topic;

public class TopicShim extends AbstractShim<Topic> {

    public TopicShim(Topic topic) {
        super(topic);
    } // TopicShim()
   
    public String getNonsense() {
      return "Hallo";
    } // getNonsense()
   
    public String getReverseTitle() {
      return new StringBuilder(delegate.title).reverse().toString();
    } // getReverseTitle()
   
} // TopicShim


Der Inhalt dieses Shims ist relativ sinnlos, zeigt aber das Wesentliche: Wir muß die Groovy-Klasse aufgebaut sein, und wie greift man über den Delegate auf die jeweilige Instanz der Java-Klasse zu.
Bleibt nur noch eine Frage zu klären: Wie kommt man dann an diesen Code heran? Zusammen mit den Instanzen der Java-Klassen wird in Tangram jeweils eine Instanz der View-Klasse angelegt und unter dem Klassen-Namen ohne Package-Angabe den Templates zur Verfügung gestellt.
Im Apache Velocity Template im Repository - JSP haben wir ja für die Anwendung selbst längst zu den Akten gelegt - sähe das dann so aus:

  <h1>$TopicShim.reverseTitle | $self.title</h1>

Freitag, 16. November 2012

Herbst Update

Ruhig hier gewesen in letzter Zeit. Aber es gab ja auch einige Probleme, die relativ nervig waren, und für die es keine Lösungen gab, die man mal eben aus dem Internet kopieren könnte.
JDO ist eine schöne, einfache Persistenz-Schnittstelle (Auch wenn man die Kritik an der Google Implementierung in der Google App Engine mal mit einrechnet.), aber der Enhancement Prozeß auf dem Kompilierten Code war für Tangram nicht nur eine Konzeptionelle Unschönheit.
Das wichtigste Problem damit war die mangelnde Update-Fähigkeit des Entwicklungssystems für Tangram auf neuere Java-Versionen, weil dort der JDO Enhancer nicht mehr als Compiler-Plugin funktionierte
Dafür gibt es nun eine neue Enhancement-Mimik in Tangram und allen Beispielanwendungen, die sicherstellt, daß man nicht mehr mit "aus Versehen" nicht enhancetem Code und damit ohne jede Möglichkeit die Anwendung zu benutzen auch nur einen Testlauf starten kann. Das gibt wesentlich mehr Vertrauen, daß das produzierte Ergebnis auch irgendwo sinnvoll laufen kann und nicht nur den Compiler, der ja von dem ganzen Prozeß ohnehin nichts mitbekommt, glücklich macht.
Der Compiler wurde mit den letzten Commits nach GitHub aber auch wieder ein wenig glücklicher, da ich die Warning-Levels weiter heraufgesetzt habe und in der Folge ein paar Zeilen für Sicherheit und Eleganz des Codes investiert habe. Natürlich ist der CI Server im BuildHive der cloudbees dabei eine große Hilfe, das am Ende wieder alles zusammenpaßt.
Das Aufsetzen der eigenen Umgebung für Tangram mit Eclipse wurde um ein paar lästige Schritte bereinigt, sodaß es nun endlich wieder auf zu neuen Ufern in den Anwendungen von Tangram gehen kann.

Dienstag, 14. Februar 2012

Noch mehr funky Groovy - und gradle blues

Rendering war ja nun schon lange nicht mehr mein Problem mit den bequemen Velocity Templates im Repository. Einiges Sites laufes ja schon damit (z.B. themen-geburtstag.de). Die URL-Formate lassen ebenfalls dort definieren, wenn man möchte, was sicherlich ein wenig schwieriger im Coding ist.
Neben dem eigentlichen Datenmodell fehlt nun noch die Action im ganzen, die ich auch gerne in's Repository verlegen würde - zumindest wieder einmal als Option, da das Verhalten doch etwas ist, was man ähnlich oft tunen will, wie das Layout.
Bisher habe ich das mit einem eigenen Satz Controller sauber lösen können, aber eben nicht so agil oder dynamisch wie die Styles und Templates.
Zumindest ist es nicht mehr meine Sicht auf moderne Web-Entwicklung, daß man einen Satz an Funktionalität fest eingebaut hat und nur noch Views darüber legt.
Und da sich am Horizont weitere Projekte abzeichen, die eher Communities als reine Websites werden sollen, bestand wieder einmal Handlungsbedarf.
Also habe ich nun den lange vorhandenen Action-Parameter bei der Link-Generierung einmal zu konsistenterem Leben erweckt (und nicht nur in der simplen Editing-Komponente verwendet) und mit zwei Annotations lassen sich nun in den LinkScheme Instanzen Methoden als Actionen markieren, die direkt über URLs angesprochen werden. Parameter-Übergabe und Resultatseiten Ansteuerung inklusive. Kommentare nach Lektüren der aktuellen Codes bitte gerne an mich.
Leider war eine Entscheidung nicht gerade förderlich (evtl. hatte ich sie deshalb beim letzte Lesen auf gradle.org auch nicht getroffen): Das update auf gradles 1.0 Milestone 7 bremst hier gerade extrem. Gut war es nur, als ich offline im Zug saß :-) Da war diese Version schneller. Ansonsten quält mich diese Version mit ewiglangen Suchaktionen nach den Dependencies. Zum glück kommt gerade Milestone 8 um die Ecke: Downloaden benutzen! Damit fühlt sich gradle wieder so gut an wie vorher :-)

Montag, 5. Dezember 2011

Endlich in's CoMA gefallen

Habe eben gerade einmal die neuen Errungenschaften des Wochenendes nach github geschoben - gepuscht auf neudeutsch. Ein kleines Update auf den neuesten Meilenstein von Gradle habe ich auch gleich noch eingezogen, weil Gradle langsam immer schneller wird und ich damit keinen nennenswerten Migrationsaufwand hatte. - Sehr zu empfehlen!
Letzte Woche hatten einmal wieder ein paar Leute gefragt, ob man nicht auch direkt auf eine CoreMedia Datenbank zugreifen kann. Kann man - aber wer will das schon.
Also habe ich jetzt endlich meinen CoreMedia Adapter (CoMA) in seiner schlichtesten Ausprägung in tangram integriert.
Nein, ich bin nicht zu doof, es ausgefeilter zu machen, aber ich will weder das Copyright von CoreMedia verletzen noch deren System nachbauen. Ich muß auch erst noch am Textkovertierer für den Richtext arbeiten.
Gemäß der neuen Doktrin seit Oktober ist nun ein Beispiel natürlich anbei. Wobei man für die Sache das Original-Beispiel von CoreMedia benötigt. Da meine Teile ohnehin nur als Ergänzung zu verstehen sind, ist das ja aber wohl keine Einschränkung.

Montag, 26. September 2011

Raus aus dem Deadlock

Eigentlich wollte ich ja schon vor Monaten Code veröffentlicht haben, aber es gibt leider drei wesentliche Probleme, von denen wenigstens eines gelöst werden sollte, bevor man daran geht.
Um überhaupt etwas herausgeben zu können braucht man ein Build-System, das ich mit Gradle umsetzen wollte.Dabei mußte ich feststellen, daß dann alle meine Google App Engine Codes im JDO Bereich nicht mehr funktionierten, wenn man sie mit Gradle baut.
Also wollte ich mich der Lösung mit relationalen Datenbanksystemen zuwenden. Das funktioniert im Unterschied zur Google App Engine auch ganz wunderbar, nur muß ich natürlich ein Bepiel bereitstellen, damit jeder am Ende auch die Funktionsweise nachvollziehen kann. Da wiederum trat als nächstes Problem die Schwierigkeit auf, daß ich bisher keine Lösung gefunden habe, unabhängig vom darunterliegenden System einen JDO-Datastore mit Datenzu befüllen, die ich aus einem andere gewonnen habe. Klingt nach einer einfachen Fingerübung mit XML oder JSON als Übertragungsformat, aber bisher habe ich da nicht nichts gefunden, das nicht in erheblicher Eigenarbeit oder viele Exceptions mündet. Ideen und Anregungen sind willkommen!
Das dritte Problem? Naja, ich müßte das Beispiel schreiben. :-)
Die völlig unverständlichen Probleme beim Bauen mit Gradle habe ich nun aber endlich umschiffen können. Damit kann ich für die Google App Engine nun auch ein Beispiel bereitstellen, indem ich einfahc das Austauschformat dort verwende. Ein Teil des Problems war "recht schnell" gefunden: Binnen einiger weniger Tage findet man heraus, daß die Dateien im JAR verpackt wurden, bevor der JDO-Enhancer sie in die Finger bekam. Der andere Trick ist hartnäckiger gewesen und ich bin ihm er jetzt auf die Schliche gekommen: Die Google Datentypen für Text und Blob wurden nicht als persistent angesehen, wie es bei der indirekten Benutzung mit dem Google App Engine Plugin für Eclipse der Fall ist. Was auch immer da genau los ist: Man muß einfach nur @Persistent an ein paar mehr Stellen schreiben. Ich will hier die Problematik von Datanucleus und App Engine gar nicht auswalzen, aber ich bin da technisch wohl ein wenig zwischen die Fronten geraten. Resultat ist jedenfalls ein ArrayIndexOutOfBounds irgendwo ganz tief im nur binär vorliegenden, enhancten Code. Eine kleine Reverse Engineering Runde durhc den Enhancer brachte nun endlich Klarheit.
Nun kann es also endlich weitergehen!
Wer doch lieger mit (a) RDBMS oder (b) CoreMedia als Speicher arbeiten möchte: Dort brauche ich also noch die (a) Datenübertragungsmöglichkeit (s.o.) und (b) Code, der mir den Richtext aus der Datenbank fischt. Anyone?

Sonntag, 22. Mai 2011

Muß es denn Maven sein?

Im Moment ist mein Code hier für mich total gut zu benutzen, aber es ist eben ein Workspace für genau einen Benutzer, der eine Reihe von Websites (z.B. www.themen-geburtstag.de und www.dragon-map.de) bastelt.
Dabei fehlt natürlich auch mir ein gutes Dependency-Management für die eingesetzte Libraries (ja ich habe síe total unzivilisiert einfach in meine jeweiligen lib/-Verzeichnisse gelegt). Im Moment pushen die einzelnen Module ihre Ergebnisse in die jeweils nächsten Schichten.
Klingt gruselig? Ist aber einfach sehr schnell und effizient zu benutzen, und das will ich auf keinen Fall verlieren!
Gewohnheitsmäßig benutzen zur Zeit viele Projekte Maven. Dabei mußten wir alle lernen, daß man nicht Maven an seine Bedürfnissen anpassen kann, sondern sich an Mavens Bedürfnisse anpassen muß. Emotionaler ausgedrückt meinte ein Kollege, daß Maven ihn nicht möge. Aber wir stellten fest, daß es noch viel schlimmer war: Maven ignoriert ihn!
Wenn ich Maven einsetze verliere ich die schöne, einfache Deploybarkeit meiner Projekte nach Google App Engine aus der IDE heraus (denke ich) und ich verliere die enorm kurzen Round-Trips beim Entwickeln, die es ermöglichen das Framework weiterzuentwickeln und die notwendigen Änderungen an den benutzenden Appliaktionen sofort zu sehen. - Sofort, nicht 4min später! Dafür bekomme ich ein sauberes Dependecy-Management und ein etwas unverständliches Build- und Packaging System. Das klingt also genauso gruselig wie der Status quo.
Also habe ich mal nach Möglichkeiten gegooglet. Dabei entdeckt man natürlich sofort JAppStart als Startpunkt für die Entwicklung einer Java-Anwendung für die App Engine. Leider bin ich über den Punkt schon seit Monaten hinaus. - Danke Jungs - zu spät. Außerdem habe ich ja einen modularen Ansatz und nicht einfach nur ein Webprojekt. Dann gibt's da die angeblichen Alternativen zu Maven (z.B. http://www.streamhead.com/maven-alternatives/). Davon habe ich mir mal Gradle genauer angesehen, weil die anderen nicht erstrebenswert schienen. Die Beschreibungsdateien für den Build-Prozeß mit Gradle sind einfacher als bei Maven, obwohl ich hier ja bei der Lernkurve bei Null anfange (bei Maven bin ich doch schon kanpp über Null nach ein paar Jahren), andererseits muß ich mir nun doch auf einmal ein komplettes Build-System aufbauen und nicht einfach etwas funktionierendes zusammenstöpseln. Das gefällt mir noch nicht. Verstanden hat der Autor aber anscheinend, daß XML nicht als Sprache zum Schreiben für Menschen gedacht ist. Gradle schreibt sich als DSL zielorientierter als das Maven XML. Das Dependency-Management kann auf Maven Repositories zurückgreifen (die sind ja in jedem Fall genau das was ich brauche) und sogar mein lokales Repository findet Berücksichtigung. Ich traue mich nun nach dem Posting gestern nicht "Maven done right" zu Gradle zu sagen, aber es fühlt sich gut an. Einziger Wehrmutstropfen: Es werden als Default Ivy-Repositories genutzt und angelegt. Ivy ist bei mir nicht positiv besetzt. Liegt das an mir?
Aber mit Gradle wie mit Maven müßte ich nun wieder alles selbst erstellen. Dazu habe ich eigentlich keine Lust. Möchte jemand übernehmen oder Tips geben?

Samstag, 21. Mai 2011

Bekehrung zu GIT

Hat schon jemand von dem Zeug, über das ich hier schreibe, den Source Code gesehen? Nein? Ok, einer hat es, aber der liest hier wohl gerade nicht.
Das hat zwei einfache Gründe: Der Code ist noch nicht in einem Zustand zusammengestellt, den ich herausgeben mag, und ich habe mich noch nicht für das "richtige" Source-Code-Verwaltungssystem und entsprechende, konkrete Repository entscheiden können.
Zum ersten Punkt gibt es entschuldigend nur zu sagen, daß die Module alle brav sauber geschrieben und zugeschnitten sind, aber das Buildsystem einfach nicht existiert. Ich fürchte mich einfach vor dem Verlust an Produktivität den mir Maven bringen würde. Gibt es Alternativen?
Für die Source-Code-Verwaltung dachte ich bisher, daß man im Open Source Bereich nun einfach mal so GIT (http://git-scm.com/) nimmt. Das lag hier so als Entscheidung herum und ich wartete nur auf den Zustand des Codes ihm bereitzustellen. Nun habe ich aber endlich Verstanden, was GIT für mich leisten kann und frage mich, worauf ich die ganze Zeit gewartet habe. Ich bin absolut bekehrt! Der Vortrag von Linus Torvalds bei Google dazu ist zwar erschreckend überheblich und er scheint auch zu wenig Erfahrung mit den anderen Arbeitsweisen im kommerziellen Umfeld zu haben (http://www.youtube.com/watch?v=4XpnKHJAok8), aber wahr bleibt wohl, daß ich mit dem Werkzeug alle Abläufe, die ich in verschiedenen Projekten brauche, damit abdecken kann. Egal, was Ihr mit Source Code macht, legt Euch einfach ein GIT-Repository an! (http://code.google.com/p/tortoisegit/) Man kann nichts falsch machen. Ich jedenfalls werde mich nun bemühen, das Backup des Tangram Workspaces (er enthält leider auch noch das halbe Dutzend Sites, die damit umgesetzt sind) durch ein GIT-Repository zu ersetzen. Das muß ich natürlich wieder sichern, aber das war es schon. Der einzige Kampf, der dann einer Herausgabe noch entgegensteht ist die Frage, ob ich ein "Superproject" in GIT brauche...

Samstag, 14. Mai 2011

Hallo Nachbarn

Nachdem ich mir ja nicht so sicher war, ob man die Lösung mit Google App Engine nun als Schmalspurvariante sehen muß, weil in mener Umgebung - gerade bei den ach so konstebewußten Kunden - noch so viele auf dedizierte Serverchen im eigenen Schrank setzen (was ja an einigen Stellen definitiv eine Berechtigung hat und behalten wird, aber man sollte doch bei ohnehin veröffentlichten Web-Inhalten drüber nachdenken können), fand ich heute bei auf welt.de (http://www.welt.de/fernsehen/specials/eurovision-grand-prix/article13361306/Lena-unheimlich-sexy-und-duester-beim-Grand-Prix.html) ein "Widget". (Sie nennen's Gadget, werde die Lieferung der Hardware verlangen! Ein Gadget ist bei mir immer ein Stück Blech oder Plastik und keine Software... ;-) )

Und siehe da, das Ding läuft auf appspot.com. Wir sind also quasi Nachbarn und die Frage der Lasttauglichkeit ist bei so einem Ereignis dann wohl auch beantwortet. (http://eurovisiongadget.appspot.com/?lang=de) Sie habe sich also nicht einmal die Mühe gemacht, eine eigene Domain dafür zu buchen (jaja, wozu auch in diesem Fall).

Wenn es Probleme damit gibt, liegt's als an meinen eingesetzten Frameworks und der Beschränktheit des Entwicklers. Das kann man ja alles noch ausmerzen, wenn es im Betrieb zuschlagen sollte. Auch in Anbetracht dessen, welchen Aufwand eine Deployment für eine eigene Umgebung bereitet und wieviel man leisten muß, um all die Möglichkeiten des Betriebs, die Google bietet, selbst bereitzustellen, sehe ich Google App Engine weiterhin als den Schwerpunkt an, wenn nicht bald ein Projekt zuschläft, das es anders braucht.

Für alle, die es lieber dediziert haben, gibt's ja schon, wie erwähnt die Möglichkeit mit eigenem Servlet/JSP Container und RDMBS nach Wahl. Außerdem bastele ich weiterhin an einem anderen Adapter...

Dienstag, 3. Mai 2011

"Erste" Web Site online

Auch wenn natürlich schon seit Monaten einige Sites mit Tangram laufen und auch schon die Integration über Google Apps und eigene Domainsnamen länger genutzt wird, verkünde ich heute mal offiziell, daß wir eine Site in Betrieb genommen haben (indem wir nur den globalen Login entfernt haben).
http://www.themen-geburtstag.de/
beschäftigt sich mit Konzepten zur Ausgestaltung von Kindergeburtstagen zu verschiedenen Themen - und es werden immer mehr - inklusiver aller Vorbereitungen, eines Leitfadens für den Ablauf. Dazu noch ein allgemeiner Teil. In Zukunft sollen hier noch mehr Themen und Hilfestellungen hinzukommen für alle, die nicht einfach eine Party irgendwo "einkaufen" wollen.

Montag, 2. Mai 2011

Vendor Lock in II

Leider habe ich hier über die weitere Entstehungsgeschichte von Tangram nicht mehr berichtet. Es ist aber einiges passiert.
Als nächstes wollte ich eigentlich unter dieser Überschrift darüber schreiben, wie ich unter das Tangram Modul statt JDO und Google App Engine eine CoreMedia-Datenbank geschraubt habe und mit als Modul "CoMA" einen CoreMedia CMS Adapter gebaut habe. Das habe ich zwar auch, aber das interessiert im Moment anscheinend niemanden. Wer's haben möchte: Mailen ;-) (GIT Zugange inkl.  aller Vorarbeiten den Code herauszugeben fehlen ohnehin noch, aber ich geb's gerne her)
Was ich jetzt allerdings kurzfristig beweisen wollte, war, daß das JDO-Modul auch mit anderen Spezialisierungen nutzbar ist. Das klappt derzeit auch recht gut. Der Editor, mit dem sich die JDO-Beans generisch bearbeiten lassen, läuft nun brav auch ohne Google App Engine. Der einzige "Nachteil" ist, daß die Version des GAE-Moduls nicht angezeigt werden kann, weil das ja die Spezialisierung ist. Mit dieser neuen Varianten bin ich aber wieder einem Lieferunanten ausgeliefert: Datanucleus. Das ist auch unter Google App Engine drin und die einzige JDO Implementierung, die bei meiner Recherche den wenigen Kriterien nach Lizenz und aktiver Entwicklung standhielt.
Die größte Schwierigkeit wäre nun, das Architektur-Diagramm aus dem letzten Posting wieder anzupassen.
Wer jetzt also nicht in die Cloud wollte, kann nun loslegen. Er muß nur noch das Themen Benutzerverwaltung angehen, weil sonst jeder seine Website editieren kann. ;-) Eine integration mit Springsecurity für die elementaren Notwendigkeiten, wie sie in der App Engine zur Verfügung stehen, scheint schlank zu sein, aber ich hatte dieses Wochenende einfach keine Lust dazu. Ich ziehe die Lösung aber jedem kleinen CMS vor.