For my ongoing work on Tangram a wanted to use the RedHat OpenShift platform. In this post I'm going to outline the generic part of this which now is extracted as a Quickstart on github via https://github.com/mgoellnitz/openshift-tomcat-gradle-quickstart.
The requirements where the following: Build must be possible with Gradle and a plain Apache Tomcat webcontainer - not a JBoss Tomcat derivative - is needed. For the time being I still left out the option to use Jenkins, since the way to re-deploy on git-push OpenShift gives me, is quite usable.
So this results in the idea of a combination of the work of Shekhar Gulati at https://www.openshift.com/blogs/run-gradle-builds-on-openshift with the code at https://github.com/shekhargulati/gradle-openshift-quickstart and the tomcat Quickstart https://github.com/openshift-quickstart/openshift-tomcat-quickstart
Looking at the changes needed to use Gradle, I decided to integrate them manually and modify them along the way. Also the Tomcat Quickstart will not be used directly but serves as a template, since I don't want to pull the Apache Tomcat binaries into the git repository. As opposed to many other examples I came across, the installation of the RedHat cloud command line tools is completely left out. You might want to use them, but they are not needed for this example.
First of all I had to create an application (named "test") and had to take "DIY 0.1" as the type of application and clone the resulting repository.
git clone ssh://524e65...094@test-application.rhcloud.com/~/git/test.git/
cd test
This repository resembles the working directories of your application on OpenShift and is not just a development set of folders. So you will find some scripts here to interact with the infrastructure of OpenShift. These scripts have to be customized to fetch and configure Apache Tomcat and Gradle.
Now it's time to add script element to fetch the tool.
# .openshift/action_hooks/build:
# gradle build
set -x
DIR=`pwd`
# obtain tomcat
export TOMCAT_VERSION=7.0.61
if [ ! -f $OPENSHIFT_DATA_DIR/apache-tomcat-${TOMCAT_VERSION}.tar.gz ] ; then
wget http://apache.../v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz
fi
if [ -f $OPENSHIFT_DATA_DIR/apache-tomcat-${TOMCAT_VERSION}.tar.gz ] ; then
rm -rf tomcat
tar xvzf $OPENSHIFT_DATA_DIR/apache-tomcat-${TOMCAT_VERSION}.tar.gz
mv apache-tomcat-${TOMCAT_VERSION} tomcat
cd $OPENSHIFT_DATA_DIR/tomcat
rm -rf logs
ln -s $OPENSHIFT_LOG_DIR logs
cd $OPENSHIFT_DATA_DIR
fi
# obtain gradle
export GRADLE_VERSION=2.2.1
if [ ! -d $OPENSHIFT_DATA_DIR/gradle-${GRADLE_VERSION} ] ; then
cd $OPENSHIFT_DATA_DIR
wget http://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip
unzip gradle-${GRADLE_VERSION}-bin.zip
rm -f gradle-${GRADLE_VERSION}-bin.zip
fi
cd $DIR
cd $OPENSHIFT_REPO_DIR
export GRADLE_USER_HOME=${OPENSHIFT_DATA_DIR}gradle
export GRADLE_HOME=${OPENSHIFT_DATA_DIR}gradle-${GRADLE_VERSION}
export PATH=$GRADLE_HOME/bin:$PATH
if [ -f openshift-build.gradle ] ; then
gradle --stacktrace -b build.gradle clean build
fi
Use at least version 2.2 of Gradle due to http://issues.gradle.org/browse/GRADLE-2871. Also Gradle needs some local directory on the target host.
# .openshift/action_hooks/pre_build:
# gradle storage dir build
set -x
if [ ! -d $OPENSHIFT_DATA_DIR/gradle ] ; then
mkdir $OPENSHIFT_DATA_DIR/gradle
fi
The default stop action hook script contains some references on a ruby server and is missing a nice tomcat handling.
# .openshift/action_hooks/stop:
source $OPENSHIFT_CARTRIDGE_SDK_BASH
# The logic to stop your application should be put in this script.
if [ -z "$(ps -efww | grep tomcat | grep -v grep)" ] ; then
client_result "Tomcat is already stopped"
else
if [ -x $OPENSHIFT_DATA_DIR/tomcat/bin/shutdown.sh ] ; then
$OPENSHIFT_DATA_DIR/tomcat/bin/shutdown.sh
else
kill `ps -efww | grep tomcat | grep -v grep | awk '{ print $2 }'` > /dev/null 2>&1
fi
fi
exit 0
For safety reasons it might be a good idea to delete unexploded wars from the webapp directory of the tomcat installation
# .openshift/action_hooks/deploy:
set -x
# Addition:
for i in `ls $OPENSHIFT_DATA_DIR/tomcat/webapps/*.war`; do
dn=`basename $i .war`
echo "removing $dn"
rm -rf $OPENSHIFT_DATA_DIR/tomcat/webapps/$dn
done
The start script has to be modified not to use ruby but the tomcat installation
# .openshift/action_hooks/start:
set -x
cp -rdp ${OPENSHIFT_REPO_DIR}/tomcat/conf/* ${OPENSHIFT_DATA_DIR}/tomcat/conf/
cp -rdp ${OPENSHIFT_REPO_DIR}/tomcat/lib/* ${OPENSHIFT_DATA_DIR}/tomcat/lib/
cp -rdp ${OPENSHIFT_REPO_DIR}/tomcat/webapps/* ${OPENSHIFT_DATA_DIR}/tomcat/webapps/cd $OPENSHIFT_DATA_DIR/tomcat
sed -ig 's/OPENSHIFT_DIY_IP/'$OPENSHIFT_DIY_IP'/g' conf/server.xml
sed -ig 's/OPENSHIFT_APP_DNS/'$OPENSHIFT_APP_DNS'/' conf/server.xml
bin/startup.sh
After these preparation steps it would be time to integrate your application by providing a build.gradle script in the root path and all the needed source files.
When using a custom domain, let this domain point to your Applications hostname via a DNS CNAME record. Then create an alias with your domain name for the application using the RedHat Cloud command line tool. (Or create the alias via the console web application) Don't forget to add this domain name to your server.xml override.
Das Entstehungs-Blog zu "Tangram". Einer Zusammenstellung von kleinere und größere Bausteinen, um schlank und elegant Ideen in's Web zu bringen. Es ist eine modulare Sammlung, um klein anzufangen ohne sich den Weg zur großen Webpräsenz zu verbauen. Außerdem ist das Ziel, vorhandene Räder nicht neu zu erfinden, sondern eher Versatzstücke zu integrieren, um ein schönes Gesamtbild zu erstellen. - Daher ja auch der Name.
Sonntag, 26. April 2015
Mittwoch, 25. März 2015
Dinistiq Version 0.4
The minimalistic Dependency Injection library for Java Dinistiq has been published in version 0.4.
This version doesn't present anything specifically new. It still deals with a single - singleton - scope with a few extensions in a very small footprint library. The library does not introduce any custom tags but fully relies on an subset of the JSR330 definitions.
Despite its limited scope it still successfully executes the TCK and comes with a once more extended unit test coverage.
Dinistiq is in daily production use for some time now and will remain supported as long as there is not always a need for more feature complete solutions like Google Guice or the Springframework.
This version doesn't present anything specifically new. It still deals with a single - singleton - scope with a few extensions in a very small footprint library. The library does not introduce any custom tags but fully relies on an subset of the JSR330 definitions.
Despite its limited scope it still successfully executes the TCK and comes with a once more extended unit test coverage.
Availability Release
One of the main changes of this release is the availability of the release artifacts through the JCenter service of bintray. This renders the integration of Dinistiq even easier since you will most likely not need to add another repository or mirror to your infrastructure.Dinistiq is in daily production use for some time now and will remain supported as long as there is not always a need for more feature complete solutions like Google Guice or the Springframework.
Next Steps
The versioneye service shows that Dinistiq is up to date with its dependencies with only one intentional exception. This release will be the last to support the Google App Engine through the use of outdated Servlet API versions.
Labels:
CDI,
Dependency Injection,
DI,
Dinistiq,
Java,
JSR330,
minimalistic
Freitag, 5. Dezember 2014
Dinistiq Version 0.3
Dinistiq ist entstanden, weil es schneller zu implemtieren war, als die Integration anderer DI-Framework und Container in Tangram dauerte.
Da es dann eine Weile einfach alles tat, was notwendig war, wurde nur geringe Code-Optimierungen eingeführt.
Seit August befindet es sich im produktiven Einsatz in einem Testframework zur Validierung der Einhaltung der Anforderungen für ein großes deutsches Medienportal, das auf einer neuen technischen Basis komplett reimplementiert wird.
Dabei sollte ein einfacher, effizienter, wartbarer und schlanker Technologiestack zu Einsatz kommen.
Die alternativen Stapelten Selenium, PHP und Shellskripte und waren nicht in der Lage, die angeforderten Varianten an Plattformen und Browsern mit Testfällen zusammenzuführen. Außerdem paßten sie natürlich nicht in die reine Java-Welt des Restes des Projektes.
Gleichzeitig sollten veraltete Techniken wie Maven natürlich ebenso außen vor bleiben.
Nun muß sich Dinistiq jeden Tag darum kümmern, hunderte von Testfällen mit jeweils unterschiedlichen Browsern und Zielplattformen durch Dependency Injection zusammenzuführen.
Zur Generierung der Übersicht wird Jacoco eingesetzt.
Der Impuls war aber hier auch, daß der Einsatz in der Qualitätssicherung für ein ungleich größeres Projekt erfolgen sollte und so mußte sich Dinistiq als Testfeld für die angeforderten Qualitätsmaße an den Source-Code zur Verfügung stellen.
Bisher war dieser Schritt ein voller Erfolg und in jedem Falle viel einfacher umzusetzen als alle mir bekannten Alternativen wie Springframework, Google Guice, Weld, OpenWebBeans, die den Job sicherlich auch erledigen können.
Dafür gibt es heute den Stempel "0.3".
Da es dann eine Weile einfach alles tat, was notwendig war, wurde nur geringe Code-Optimierungen eingeführt.
Qualitätssicherung
Zu seinem ersten Geburtstag hat Dinistiq aber ein echte Upgrade verdient.Seit August befindet es sich im produktiven Einsatz in einem Testframework zur Validierung der Einhaltung der Anforderungen für ein großes deutsches Medienportal, das auf einer neuen technischen Basis komplett reimplementiert wird.
Dabei sollte ein einfacher, effizienter, wartbarer und schlanker Technologiestack zu Einsatz kommen.
Die alternativen Stapelten Selenium, PHP und Shellskripte und waren nicht in der Lage, die angeforderten Varianten an Plattformen und Browsern mit Testfällen zusammenzuführen. Außerdem paßten sie natürlich nicht in die reine Java-Welt des Restes des Projektes.
Gleichzeitig sollten veraltete Techniken wie Maven natürlich ebenso außen vor bleiben.
Nun muß sich Dinistiq jeden Tag darum kümmern, hunderte von Testfällen mit jeweils unterschiedlichen Browsern und Zielplattformen durch Dependency Injection zusammenzuführen.
Qualitätssicherung
Dinistiq befindet sich nun täglich im Projekteinsatz und es ist nicht mehr hinnehmbar, wenn dabei genutzte Funktionen nicht zuverlässig nutzbar sind. Da Dinistiq mit dem Einsatz reift, sind dennoch häufige Snapshots nötig gewesen, sodaß ist einer verstärkten UnitTest Abdeckung und dem Einsatz von PMD zur Source-Code Kontrolle zwar nur ein Fehler befunden wurde, das Neu-Einführen von Fehlern aber von vorneherein úmgangen wurde.Zur Generierung der Übersicht wird Jacoco eingesetzt.
Der Impuls war aber hier auch, daß der Einsatz in der Qualitätssicherung für ein ungleich größeres Projekt erfolgen sollte und so mußte sich Dinistiq als Testfeld für die angeforderten Qualitätsmaße an den Source-Code zur Verfügung stellen.
Bisher war dieser Schritt ein voller Erfolg und in jedem Falle viel einfacher umzusetzen als alle mir bekannten Alternativen wie Springframework, Google Guice, Weld, OpenWebBeans, die den Job sicherlich auch erledigen können.
Dafür gibt es heute den Stempel "0.3".
Details
Mit Version 0.3 ist auch das Standard Repository für die Artefakte gewandert und der CI Server ebenfalls. Dies ist nur der Tatsache geschuldet, daß Cloudbees sich aus dem Geschäft zum Jahresende zurückzieht.
Labels:
CDI,
Dependency Injection,
DI,
Dinistiq,
Java,
JSR330,
minimalistic
Samstag, 30. August 2014
Tangram CoMA erwacht
Da ich nach einem langen Sommeurlaub nun wieder schwerpunktmäßig mit dem CoreMedia CMS zutun habe, habe ich mir auch im Tangram nach sehr langer Ruhe mal wieder die entsprechende Anbindung angesehen.
Für diese Anwendung stehen Möglichkeiten von Tangram, Content einzugeben, nicht zur Verfügung, da der CoMA nur lesend arbeitet. Um dennoch Inhalte und ein paar Templates zum Zeigen zu bekommen, nutze ich die uralte Beispielanwendung MenuSite von CoreMedia selbst.
Man benötigt also zum Nutzen der Anwendung eine Datenbank, wie sie ein CoreMedia Content Server für die MenuSite angelegt und mit Daten befüllt hätte.
Bisher waren die Schritte, die nötig waren, um diese Datenbank aufzusetzen nur zur Ausführung beschrieben. Alle andere Beispiele kann man einfach bauen und starten.
Die Content Management Server Webanwendung unter
https://github.com/mgoellnitz/cm-cms-webapp
und die Content Management Server Tools unter
https://github.com/mgoellnitz/cm-cms-tools
Die harte Nuß dabei war weniger der Server als das Tools Paket. Aber ohne die Tools konnte ich die Daten natürlich nicht in den Server importieren. Außerdem hat das von mir gewählte Tomcat Plugin für Gradle sich nicht von der freundlichen Seite gezeigt. Mittlerweile weiß ich, daß auch andere Anwendungen als der CoreMedia Content Server unter dem falsch zusammengestellten Classpath leiden.
Ein altes Beispiele
Seit geraumer Zeit gibt es eine Beispielanwendung zum CoreMedia Adapter CoMA im Tangram Framework. Diese litt aber daran, daß das Aufsetzen der Umgebung dazu nicht ganz trivial war. Alleine schon deshalb konnte ich nicht soviel Energie in die Weiterentwicklung stecken.Für diese Anwendung stehen Möglichkeiten von Tangram, Content einzugeben, nicht zur Verfügung, da der CoMA nur lesend arbeitet. Um dennoch Inhalte und ein paar Templates zum Zeigen zu bekommen, nutze ich die uralte Beispielanwendung MenuSite von CoreMedia selbst.
Man benötigt also zum Nutzen der Anwendung eine Datenbank, wie sie ein CoreMedia Content Server für die MenuSite angelegt und mit Daten befüllt hätte.
Bisher waren die Schritte, die nötig waren, um diese Datenbank aufzusetzen nur zur Ausführung beschrieben. Alle andere Beispiele kann man einfach bauen und starten.
Neue Server
Meine Experimente mit Gradle zum Zusammenbau von CoreMedia Softwarekomponenten ohne das bei mir nicht sehr beliebte Maven haben allerdings nun einen Stand erreicht, in dem man Skripte und kleine Workspaces präsentieren kann, mit denen man die benötigte Datenbank erstellen kann.Die Content Management Server Webanwendung unter
https://github.com/mgoellnitz/cm-cms-webapp
und die Content Management Server Tools unter
https://github.com/mgoellnitz/cm-cms-tools
Die harte Nuß dabei war weniger der Server als das Tools Paket. Aber ohne die Tools konnte ich die Daten natürlich nicht in den Server importieren. Außerdem hat das von mir gewählte Tomcat Plugin für Gradle sich nicht von der freundlichen Seite gezeigt. Mittlerweile weiß ich, daß auch andere Anwendungen als der CoreMedia Content Server unter dem falsch zusammengestellten Classpath leiden.
Und alles ohne Maven
Die genaus Beschreibung findet sich im Beispiel Repository zu Tangram.
Labels:
CoreMedia,
CoreMedia 7,
CoreMedia CMS,
Gradle,
Maven,
Tangram,
Tangram CMS
Sonntag, 17. August 2014
Tangram Release 0.9
Over the last year, Tangram has changed very much and does not look the same in all of its modules and options.
The Tangram examples reflect this with the JDO/DataNucleus, JDO/Google App Engine, EBean, and JPA example where the later is switchable with tested API implementations for OpenJPA, EclipseLink, DataNucleus, and Hibernate.
The simple and more or less generic JDO editor now is a generic editor for all the storage solutions and built as a separate module. Except for Google App Engine this module can be left out if there is another solution available to get the content into the repository.
To make the building of Tangram itself, any Tangram application, or even any application using byte-code transformation for JDO, JPA, and Ebean easier, a gradle plugin has been introduced. The examples and over blog entries illustrate the usage of this plugin.
Along this way it was easier to present a custom DI component, Dinistiq, than to use one of the available solutions. Tests have been done with Google Guice, TinyDI, and JSR-330. As of Tangram 0.9 none of these are more than experiments. Work on a Tangram JavaEE integration is also in an experimental stage and would require a major refactoring of some parts of Tangram, see other entries in this blog on the JavaEE topic.
It should now be fairly easy to do more experiments with other IoC/DI frameworks and containers or to integrate other web frameworks starting from the new plain servlet based solution.
The option matrix now looks like this:
Persistence: JDO, JPA, EBean
IoC: Springframework, Dinistiq
Security: Spring Security, Apache Shiro
Hosting: On Premise, OpenShift, Cloudbees, Google App Engine
Storage: RDBMS, No-SQL e.g. MongoDB, Files
Persistence Options
The Tangram Dynamic Web Application Framework has been extended to support the Java Persistence API (JPA) and EBean as persistence layers in addition to the already available Java Data Objects solution. This greatly extends the number of options for platforms to use with Tangram.The Tangram examples reflect this with the JDO/DataNucleus, JDO/Google App Engine, EBean, and JPA example where the later is switchable with tested API implementations for OpenJPA, EclipseLink, DataNucleus, and Hibernate.
The simple and more or less generic JDO editor now is a generic editor for all the storage solutions and built as a separate module. Except for Google App Engine this module can be left out if there is another solution available to get the content into the repository.
Dynamic Model Extenions
In addition to the Groovy implemented classes stored in the repository, which are used to extend the view and controller part of the application, you can now create JDO annotated classes which are immetiately usable as model classes in the repository. This option can only be presented for the JDO implementation.To make the building of Tangram itself, any Tangram application, or even any application using byte-code transformation for JDO, JPA, and Ebean easier, a gradle plugin has been introduced. The examples and over blog entries illustrate the usage of this plugin.
IDE Integration
To be able to synchronize codes stored in the repository a separate FTP module has be introduced. Most IDE due to their strong PHP past support FTP better than any other protocol. CSS, JavaScript, Groovy codes can be imported and exported.Generic Import and Export
Additionally and apart from the FTP module Tangram now contains a generic importer and exporter for the whole content stored in the repository. The XML representation can be used to transfer content between application using JPA, JDO, or EBean. IDs cannot be preserved.Framework Independency
For the whole Tangram code the Springframework now is only an option to do the setup of the application by Spring's Dependency Injection IoC-Container and for the controller and view parts of the application.Along this way it was easier to present a custom DI component, Dinistiq, than to use one of the available solutions. Tests have been done with Google Guice, TinyDI, and JSR-330. As of Tangram 0.9 none of these are more than experiments. Work on a Tangram JavaEE integration is also in an experimental stage and would require a major refactoring of some parts of Tangram, see other entries in this blog on the JavaEE topic.
It should now be fairly easy to do more experiments with other IoC/DI frameworks and containers or to integrate other web frameworks starting from the new plain servlet based solution.
Options
Tangram 0.9 has been tested, verified, or is even in production use on the following platforms: Google App Engine, run@CloudBees, OpenShift, and Standalone with Apache Tomcat using RDBMS or MongoDB.The option matrix now looks like this:
Persistence: JDO, JPA, EBean
IoC: Springframework, Dinistiq
Security: Spring Security, Apache Shiro
Hosting: On Premise, OpenShift, Cloudbees, Google App Engine
Storage: RDBMS, No-SQL e.g. MongoDB, Files
Code Reduction
Tangram started as an idea to plug existing components together to form a web application with as little glue code as possible. Some of the ideas like object oriented templating though had to be coded explicitly. After this starting point the Tangram codes started growing and the 0.9 release got an additional design goal to stop this. Still some of the codes in Tangram duplicate functionality which would otherwise externally be available but avoids a depedency just to call one method. And there are still codes duplicates within Tangram where the different options e.g. for persistence might get a stronger common code base. In these areas it is still not clear if they will differentiate or grow together.Outlook
The experiences with CapeDwarf showed the way into a Java EE module as an alternative to dinistiq, the Springframework, and the many tests with e.g. Google Guice. The not that encouraging experiences with the EBean ORM might lead to discontinued support for that module. Dinistiq will become more Java EE / CDI compatible and CDI without the full Java EE stack also seems to be an interesting option. Work on the generic import and export functions using XStream needs to be extended and easier integration of OpenID or OAuth outside of the Google App Engine is needed for many applications. Google App Engine with JPA is still on the list but not desperately needed.Donnerstag, 7. August 2014
Dinistiq 0.2 Release
The minimalistic Dependency Injection solution for the setup of component based Java applications using Singletons and the JSR330 annotations has stabilized to a 0.2 release.
With some minor bug fixes it also better deals with misconfigured setups.
All system properties from the JVM are now part of the scope. The logging framework has been changed from Apache Commons Logging to Simple Logging Facade for Java (slf4j).
Decent handling of maps and booleans has been added and circular dependencies are now detected and reported.
Along all these minor changes the documentation has been extended and a javadoc archive is added to the deliverables.
With some minor bug fixes it also better deals with misconfigured setups.
All system properties from the JVM are now part of the scope. The logging framework has been changed from Apache Commons Logging to Simple Logging Facade for Java (slf4j).
Decent handling of maps and booleans has been added and circular dependencies are now detected and reported.
Along all these minor changes the documentation has been extended and a javadoc archive is added to the deliverables.
Labels:
Dependency Injection,
DI,
Dinistiq,
IoC,
Java
Freitag, 25. Juli 2014
150 Lines just for one Collection
Some 15 years ago I left the Java Enterprise Edition train and am now pushed by things like CapeDwarf on JEE Servers to the evaluation of running Tangram somehow in a JEE environment. I read the promise, that things have become a lot easier and that JEE has adopted the annotation and convention based style I now feel familiar.
I came across the JSR330 annotations from the javax.injection package which were introduced in the JEE world. JSR330 Annotations are recognized by several Dependency Injection frameworks like Guice, Springframework, my homegrown dinistiq, and obviously the JEE Containers.
@Autowired
private ClassRepository classRepository;
to
@Inject
private ClassRepository classRepository;
I lost the required = false option at that time but was able to live with that given the advantages of portability.
After having migrated to the new annotations most of my Components where portable across containers. So I don't have to sell my soul to a special DI framework for very many cases, which helps choosing the right infrastructure for every project. But there are several details which still remain problematic, most notably the missing required = false option and the missing collection of instances to be able to automatically let the whole set of instances be injected.
@Autowired(required = false)
private Collection<ControllerHook> controllerHooks = new HashSet<ControllerHook>();
Later I migrated this to the JSR-330 Annotations - which also works with spring.
@Inject
private Collection<ControllerHook> controllerHooks = new HashSet<ControllerHook>();
I made this work with dinistiq as well.
With Guice I learned, that it didn't like to collect the instances for me and provide me with the collection out of the box.
I'm expecting here, that any instance implementing ControllerHook from the application context gets added to a collection which then is injected into the consuming component. Spring does it, dinistiq does it, Guice can be convinced to do it by the additional Multibinder:
Multibinder<ControllerHook> multibinder =
Multibinder.newSetBinder(binder(), ControllerHook.class);
multibinder.addBinding().to(UniqueUrlHook.class);
multibinder.addBinding().to(ProtectionHook.class);
This approach doesn't work for Tangram since the used DI solution within the application - be it dinistiq or the Springframework - interferes with the JEE Container's CDI implementation. The Application Server starts to interpret the annotations intended for the other DI framework. This would instantiate the application components twice and right at the moment it also fails on some of those components.
@Inject
private Collection<ControllerHook> controllerHooks = new HashSet<ControllerHook>();
This time the solution really is ugly. It seems I have to implement a different consuming component and thus instead of the two lines, a separate ControllerHookProvider is needed
public interface ControllerHookProvider {
Collection<ControllerHook> getControllerHooks();
} // ControllerHookProvider
Of course the generic implementation looks like the good old two lines which did the whole job for me so far.
public class GenericControllerHookProvider implements ControllerHookProvider {
@Inject
private Collection<ControllerHook> controllerHooks;
public Collection<ControllerHook> getControllerHooks() {
return controllerHooks;
} // getControllerHooks()
} // GenericControllerHookProvider
For JEE an alternative implementation has to be chosen, which made the interface necessary in the first place, and it is surprisingly wordy for that common and simple scenario.
@Named("controllerHooksProvider")
@Singleton
public class JeeControllerHooksProvider implements ControllerHookProvider {
private Collection<ControllerHook> controllerHooks = new HashSet<>();
@Inject
public void setControllerHooks(@Any Instance<ControllerHook> hooks) {
for (ControllerHook hook : hooks) {
controllerHooks.add(hook);
} // for
} // setControllerHooks()
public Collection<ControllerHook> getControllerHooks() {
return controllerHooks;
} // getControllerHooks()
} // JeeControllerHooksProvider
This really didn't invite me to go deep into JEE again. Additionally it is missing any of the configuration file based bean definitions avoiding much of the interfacing of classes where in fact just two injected values make the difference. With the Springframework configuration files and auto scanning of beans go hand in hand. JEE intentionally left out this part.
I came across the JSR330 annotations from the javax.injection package which were introduced in the JEE world. JSR330 Annotations are recognized by several Dependency Injection frameworks like Guice, Springframework, my homegrown dinistiq, and obviously the JEE Containers.
Step 1: Get rid of Spring
This is were I started to make Tangram less depending on the Springframework directly or provide interfaces to be implemented in a spring and a non-spring way. For the dependency injection part it was mostly as easy as to migrate from@Autowired
private ClassRepository classRepository;
to
@Inject
private ClassRepository classRepository;
I lost the required = false option at that time but was able to live with that given the advantages of portability.
Step 2: Find Alternatives
The spring parts of the application where re-implemented using a plain servlet based solution, and springsecurity was replaced by Apache Shiro for those scenarios.After having migrated to the new annotations most of my Components where portable across containers. So I don't have to sell my soul to a special DI framework for very many cases, which helps choosing the right infrastructure for every project. But there are several details which still remain problematic, most notably the missing required = false option and the missing collection of instances to be able to automatically let the whole set of instances be injected.
Step 3: Annoying Details
The annoying collection problem looks like this:@Autowired(required = false)
private Collection<ControllerHook> controllerHooks = new HashSet<ControllerHook>();
Later I migrated this to the JSR-330 Annotations - which also works with spring.
@Inject
private Collection<ControllerHook> controllerHooks = new HashSet<ControllerHook>();
I made this work with dinistiq as well.
With Guice I learned, that it didn't like to collect the instances for me and provide me with the collection out of the box.
I'm expecting here, that any instance implementing ControllerHook from the application context gets added to a collection which then is injected into the consuming component. Spring does it, dinistiq does it, Guice can be convinced to do it by the additional Multibinder:
Multibinder<ControllerHook> multibinder =
Multibinder.newSetBinder(binder(), ControllerHook.class);
multibinder.addBinding().to(UniqueUrlHook.class);
multibinder.addBinding().to(ProtectionHook.class);
Step 4: Show Stopper
Inspired by the CapeDwarf project, promising to be able to deploy applications developed for the Google App Engines and their APIs on a JEE infrastructure, I tried to deploy GAE based Application to such an Infrastructure based on a JBoss AS7 or Wildfly 8 Server using CapeDwarf Versions 1 or 2 respectively.This approach doesn't work for Tangram since the used DI solution within the application - be it dinistiq or the Springframework - interferes with the JEE Container's CDI implementation. The Application Server starts to interpret the annotations intended for the other DI framework. This would instantiate the application components twice and right at the moment it also fails on some of those components.
Step 5: JEE Wordiness
So quite naturally I now went over to directly migrate Tangram to the JEE world. But also JEE has the same problem as plain Guice has.@Inject
private Collection<ControllerHook> controllerHooks = new HashSet<ControllerHook>();
This time the solution really is ugly. It seems I have to implement a different consuming component and thus instead of the two lines, a separate ControllerHookProvider is needed
public interface ControllerHookProvider {
Collection<ControllerHook> getControllerHooks();
} // ControllerHookProvider
Of course the generic implementation looks like the good old two lines which did the whole job for me so far.
public class GenericControllerHookProvider implements ControllerHookProvider {
@Inject
private Collection<ControllerHook> controllerHooks;
public Collection<ControllerHook> getControllerHooks() {
return controllerHooks;
} // getControllerHooks()
} // GenericControllerHookProvider
For JEE an alternative implementation has to be chosen, which made the interface necessary in the first place, and it is surprisingly wordy for that common and simple scenario.
@Named("controllerHooksProvider")
@Singleton
public class JeeControllerHooksProvider implements ControllerHookProvider {
private Collection<ControllerHook> controllerHooks = new HashSet<>();
@Inject
public void setControllerHooks(@Any Instance<ControllerHook> hooks) {
for (ControllerHook hook : hooks) {
controllerHooks.add(hook);
} // for
} // setControllerHooks()
public Collection<ControllerHook> getControllerHooks() {
return controllerHooks;
} // getControllerHooks()
} // JeeControllerHooksProvider
This really didn't invite me to go deep into JEE again. Additionally it is missing any of the configuration file based bean definitions avoiding much of the interfacing of classes where in fact just two injected values make the difference. With the Springframework configuration files and auto scanning of beans go hand in hand. JEE intentionally left out this part.
Abonnieren
Posts (Atom)